Merge branch 'master' into worktree/fail-web-wildcard-host
This commit is contained in:
+6
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-collapsed-sidebar-shared-entry-motion.md
|
||||
2026-08-12-collapsed-sidebar-shared-entry-motion.md: c5bc18973db693cf9ba60800fbcf7720593dbad5
|
||||
2026-08-12-collapsed-sidebar-shared-entry-motion.zh.md: b87ef6322d548061cc2e29c0e8f9896098c09041
|
||||
@@ -0,0 +1,33 @@
|
||||
# Agent Note: Collapsed sidebar upper controls share one entry motion
|
||||
|
||||
Status: implemented
|
||||
Archived: 2026-08-12
|
||||
|
||||
English | [中文](2026-08-12-collapsed-sidebar-shared-entry-motion.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The collapsed sidebar rail renders four upper controls owned by two packages: the shell owns the toggle and New Session, while the workspace region owns add and search. Their opacity timing matched, but their geometry did not. Right-aligned controls moved with the narrowing column while left-aligned controls stayed fixed, so add appeared slower than search even under the same fade.
|
||||
|
||||
The bottom settings control has a different role. It is pinned to the rail foot and must not join the upper controls' horizontal entry.
|
||||
|
||||
## Decision
|
||||
|
||||
At the rail settle point, the four upper 36px controls start from one left-anchored layout and share one `150ms` animation from `translateX(49px)` to their final 10px inset. The shell applies the translation to its toggle and New Session seats and once to the workspace region, so add and search inherit the same path without nested transforms. Opacity uses the same animation timeline.
|
||||
|
||||
The settings seat uses a separate opacity-only keyframe with the same duration and easing. A page that starts collapsed renders the rail without an entry animation, and reduced-motion mode disables both keyframes.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep every rail control fixed at its final inset.** This removes the mismatch, but it also removes the requested horizontal entry from the four upper controls.
|
||||
|
||||
**Animate each workspace button independently.** This would duplicate shell timing inside `ui-workspace` and could apply both a region and child transform. Translating the registered region once keeps animation ownership in the sidebar shell.
|
||||
|
||||
**Translate the settings control with the upper controls.** Rejected because settings is a bottom-pinned foot action, not part of the upper control sequence.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Toggle, New Session, add, and search follow the same horizontal coordinates throughout collapse.
|
||||
- Settings fades at its final horizontal coordinate.
|
||||
- Static collapsed renders retain their final geometry without startup motion.
|
||||
- Style tests pin the shared animation assignments, translation distance, base anchors, and settings exception.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Agent Note: 收起侧栏的上方控件共用同一进入动画
|
||||
|
||||
Status: implemented
|
||||
Archived: 2026-08-12
|
||||
|
||||
[English](2026-08-12-collapsed-sidebar-shared-entry-motion.md) | 中文
|
||||
|
||||
## Problem
|
||||
|
||||
收起侧栏轨道的四个上方控件由两个包渲染:外壳持有侧栏切换与新建会话,Workspace 区域持有添加和搜索。它们的透明度时序相同,但几何行为不同。右对齐控件会随栏变窄而移动,左对齐控件则保持不动,因此添加即使使用相同淡入,视觉上仍比搜索慢。
|
||||
|
||||
底部设置控件承担不同角色。它固定在轨道页脚,不能参与上方控件的横向进入。
|
||||
|
||||
## Decision
|
||||
|
||||
轨道落位时,四个 36px 上方控件从同一个左对齐布局开始,共用一段 `150ms` 动画,从 `translateX(49px)` 移动到最终 10px 内边距。外壳把位移分别应用于侧栏切换、新建会话,并只对 Workspace 区域应用一次,因此添加与搜索会继承同一路径,不产生嵌套变换。透明度使用同一条动画时间线。
|
||||
|
||||
设置控件使用时长与缓动相同、但只改变透明度的独立关键帧。页面初始即为收起状态时不会播放进入动画;减少动态效果模式会禁用两段关键帧。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**把每个轨道控件固定在最终内边距。** 这能消除不一致,但也会移除四个上方控件所需的横向进入效果。
|
||||
|
||||
**分别为每个 Workspace 按钮添加动画。** 这会在 `ui-workspace` 中重复外壳时序,还可能同时应用区域与子控件变换。只移动一次已注册区域,可以让动画继续由侧栏外壳持有。
|
||||
|
||||
**让设置控件随上方控件一起移动。** 不予采纳,因为设置是固定在底部的页脚操作,不属于上方控件序列。
|
||||
|
||||
## Consequences
|
||||
|
||||
- 侧栏切换、新建会话、添加与搜索在整个收起过程中使用相同横坐标。
|
||||
- 设置在最终横坐标上淡入。
|
||||
- 静态收起渲染保持最终几何,不播放启动动画。
|
||||
- 样式测试固定共用动画分配、位移距离、基础锚点与设置例外。
|
||||
@@ -97,6 +97,9 @@
|
||||
"bug-fix/2026-08-10-web-favicon-dark-mode.i18n.yaml": "sha256:859c4399f9a017a68ba89552fdafa05e73c0599d94cee9551c84ea5b749a14f3",
|
||||
"bug-fix/2026-08-10-web-favicon-dark-mode.md": "sha256:4d17e247abd76ae3aed5fb4e075fd66a2838292f89f7021c82a79fe37ed905e6",
|
||||
"bug-fix/2026-08-10-web-favicon-dark-mode.zh.md": "sha256:7bbff8a3b7061c127afcc75cd2a8043b02a999b78c0180edd8f7e4807fcfe71d",
|
||||
"bug-fix/2026-08-12-collapsed-sidebar-shared-entry-motion.i18n.yaml": "sha256:3ce4f6e39e173fc304bf64deca9c95bcddc1dbb492e065ca8c267a7a40788588",
|
||||
"bug-fix/2026-08-12-collapsed-sidebar-shared-entry-motion.md": "sha256:7b169aa4543edfc965de5a8b7b9e60aa9d9d5218693cd0b57908e2d482280723",
|
||||
"bug-fix/2026-08-12-collapsed-sidebar-shared-entry-motion.zh.md": "sha256:88db36c698800bf55c3c7531d6f92665576d978c29c15ff7d74215fb93376cb1",
|
||||
"feature/2026-06-14-acp-agent-client-protocol.i18n.yaml": "sha256:006795baa43ae962a8d125cc0f1e9f134bc2ee9fb758b6e7669e3fa0126e1918",
|
||||
"feature/2026-06-14-acp-agent-client-protocol.md": "sha256:6828c0af74bb3fb96206ca6b21c0e56a000b50e4744aad4bc2c05092f3a5a31b",
|
||||
"feature/2026-06-14-acp-agent-client-protocol.zh.md": "sha256:ba104e841a1fb84edbd3b6c8119d50445b7785255a7a8d13bb9ac8a2cb4d2e69",
|
||||
|
||||
+2
-2
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-04-composer-tab-gutter-reservation.md
|
||||
2026-08-04-composer-tab-gutter-reservation.md: 3b28c35c1f11676e41cabde76d1b0d16c688f034
|
||||
2026-08-04-composer-tab-gutter-reservation.zh.md: c357dd06c52a834c18d2e8a25246d4ad003db548
|
||||
2026-08-04-composer-tab-gutter-reservation.md: 8bd9fb2d86982d82b44a82c55b7303fcd9a5bf4d
|
||||
2026-08-04-composer-tab-gutter-reservation.zh.md: 4b70aeb1d3777384907c345968971fcf75b3e74d
|
||||
@@ -14,13 +14,11 @@ So for as long as the transcript overflowed — the ordinary state of any sessio
|
||||
|
||||
## Decision
|
||||
|
||||
`.scrollBody` declares `scrollbar-gutter: stable` unconditionally, and the overlay branch declares the same box a scroll container on both axes — `overflow-x: hidden; overflow-y: auto` — instead of `overflow: hidden`.
|
||||
`.scrollBody` declares `scrollbar-gutter: stable` for the Chat state, and the overlay branch overrides it with `scrollbar-gutter: auto` while staying a scroll container on both axes — `overflow-x: hidden; overflow-y: auto`. The reservation is Chat's alone: it holds the seat's content box at the same width whether or not the transcript overflows, so the card never jumps as a growing transcript starts to scroll, nor between the hero phase and the first scrolling turn. The overlay branch reserves nothing — the view owns its own scrollers, so a gutter there would only narrow the view's content — and its seat compensates for the bar instead ([the seat-width compensation](2026-08-12-composer-overlay-seat-width-compensation.md)).
|
||||
|
||||
The two halves are one change. The reservation is what makes both states measure against the same width; declaring the overlay branch a scroll container is what makes the reservation reach it. `stable` rather than `auto` because `auto` reserves only while the box actually overflows, and the difference between overflowing and not is precisely the difference between the two tabs — an `auto` gutter would state the bug rather than fix it.
|
||||
`stable` rather than `auto` because `auto` reserves only while the box actually overflows, and the difference between overflowing and not is precisely the difference between Chat's two phases — an `auto` gutter would state the bug rather than fix it.
|
||||
|
||||
The overlay state is a scroll container that nothing scrolls: the view fills it (`flex: 1 1 0` with its own clip) and the seat is out of flow, so no gesture and no clipping behavior changes. What changes is which declarations the engine honours. WebKit applies `scrollbar-gutter` to an `overflow-y: auto` box and ignores it on a hidden one — measured on this app's own composer layers and recorded in [the composer scrollport note](2026-07-31-composer-text-layers-share-one-scrollport.md) — so a reservation left on a hidden box would hold in Chromium and silently not in Safari.
|
||||
|
||||
The horizontal axis is declared rather than left to compute: a box that scrolls on one axis computes `visible` on the other to `auto`, and would grow a horizontal scrollbar of its own the first time a view's content reached past the column.
|
||||
The reservation lives on an `overflow-y: auto` box, and that form is load-bearing: WebKit applies `scrollbar-gutter` to an `overflow-y: auto` box and ignores it on a hidden one — measured on this app's own composer layers and recorded in [the composer scrollport note](2026-07-31-composer-text-layers-share-one-scrollport.md) — so a reservation on a hidden box would hold in Chromium and silently not in Safari. The overlay branch keeps its `overflow-y: auto` form too, as a clipping box nothing scrolls out of: a single-axis scroller computes the other axis to `auto`, so the horizontal axis is declared `hidden` rather than left to compute, and would otherwise grow a horizontal scrollbar of its own the first time a view's content reached past the column.
|
||||
|
||||
The reservation is worth what it costs only because the bar takes layout space here at all, which is not the browser's default behavior but this client's: `::-webkit-scrollbar` carries a width in ui-theme's sheet ([themed scrollbars](2026-07-28-themed-scrollbars-and-reserved-gutter.md)), and the sidebar's session list already reserves its own gutter for the same reason.
|
||||
|
||||
@@ -37,7 +35,7 @@ The reservation is worth what it costs only because the bar takes layout space h
|
||||
## Consequences
|
||||
|
||||
- Chat's content column is permanently 8px narrower — in the hero phase and while the transcript is short as well, where no bar is drawn. That is the trade: one card position at every content height, instead of the widest possible column.
|
||||
- The fix covers three transitions with one declaration, because all three are the same difference: Chat ↔ Trajectory, short ↔ scrolling transcript within Chat, and hero ↔ first scrolling turn.
|
||||
- The card holds one position across three transitions, by two mechanisms: the reservation keeps Chat's seat at one width across its own phases (short ↔ scrolling transcript, hero ↔ first scrolling turn), and the overlay seat's compensation matches it on the Chat ↔ Trajectory transition ([the seat-width compensation](2026-08-12-composer-overlay-seat-width-compensation.md)).
|
||||
- The overlay state is now a scroll container. Nothing in it can overflow today; a future view that let its content exceed the column would scroll this box instead of clipping, and would need its own clip the way the Trajectory view already has one.
|
||||
- The committed golden records the reserved band, so a change to the sheet's `::-webkit-scrollbar` width — the value that decides how wide the reservation is — arrives as a reviewable diff in this scenario as well as in the sidebar's.
|
||||
|
||||
@@ -45,6 +43,6 @@ The reservation is worth what it costs only because the bar takes layout space h
|
||||
|
||||
`apps/web/tests/composer-tab-geometry.e2e.ts` measures the input card's rectangle in both tabs, at a viewport where the card sits at its width cap and one where it shrinks with the column, and asserts the two rectangles are the same rectangle. Only a real engine reports this: jsdom gives every element a zero-sized box and no scrollbar, so a unit spec could assert the declarations exist but not that the two states land in the same place. For the same reason no CSS-text spec accompanies it — it would restate the declarations without adding a fact the browser lane does not already establish.
|
||||
|
||||
The scenario launches chromium without Playwright's default `--hide-scrollbars`, which is load-bearing: under that argument a bar consumes no layout width, both tabs agree before this change as much as after it, and every comparison in the file holds vacuously. Measured, the pre-fix cascade leaves both bands at 0 under the argument, and at 8 and 0 with it dropped.
|
||||
The scenario launches chromium without Playwright's default `--hide-scrollbars`, which is load-bearing: under that argument a bar consumes no layout width, so the tabs agree with and without the compensation and every comparison in the file holds vacuously. Measured, both bands sit at 0 under the argument and at 8 and 0 with it dropped.
|
||||
|
||||
The pre-fix cascade is then applied in the page — `scrollbar-gutter: auto` on the scroller, `overflow: hidden` on the overlay branch — and the same two tabs measured through it, which is what separates a card that does not move from a tab switch that never reached the layout. It reproduces the reported symptom as a number: 4px on each edge, half the 8px band. The golden records that control beside the fixed state, so the fixture carries the difference the change removes rather than only its absence.
|
||||
The uncompensated cascade is then applied in the page — the overlay seat's `right` compensation dropped to 0 via `!important`, Chat's reservation untouched — and the same two tabs measured through it, which is what separates a card that does not move from a tab switch that never reached the layout. It reproduces the reported symptom as a number: 4px on each edge, half the 8px band. The golden records that control beside the fixed state, so the fixture carries the difference the change removes rather than only its absence.
|
||||
@@ -14,13 +14,11 @@ composer 座位在组件树中只有一个节点、一个位置,但它究竟
|
||||
|
||||
## 决策
|
||||
|
||||
`.scrollBody` 无条件声明 `scrollbar-gutter: stable`,overlay 分支则把同一个盒子在两个轴向上都声明为滚动容器——`overflow-x: hidden; overflow-y: auto`——而不再是 `overflow: hidden`。
|
||||
`.scrollBody` 为 Chat 状态声明 `scrollbar-gutter: stable`,覆盖分支则将其覆盖为 `scrollbar-gutter: auto`,同时保持为双轴滚动容器——`overflow-x: hidden; overflow-y: auto`。这条预留只属于 Chat:它让座位的内容盒在 transcript 是否溢出时都保持同一宽度,因此卡片不会在 transcript 增长到开始滚动的那一刻跳动,也不会在 hero 态与第一个可滚动轮次之间跳动。覆盖分支不预留任何槽位——视图自己滚动,槽位只会白白收窄视图内容——它的座位改为补偿滚动条宽度([座位宽度补偿](2026-08-12-composer-overlay-seat-width-compensation.md))。
|
||||
|
||||
这两半是同一处改动。预留使两种状态依附于同一个宽度;把 overlay 分支声明为滚动容器,才使这条预留真正抵达它。选 `stable` 而非 `auto`,是因为 `auto` 只在盒子确实溢出时才预留,而「溢出与否」恰恰就是两个标签页之间的那点差别——`auto` 的写法只是把缺陷重述一遍,并不能修掉它。
|
||||
选 `stable` 而非 `auto`,是因为 `auto` 只在盒子确实溢出时才预留,而「溢出与否」恰恰就是 Chat 两种相位之间的那点差别——`auto` 的写法只是把缺陷重述一遍,并不能修掉它。
|
||||
|
||||
overlay 状态是一个没有任何东西会去滚动它的滚动容器:视图把它填满(`flex: 1 1 0`,且自带裁剪),座位不在常规流中,因此没有任何手势与裁剪行为发生变化。变化的是引擎会认哪些声明。WebKit 对 `overflow-y: auto` 的盒子应用 `scrollbar-gutter`,对 hidden 的盒子则忽略它——这是在本应用 composer 自身的图层上实测所得,并记录于 [composer 滚动视口记录](2026-07-31-composer-text-layers-share-one-scrollport.md)——所以把预留留在一个 hidden 盒子上,会在 Chromium 上成立,在 Safari 上悄无声息地不成立。
|
||||
|
||||
横向轴是显式声明的,而不是交给推导:单轴滚动的盒子会把另一轴的 `visible` 计算为 `auto`,于是只要某个视图的内容第一次伸出列外,它就会长出自己的横向滚动条。
|
||||
这条预留位于 `overflow-y: auto` 的盒子上,而这个形式是承重的:WebKit 对 `overflow-y: auto` 的盒子应用 `scrollbar-gutter`,对 hidden 的盒子则忽略它——这是在本应用 composer 自身的图层上实测所得,并记录于 [composer 滚动视口记录](2026-07-31-composer-text-layers-share-one-scrollport.md)——所以把预留放在 hidden 盒子上,会在 Chromium 上成立,在 Safari 上悄无声息地不成立。覆盖分支同样保留 `overflow-y: auto` 的形式,作为没有任何内容会滚出去的裁剪盒:单轴滚动的盒子会把另一轴的 `visible` 计算为 `auto`,因此横向轴显式声明为 `hidden` 而不是交给推导,否则某个视图的内容第一次伸出列外时,它就会长出自己的横向滚动条。
|
||||
|
||||
这条预留之所以值回它的代价,前提是滚动条在这里确实占布局空间——这并非浏览器的默认行为,而是本客户端的选择:ui-theme 的样式表给 `::-webkit-scrollbar` 声明了宽度([滚动条主题化](2026-07-28-themed-scrollbars-and-reserved-gutter.md)),侧边栏的会话列表也正是出于同一原因预留了自己的滚动条槽。
|
||||
|
||||
@@ -37,7 +35,7 @@ overlay 状态是一个没有任何东西会去滚动它的滚动容器:视图
|
||||
## 后果
|
||||
|
||||
- Chat 的内容列永久变窄 8px——hero 态与 transcript 尚短、根本不绘制滚动条时同样如此。这就是这笔交易:以最宽的列换取卡片在任何内容高度下都只有一个位置。
|
||||
- 一条声明覆盖三种切换,因为这三者本就是同一个差异:Chat ↔ Trajectory、Chat 内部 transcript 较短 ↔ transcript 可滚动,以及 hero ↔ 第一个可滚动轮次。
|
||||
- 卡片在三种切换下保持同一位置,由两种机制达成:预留让 Chat 的座位在自身各相位间保持同一宽度(transcript 较短 ↔ 可滚动、hero ↔ 第一个可滚动轮次),Chat ↔ Trajectory 的切换则由覆盖座位的补偿来对齐([座位宽度补偿](2026-08-12-composer-overlay-seat-width-compensation.md))。
|
||||
- overlay 状态现在是一个滚动容器。今天其中没有任何内容会溢出;将来若有视图允许自身内容超出会话列,这个盒子会滚动而不是裁剪,那个视图就需要像 Trajectory 视图那样自带裁剪。
|
||||
- 提交的 golden 记录了预留条带,因此样式表中 `::-webkit-scrollbar` 宽度的变化——决定这条预留有多宽的那个值——会在本场景中与在侧边栏场景中一样,以可评审的 diff 形式出现。
|
||||
|
||||
@@ -45,6 +43,6 @@ overlay 状态是一个没有任何东西会去滚动它的滚动容器:视图
|
||||
|
||||
`apps/web/tests/composer-tab-geometry.e2e.ts` 在两个标签页下测量输入卡片的矩形,分别取卡片处于宽度上限的视口与卡片随列收缩的视口,并断言这两个矩形是同一个矩形。只有真实引擎能报告这件事:jsdom 给每个元素的盒子尺寸都是零,也没有滚动条,因此单元测试只能断言那些声明存在,无法断言两种状态落在同一位置。出于同一原因,本次没有附带读取 CSS 文本的单元测试——它只会把声明复述一遍,并不会补上浏览器车道尚未确立的事实。
|
||||
|
||||
该场景启动 chromium 时去掉了 Playwright 默认的 `--hide-scrollbars`,这一点是承重的:带上该参数时滚动条不占任何布局宽度,两个标签页在改动前后同样一致,文件中的每一处比较都会空洞地通过。实测:带上该参数时,改动前的层叠让两条预留带的宽度都是 0;去掉它则分别是 8 与 0。
|
||||
该场景启动 chromium 时去掉了 Playwright 默认的 `--hide-scrollbars`,这一点是承重的:带上该参数时滚动条不占任何布局宽度,因此两个标签页在有补偿与无补偿时同样一致,文件中的每一处比较都会空洞地通过。实测:带上该参数时两条预留带的宽度都是 0;去掉它则分别是 8 与 0。
|
||||
|
||||
随后,改动前的层叠会被注入页面——滚动容器上 `scrollbar-gutter: auto`,overlay 分支上 `overflow: hidden`——并在其下测量同样的两个标签页,这正是把「卡片确实没动」与「标签页切换根本没到达布局」区分开的那一步。它把上报的症状复现为一个数字:每条边 4px,恰是 8px 带宽的一半。golden 把这份对照与修复后的状态并排记录,因此 fixture(测试前置数据)承载的是这次改动所消除的那个差值,而不仅仅是它的缺席。
|
||||
随后,未补偿的级联会被注入页面——通过 `!important` 把覆盖座位的 `right` 补偿降为 0,Chat 的预留保持不变——并在其下测量同样的两个标签页,这正是把「卡片确实没动」与「标签页切换根本没到达布局」区分开的那一步。它把上报的症状复现为一个数字:每条边 4px,恰是 8px 带宽的一半。golden 把这份对照与修复后的状态并排记录,因此 fixture(测试前置数据)承载的是这次改动所消除的那个差值,而不仅仅是它的缺席。
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-composer-overlay-seat-width-compensation.md
|
||||
2026-08-12-composer-overlay-seat-width-compensation.md: 0ec4d1272ac1adab5b724dccf44f567e15cc3368
|
||||
2026-08-12-composer-overlay-seat-width-compensation.zh.md: 2f66771240fe62e15c481342d55a82dd09cfb864
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Agent Note: The overlay composer seat compensates for the bar instead of reserving a gutter
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-12-composer-overlay-seat-width-compensation.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The [composer-tab gutter reservation](2026-08-04-composer-tab-gutter-reservation.md) made the column's scroller reserve a scrollbar gutter unconditionally, so the composer seat measured the same width in Chat and in a view with a composer overlay. The cost was paid by every overlay view: the view's content column ended 8px short of the column's right edge, because the scroller reserved a gutter for a bar it never draws — the trajectory ledger owns its own scrollers and the outer box never scrolls.
|
||||
|
||||
The trajectory table made that cost visible: its full-width row divider lines stopped 8px short of the pane edge, leaving a strip of whitespace at the right of every line and of the whole content column.
|
||||
|
||||
## Decision
|
||||
|
||||
The reservation now belongs to Chat alone. The overlay branch declares `scrollbar-gutter: auto`, so the view's content spans the full column; the overlay composer seat (absolutely positioned against the padding box) gives back the bar's width with `right: var(--dsh-scrollbar-width)`, so the input card still measures the same width as Chat's seat and does not move between tabs.
|
||||
|
||||
The compensation value is not a literal: ui-theme's scrollbar.css defines `--dsh-scrollbar-width` (8px on the WebKit path) beside the `::-webkit-scrollbar` rule it mirrors, and the seat reads that variable. The scrollbar-styles spec pairs the variable with the mirrored rule and with the compensation consumer, so a change to the sheet's bar width without the variable — or to the variable without the consumer — fails the gate, not just review.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep the unconditional reservation and shrink every overlay view.** The pre-fix behavior. It keeps one declaration for both tabs but taxes every overlay view with an 8px content column, which the trajectory ledger surfaced as visible whitespace. Rejected because the overlay views own their scrolling; they should not pay for Chat's bar.
|
||||
|
||||
**Reserve on the overlay branch too and let the view bleed into the gutter.** More moving parts for the same result: the gutter would still exist on a box that never scrolls, and the view would have to break out of the content box to reclaim its width.
|
||||
|
||||
**Accept the 4px card shift.** Dropping the reservation without compensating the seat would move the input card on every tab switch, which is exactly the symptom the earlier note fixed. Rejected: the card position is a deliberate cross-tab invariant.
|
||||
|
||||
**Inset the overlay seat by the bar's width.** The [gutter-reservation note](2026-08-04-composer-tab-gutter-reservation.md) rejected exactly this, and this note adopts it; what changed is the rejection's premise. The number was the engine's, not ours — the WebKit path draws the sheet's 8px bar while the Firefox path draws whatever `scrollbar-width: thin` resolves to — so a hardcoded inset would line the two states up in Chromium and drift elsewhere. The overlay branch reserved an engine-resolved gutter of its own back then, so an inset had to match that width exactly. Today the overlay branch reserves nothing, so the compensation is the overlay side's only mechanism, and the literal half of the rejection is answered by making the 8px a variable that mirrors the `::-webkit-scrollbar` rule in the same diff. The Firefox half remains: Chat reserves the engine-resolved width while the compensation stays fixed, and the residual drift where the two differ is recorded as an accepted cost in Consequences.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Chat keeps its reserved gutter and its stable card position; nothing changes on that tab.
|
||||
- Overlay views (trajectory) span the full column; the trajectory ledger's divider lines reach the pane edge.
|
||||
- The input card still holds one horizontal position across the Chat and Trajectory tabs, now by two mechanisms instead of one: Chat reserves, the overlay seat compensates.
|
||||
- Chat reserves the engine-resolved width while the overlay seat compensates a fixed 8px. Where the two differ — the Firefox path resolves `scrollbar-width: thin` per platform, and the e2e runs only on Chromium — the card drifts by half the difference on tab switch. Accepted residual cost, recorded here rather than asserted away: no measurement of the Firefox thin width on the target platforms exists in this change.
|
||||
- `--dsh-scrollbar-width` becomes a public ui-theme variable read outside ui-theme; the scrollbar-styles spec pairs it with the mirrored `::-webkit-scrollbar` width rule and with the compensation consumer, closing the indirection-gate gap the variable would otherwise leave.
|
||||
|
||||
## Testing
|
||||
|
||||
`apps/web/tests/composer-tab-geometry.e2e.ts` still asserts the card holds its position across tabs and now also asserts the split: Chat's scroller keeps `scrollbar-gutter: stable` and a nonzero band, while the overlay branch resolves `auto` with a zero band. The control cascade changed with the mechanism: it now drops the seat's `right` compensation (instead of dropping a gutter Chat never had on that branch) and measures the same 4px shift, proving the equal rectangles are not a tab switch that never reached layout. The committed golden records both states.
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Agent Note: 覆盖视图的 composer 座位改为补偿滚动条宽度,不再预留滚动条槽
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-12-composer-overlay-seat-width-compensation.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
[composer 标签页滚动条槽预留](2026-08-04-composer-tab-gutter-reservation.md) 让会话列滚动容器无条件预留一条滚动条槽,使 composer 座位在 Chat 与带 composer 覆盖的视图中测得相同宽度。代价由每个覆盖视图承担:视图内容列比列右边缘窄 8px,因为滚动容器为一条它从不绘制的滚动条预留了槽——trajectory 台账由视图内部自己的滚动容器滚动,外层盒子从不滚动。
|
||||
|
||||
trajectory 表格让这个代价显形:整行分隔线在面板右边缘前 8px 处停止,每条线右侧以及整个内容列右侧都留下一条空白带。
|
||||
|
||||
## 决策
|
||||
|
||||
预留现在只属于 Chat。覆盖分支声明 `scrollbar-gutter: auto`,视图内容占满整列;覆盖分支的 composer 座位(相对 padding box 绝对定位)用 `right: var(--dsh-scrollbar-width)` 让出滚动条宽度,使输入卡仍与 Chat 座位测得相同宽度,切换标签页时不移动。
|
||||
|
||||
补偿值不是字面量:ui-theme 的 scrollbar.css 在它镜像的 `::-webkit-scrollbar` 规则旁定义 `--dsh-scrollbar-width`(WebKit 路径 8px),座位读取该变量。scrollbar-styles 规格把该变量与其镜像规则、以及补偿消费者配对检查,因此样式表滚动条宽度一变却不同步变量——或变量一变却不同步消费者——都会让门禁失败,而不只是评审时发现。
|
||||
|
||||
## 备选方案
|
||||
|
||||
**保留无条件预留,压缩每个覆盖视图。** 修复前行为。两个标签页一条声明,但每个覆盖视图都要付出 8px 内容列,trajectory 台账将其显现为可见空白。已拒绝:覆盖视图自己滚动,不应为 Chat 的滚动条买单。
|
||||
|
||||
**覆盖分支也预留,并让视图渗入滚动条槽。** 同样结果下更多活动部件:从不滚动的盒子上仍存在滚动条槽,视图还得突破内容盒才能取回宽度。
|
||||
|
||||
**接受 4px 卡片位移。** 去掉预留却不补偿座位,会在每次切换标签页时移动输入卡——正是前一份 note 修复的症状。已拒绝:卡片位置是刻意保持的跨标签页不变量。
|
||||
|
||||
**把 overlay 座位按滚动条宽度内缩。** [滚动条槽预留 note](2026-08-04-composer-tab-gutter-reservation.md) 当初否决的正是这个方案,本 note 采纳了它;变的是否决的前提。这个数字属于引擎而不属于我们——WebKit 路径绘制样式表里的 8px 滚动条,Firefox 路径绘制 `scrollbar-width: thin` 解析出的宽度——因此硬编码的内缩会让两种状态在 Chromium 上对齐、在别处继续漂移。当初 overlay 分支自己预留的是引擎解析出的槽宽,内缩必须精确匹配那个宽度。如今 overlay 分支不预留任何槽位,补偿成为覆盖侧唯一的机制;否决的字面量那一半,通过把 8px 变成与 `::-webkit-scrollbar` 规则同处一个 diff 的变量来回应。Firefox 那一半仍然存在:Chat 预留引擎解析宽度,补偿保持固定 8px,两者不等之处的残余漂移作为接受的代价记录在后果中。
|
||||
|
||||
## 后果
|
||||
|
||||
- Chat 保留滚动条槽与稳定的卡片位置;该标签页无任何变化。
|
||||
- 覆盖视图(trajectory)占满整列;trajectory 台账的分隔线到达面板右边缘。
|
||||
- 输入卡在 Chat 与 Trajectory 标签页间仍保持同一水平位置,现在由两种机制而非一种达成:Chat 预留,覆盖座位补偿。
|
||||
- Chat 预留引擎解析宽度,覆盖座位补偿固定的 8px。两者不等之处——Firefox 路径按平台解析 `scrollbar-width: thin`,而 e2e 只在 Chromium 上运行——卡片在切换标签页时会漂移半个差值。这是接受的残余代价,如实记录于此而不断言消除:本次改动并未提供目标平台 Firefox thin 宽度的实测。
|
||||
- `--dsh-scrollbar-width` 成为 ui-theme 对外、且被 ui-theme 之外读取的变量;scrollbar-styles 规格把它与镜像的 `::-webkit-scrollbar` 宽度规则、以及补偿消费者配对检查,补上了该变量本会留下的间接层门禁缺口。
|
||||
|
||||
## 测试
|
||||
|
||||
`apps/web/tests/composer-tab-geometry.e2e.ts` 仍断言输入卡在标签页间保持位置,并新增断言拆分:Chat 滚动容器保持 `scrollbar-gutter: stable` 与非零槽宽,覆盖分支解析为 `auto` 且槽宽为零。控制级联随机制改变:现在移除座位的 `right` 补偿(而非移除该分支上 Chat 从未有过的槽),测得同样的 4px 位移,证明相等的矩形并非从未到达布局的标签页切换。提交的 golden 记录两种状态。
|
||||
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-resolve-store-pwsh-aliases.md
|
||||
2026-08-12-resolve-store-pwsh-aliases.md: 20fe58e15e75462dc0a9ba76c7a1a94939f8a004
|
||||
2026-08-12-resolve-store-pwsh-aliases.zh.md: bbfa4616127a9dbdb6609fe2973283663de55b31
|
||||
@@ -0,0 +1,23 @@
|
||||
# Agent Note: Resolve Microsoft Store pwsh aliases
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-12-resolve-store-pwsh-aliases.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
`resolvePwshPath` documented that Microsoft Store installs resolve through PATH, but its existence probe was `existsSync`, which stats a candidate and therefore follows reparse points. The Store's `%LOCALAPPDATA%\Microsoft\WindowsApps\pwsh.exe` is an app execution alias whose target directory ACL refuses stat (EACCES), so `existsSync` missed it and resolution silently fell through to Windows PowerShell 5.1 on hosts whose only PowerShell 7 is a Store install.
|
||||
|
||||
## Decision
|
||||
|
||||
`candidateExists` accepts a candidate that stats as a file or that lstat sees as a link-shaped reparse point, and `resolvePwshPath` uses it. Spawning the alias path works because CreateProcess resolves app execution aliases. A dangling link-shaped candidate is accepted so a broken pwsh fails loudly at spawn instead of silently downgrading to 5.1.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Probe the WindowsApps package directory directly.** The Store package path is versioned and ACL-hidden; hard-coding it duplicates packaging knowledge that PATH plus the alias already owns.
|
||||
|
||||
**Keep the 5.1 fallback for stat failures.** Rejected: it silently runs a different shell than the one installed, which is the defect this note fixes.
|
||||
|
||||
## Consequences
|
||||
|
||||
Store-installed PowerShell 7 now resolves ahead of the 5.1 fallback on Windows; real-file candidates and non-Windows behavior are unchanged. The dangling-symlink unit test pins the stat/lstat split on every platform.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Agent Note: 解析 Microsoft Store 的 pwsh 别名
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-12-resolve-store-pwsh-aliases.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
`resolvePwshPath` 声称 Store 安装经 PATH 解析,但它的存在性探测用的是 `existsSync`,会对候选做 stat、从而跟随重解析点。Store 的 `%LOCALAPPDATA%\Microsoft\WindowsApps\pwsh.exe` 是 app execution alias,其目标目录的 ACL 拒绝 stat(EACCES),于是 `existsSync` 看不到它,解析静默落到 Windows PowerShell 5.1——在这类「唯一的 PowerShell 7 是 Store 安装」的机器上就用了错误的 shell。
|
||||
|
||||
## 决策
|
||||
|
||||
`candidateExists` 接受「stat 为文件」或「lstat 为链接形态重解析点」的候选,`resolvePwshPath` 改用它。spawn 别名路径可以工作,因为 CreateProcess 会解析 app execution alias。悬空的链接形态候选同样被接受,让损坏的 pwsh 在 spawn 时响亮失败,而不是静默降级到 5.1。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
**直接探测 WindowsApps 包目录。** Store 包路径带版本且被 ACL 隐藏;硬编码它只是重复了 PATH 加别名已经拥有的打包知识。
|
||||
|
||||
**对 stat 失败继续走 5.1 回退。** 否决:它静默运行了一个并非所装的 shell,这正是本 note 修复的缺陷。
|
||||
|
||||
## 后果
|
||||
|
||||
Windows 上 Store 安装的 PowerShell 7 现在先于 5.1 回退被解析;普通文件候选和非 Windows 平台行为不变。悬空 symlink 单元测试在全部平台上钉住 stat/lstat 的分裂行为。
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-unlink-fixture-junctions-before-delete.md
|
||||
2026-08-12-unlink-fixture-junctions-before-delete.md: 4514a33d728866b817f4e9c1393f16c07976ed45
|
||||
2026-08-12-unlink-fixture-junctions-before-delete.zh.md: 3c212c052ab0303ccb8d31d2b310a365a1d8cc99
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Agent Note: Unlink fixture junctions before recursive deletion
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-12-unlink-fixture-junctions-before-delete.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The install-lefthook and translation-pairing fixtures junction the repository's real `scripts/`, `node_modules`, and tsx package directories into fixture trees so installer probes resolve through them. Windows recursive deletion can treat a junction (a MOUNT_POINT reparse point) as a directory and follow it into its target; Git's `worktree remove` did exactly that and deleted the repository's tracked `scripts/` and tsx package (the incident's instrumentation pinned the deletion to that step). A fixture cleanup that trusts its deleter therefore deletes the repository's own sources instead of the fixture.
|
||||
|
||||
## Decision
|
||||
|
||||
`scripts/test-fixture-cleanup.ts` owns junction-safe fixture teardown: `unlinkFixtureLinks` walks a tree and unlinks every reparse point before `removeFixtureSafely` removes the now link-free tree (with Windows async-handle retries). Every affected `afterEach` and the pre-`worktree remove` hook call it. The general rule lives in `docs/defensive-patterns.md`: remove link-shaped paths with unlink, reserve recursive `rmSync` for known real directories.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Trust recursive deletion alone.** Rejected: whether a given deleter follows junctions is tool- and version-dependent, and one path through `git worktree remove` already destroyed tracked files; no cleanup may bet the repository on that behavior.
|
||||
|
||||
**Copy instead of junctioning the real directories.** Rejected: the fixtures exist to probe the real installer paths through their real contents, so copies would stop exercising the boundary under test.
|
||||
|
||||
## Consequences
|
||||
|
||||
Fixture teardown can no longer reach repository sources through junctions. The extra walk is one lstat/unlink pass over small fixture trees. The data-destroying defect now has its durable why beside the defensive-patterns rule, and the helper is the shared teardown path for future junction fixtures.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Agent Note: 递归删除前先解链 fixture junction
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-12-unlink-fixture-junctions-before-delete.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
install-lefthook 与 translation-pairing 的 fixture 把仓库真实的 `scripts/`、`node_modules` 和 tsx 包目录用 junction 链进 fixture 树,让 installer 探测能穿透解析。Windows 的递归删除可能把 junction(MOUNT_POINT 重解析点)当作目录并跟随进其目标;Git 的 `worktree remove` 正是这样删掉了仓库被跟踪的 `scripts/` 和 tsx 包(事故的插桩把删除定位到这一步)。因此,信任删除器的 fixture 清理删掉的是仓库自己的源码,而不是 fixture。
|
||||
|
||||
## 决策
|
||||
|
||||
`scripts/test-fixture-cleanup.ts` 拥有 junction 安全的 fixture 拆除:`unlinkFixtureLinks` 先遍历并解链所有重解析点,`removeFixtureSafely` 再删除已无链接的树(带 Windows 异步句柄重试)。所有受影响的 `afterEach` 和 `worktree remove` 前的钩子都调用它。通用规则记录在 `docs/defensive-patterns.md`:链接形态的路径用 unlink 删除,递归 `rmSync` 只留给确知为真实目录的路径。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
**只信任递归删除。** 否决:特定删除器是否跟随 junction 随工具和版本而异,而 `git worktree remove` 这一条路径已经摧毁过被跟踪文件;任何清理都不该拿仓库去赌这个行为。
|
||||
|
||||
**复制而不是 junction 真实目录。** 否决:fixture 的意义就是用真实内容探测真实 installer 路径,复制品会失去被测边界。
|
||||
|
||||
## 后果
|
||||
|
||||
fixture 拆除不再能穿过 junction 触及仓库源码。额外开销只是对小型 fixture 树的一趟 lstat/unlink。这个摧毁数据的缺陷现在在 defensive-patterns 规则旁有了持久化的原因,helper 也是未来所有 junction fixture 共享的拆除路径。
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-12-unlink-stale-profile-fallback-links.md
|
||||
2026-08-12-unlink-stale-profile-fallback-links.md: 32959eb1b83bcc290d1daa4e4a020a2721be489b
|
||||
2026-08-12-unlink-stale-profile-fallback-links.zh.md: 1f4da12748c9b57c12bf41a740001d5df770beb6
|
||||
@@ -0,0 +1,25 @@
|
||||
# Agent Note: Unlink stale profile fallback links instead of rmSync
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-12-unlink-stale-profile-fallback-links.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
`healProfilesModuleFallback` re-points `$DSH_HOME/profiles/node_modules` entries when an installation moves, and Windows hosts keep those entries as junctions. `ensureSymlink` deleted a stale entry with `rmSync(link)`, but Node treats a junction as a directory for removal: without `recursive`, `rmSync` throws `ERR_FS_EISDIR`, so every launch from a moved installation or a second worktree crashed before booting. The `replaces a wrong symlink` unit test reproduces that crash on Windows at the exact removal call.
|
||||
|
||||
## Decision
|
||||
|
||||
`ensureSymlink` removes a stale link with `unlinkSync(link)`. `unlink` deletes the reparse point or symlink itself on every platform and never descends into the target, which preserves the function's fail-loud guarantee that a real directory is never deleted. The [profile-plugin-bundles decision](../architecture/2026-08-05-profile-plugin-bundles.md) keeps owning the fallback's two-anchor resolution; this note owns only the removal primitive.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**`rmSync(link, { recursive: true })`.** On Node 24 this deletes the junction without following its target, but `recursive` would silently delete a real directory that replaced the link between the `lstat` guard and the removal, weakening the fail-loud contract that motivates the guard.
|
||||
|
||||
**`rmdirSync(link)`.** Removes a junction on Windows as well, but it reads as directory removal for a link, and `unlinkSync` is the repository's existing junction-cleanup idiom.
|
||||
|
||||
**Delete and recreate every entry unconditionally.** Correct but churns unchanged links on every launch and widens the concurrent-heal race window.
|
||||
|
||||
## Consequences
|
||||
|
||||
Windows launches heal moved or second-checkout installations instead of crashing with `ERR_FS_EISDIR`; POSIX behavior is unchanged because `unlinkSync` also unlinks plain symlinks. The existing `replaces a wrong symlink` test now passes on Windows where it previously reproduced the crash. Two concurrent healers deleting the same stale link still surface the second deletion as `ENOENT`, unchanged from the previous `rmSync` implementation.
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Agent Note: 用 unlink 删除过期的 profile 回退链接而非 rmSync
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-12-unlink-stale-profile-fallback-links.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
`healProfilesModuleFallback` 在安装位置迁移时会把 `$DSH_HOME/profiles/node_modules` 中的条目重新指向新目标,而 Windows 主机上这些条目是 junction。`ensureSymlink` 原先用 `rmSync(link)` 删除过期条目,但 Node 在删除时把 junction 当作目录处理:不带 `recursive` 的 `rmSync` 会抛 `ERR_FS_EISDIR`,于是从迁移后的安装或第二个 worktree 启动时,每次都会在应用引导前崩溃。`replaces a wrong symlink` 单元测试在 Windows 上正好在该删除调用处复现了这一崩溃。
|
||||
|
||||
## 决策
|
||||
|
||||
`ensureSymlink` 改用 `unlinkSync(link)` 删除过期链接。`unlink` 在所有平台上都只删除重解析点或符号链接本身、绝不进入目标目录,从而保住该函数“真实目录永远不会被删除”的大声失败保证。[profile-plugin-bundles 决策](../architecture/2026-08-05-profile-plugin-bundles.md)继续拥有回退目录的双锚点解析;本 note 只拥有“用哪个删除原语”这一决定。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
**`rmSync(link, { recursive: true })`。** Node 24 上它只删 junction、不跟随目标,但 `recursive` 会在 `lstat` 守卫与删除之间链接被替换成真实目录时静默删除该目录,削弱守卫存在所依据的大声失败契约。
|
||||
|
||||
**`rmdirSync(link)`。** Windows 上同样能删 junction,但它读起来像“删目录”,而 `unlinkSync` 才是仓库现有的 junction 清理惯例。
|
||||
|
||||
**无条件删除并重建所有条目。** 正确,但每次启动都翻动未变化的链接,并扩大并发修复的竞态窗口。
|
||||
|
||||
## 后果
|
||||
|
||||
Windows 启动现在可以修复迁移后的安装或第二个 checkout,而不是以 `ERR_FS_EISDIR` 崩溃;POSIX 行为不变,因为 `unlinkSync` 同样能 unlink 普通符号链接。现有的 `replaces a wrong symlink` 测试在 Windows 上从复现崩溃变为通过。两个并发 healer 删除同一过期链接时,第二次删除仍会以 `ENOENT` 浮现,与原先的 `rmSync` 实现一致。
|
||||
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md
|
||||
2026-08-13-bounded-cold-blank-verification.md: bf8d167d742001ce65b3e96713a9603adb19603e
|
||||
2026-08-13-bounded-cold-blank-verification.zh.md: 7cfef77a02308a8e75281877f8a774b41bb9559d
|
||||
@@ -0,0 +1,37 @@
|
||||
# Agent Note: Bound cold blank-session verification
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-13-bounded-cold-blank-verification.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The Web session tree hides blank Sessions and reuses the selected blank entry as New Session. Attached Sessions can derive blankness from their in-memory event log, but `session.list` normally avoids loading every cold log. Treating every materialized cold Session as non-blank exposes empty Sessions left by older versions. Treating a projection-cache `blank: true` as current can instead hide a real conversation after the log advances and the fail-soft cache remains stale.
|
||||
|
||||
The same cold list used the JSONL artifact mtime for `updatedAt`. Opening a Session appends `session/end-seed`, so a pickup with no human prompt refreshed mtime and promoted that Session above recently used conversations.
|
||||
|
||||
## Decision
|
||||
|
||||
`dsh-host-apiproxy` registers `sessionListMetadata`, a projection containing `blank` and `lastPromptAt`. The attached summary folds the same functions directly over the live log. `blank` changes only from true to false on `turn/start`; `lastPromptAt` changes only on a `user/message` whose source kind is `user`.
|
||||
|
||||
A cold summary trusts cached `blank: false`, because a checkpoint prefix containing `turn/start` remains non-blank. Cached `blank: true` and a cache miss do not prove the current log is blank. When persistence exposes a physical artifact through `locate()` and its observed size is at most the `coldBlankProbeMaxBytes` eligibility threshold (default 1 KiB per Session), the gateway calls `readFrom(id, 0)` and folds exact list metadata from the stored prefix. Files above the threshold, backends without a location, vanished artifacts, and failed reads all produce `blank: false`, keeping the Session visible.
|
||||
|
||||
`updatedAt` is the later of `createdAt` and `lastPromptAt`. An eligible artifact read supplies exact `lastPromptAt` at no additional I/O cost; other cache misses or stale checkpoints order the Session too old rather than promoting it from an unrelated file write. After each asynchronous cold read, the gateway checks the live store again and replaces the cold result with an attached summary when another request resumed that Session meanwhile.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Trust cached `blank: true`.** Rejected because the projection cache deliberately permits a persisted log to advance beyond its checkpoint. A crash or fail-soft write failure after the first `turn/start` would hide a real conversation and could make the client reuse it as New Session.
|
||||
|
||||
**Read every cold log.** Rejected because list latency and I/O would scale with total stored conversation bytes. The physical-size eligibility check targets small historical artifacts that can be checked cheaply and degrades larger unknowns toward visibility. It intentionally does not add a persistence operation solely to make the threshold atomic with the read: concurrent growth may increase one probe's read cost, but the additional events can only preserve visibility or change a blank result to non-blank.
|
||||
|
||||
**Store blankness and recency in an authoritative persistence index.** Deferred because JSONL has an immutable first line and would require a second durable artifact with ordered updates, while SQLite would require a schema field. The broader exact-index design remains in the [last-activity proposal](../../proposed/architecture/2026-07-29-durable-last-activity-index.md).
|
||||
|
||||
**Continue ordering JSONL by mtime.** Rejected because mtime records every artifact write, including pickup boundaries, rather than the latest human prompt. Its error direction promotes untouched Sessions to the front.
|
||||
|
||||
## Consequences
|
||||
|
||||
Existing small blank JSONL artifacts are hidden without depending on projection-cache availability, and a stale cache cannot hide a stored `turn/start`. A cold list may read each artifact whose observed physical size is within the configured threshold when its cache does not already prove non-blank. The default threshold compares compressed bytes for the shipped Zstandard JSONL backend.
|
||||
|
||||
Blank artifacts above the threshold and blank Sessions on location-less backends remain visible. Missing or delayed recency cache entries for artifacts that are not read fall back to `createdAt`. These are conservative degradations: the UI may show an extra empty row or order a Session too low, but it does not hide a conversation or promote one because it was merely opened.
|
||||
|
||||
The gateway-owned projection is an effect of the gateway fiber; unloading the gateway removes the key. Unit coverage pins exact-threshold eligibility, stale-true rejection, monotonic false reuse, exact small-log recency, live-attachment races, fallback direction, human-prompt recency, and fiber disposal. A keyless Web snapshot boots the shipped compressed JSONL composition, seeds a small cold blank artifact without a cache row, and verifies that the sidebar omits it.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Agent Note: 有界验证冷空白会话
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-13-bounded-cold-blank-verification.md) | 中文
|
||||
|
||||
## Problem
|
||||
|
||||
Web 会话树会隐藏空白 Session,并把当前选中的空白项复用为 New Session。已附加 Session 可以从内存事件日志派生空白状态,但 `session.list` 通常不会加载每一份冷日志。把所有已物化的冷 Session 都视为非空,会暴露旧版本留下的空 Session;反过来,把 projection cache 中的 `blank: true` 当成当前事实,则可能在日志已经前进而 fail-soft cache 仍然陈旧时隐藏真实对话。
|
||||
|
||||
同一份冷列表还曾用 JSONL 工件的 mtime 作为 `updatedAt`。打开 Session 会追加 `session/end-seed`,因此即使没有真人 prompt,单纯拾起也会刷新 mtime,并把该 Session 提升到最近使用的对话之前。
|
||||
|
||||
## Decision
|
||||
|
||||
`dsh-host-apiproxy` 注册 `sessionListMetadata` 投影,其中包含 `blank` 与 `lastPromptAt`。已附加摘要直接用同一组函数折叠实时日志。`blank` 只在 `turn/start` 时从 true 单调变为 false;`lastPromptAt` 只在来源 kind 为 `user` 的 `user/message` 上更新。
|
||||
|
||||
冷摘要信任缓存的 `blank: false`,因为已包含 `turn/start` 的 checkpoint 前缀会始终保持非空。缓存的 `blank: true` 和 cache miss 都无法证明当前日志为空。当 persistence 通过 `locate()` 暴露物理工件,且其观测大小不超过 `coldBlankProbeMaxBytes` 资格阈值(默认每个 Session 1 KiB)时,网关调用 `readFrom(id, 0)`,从已存前缀折叠精确列表元数据。超过阈值的文件、不提供位置的后端、已消失的工件和读取失败都产生 `blank: false`,让 Session 保持可见。
|
||||
|
||||
`updatedAt` 取 `createdAt` 与 `lastPromptAt` 中较晚者。符合资格的工件读取无需额外 I/O 即可提供精确 `lastPromptAt`;其他 cache miss 或陈旧 checkpoint 只会让 Session 排得偏旧,而不会因无关的文件写入被提升。每次异步冷读取后,网关都会再次检查实时 store;若另一请求期间已恢复该 Session,则用已附加摘要替换冷结果。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**信任缓存的 `blank: true`。** 拒绝,因为 projection cache 有意允许持久日志前进到 checkpoint 之后。首个 `turn/start` 之后若发生崩溃或 fail-soft 写入失败,真实对话就会被隐藏,客户端还可能把它复用为 New Session。
|
||||
|
||||
**读取每一份冷日志。** 拒绝,因为列表延迟与 I/O 会随所有已存对话的总字节数增长。物理大小资格检查只针对能够低成本核验的小型历史工件,更大的未知项则向保持可见降级。该检查有意不为“让阈值与读取原子化”单独新增 persistence 操作:并发增长可能增加一次探测的读取成本,但新增事件只会保持可见,或把空白结果改为非空。
|
||||
|
||||
**把空白状态与最近时间存入权威 persistence index。** 暂缓,因为 JSONL 的首行不可变,需要增加带有顺序写入要求的第二份持久工件;SQLite 则需要 schema 字段。更广泛的精确索引设计仍由[最后活动提案](../../proposed/architecture/2026-07-29-durable-last-activity-index.md)负责。
|
||||
|
||||
**继续按 mtime 排序 JSONL。** 拒绝,因为 mtime 记录包括拾起边界在内的每一次工件写入,而非最近真人 prompt;其错误方向会把未经操作的 Session 提升到列表开头。
|
||||
|
||||
## Consequences
|
||||
|
||||
既有的小型空白 JSONL 工件无需依赖 projection cache 是否存在即可被隐藏,陈旧 cache 也无法隐藏已存的 `turn/start`。对于 cache 尚不能证明非空,且观测物理大小在配置阈值内的每个 Session,冷列表可能读取其工件。对默认交付的 Zstandard JSONL 后端,该阈值比较压缩后的字节数。
|
||||
|
||||
超过阈值的空白工件,以及来自不提供位置的后端的空白 Session 会保持可见。对于未被读取的工件,缺失或延迟的最近时间 cache 会回退到 `createdAt`。这些都是保守降级:UI 可能多显示一条空记录,或把 Session 排得偏低,但不会隐藏真实对话,也不会因为单纯打开而把会话提升到前面。
|
||||
|
||||
网关自有投影是网关 fiber 的 effect;卸载网关会移除该 key。单元覆盖固定了临界大小资格、拒绝陈旧 true、复用单调 false、小日志精确最近时间、实时附加竞态、回退方向、真人 prompt 最近时间和 fiber 销毁。无密钥 Web snapshot 会启动发行版的压缩 JSONL 组合,在没有 cache row 的情况下播种一份小型冷空白工件,并验证侧栏不展示它。
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-27-trajectory-inspection-ledger.md
|
||||
2026-07-27-trajectory-inspection-ledger.md: 74ed1f8ec6f6efcbf77e9caec7e254cb114efbd9
|
||||
2026-07-27-trajectory-inspection-ledger.zh.md: be648cb73478037979fd941753129b7c68be5085
|
||||
2026-07-27-trajectory-inspection-ledger.md: 7f97bc395ed694a0a750d3b744cc9887834ef32f
|
||||
2026-07-27-trajectory-inspection-ledger.zh.md: 34bb8741124c410fe06ec18bdde801caa987f4fb
|
||||
@@ -21,7 +21,7 @@ Trajectory has to make prose, machine payloads, token usage, timing, and nested
|
||||
- Call schemas come from the active recorded Request header. Keyless snapshot fixtures deliberately replace that catalog with the non-array `{{tools}}` token, which the durable inspection boundary treats as unavailable instead of attempting to project or fabricate schemas.
|
||||
- Selecting a record or Request opens an inspector inside Trajectory. Tabs and Summary sections follow the selected entity: Markdown messages expose rendered content, source fields, provider/model fields, and hierarchy views; tools add JSON payload/result and schema views; Requests add options, usage, timing, and result navigation. Scrollable Summary regions keep their scrollbar thumbs transparent until hover or `focus-within`, while retaining the scrollbar reservation and scroll behavior. Images render as media rather than serialized data.
|
||||
- Turn folding removes all rows after its first record and replaces them with a compact step/tool-call count; Assistant folding applies the same interaction to its tool-call descendants. Global controls fold or expand both levels.
|
||||
- A long ledger initially positions the loaded tail at the bottom and mounts only the viewport's row window plus bounded overscan. Request-only separators join the next measurable virtual item, with a terminal separator retaining its own fixed clearance, so the virtualizer never owns a zero-height item. Semantic DOM-safe row keys and ARIA indexes expose identity independently from mount position. A tail with known older history virtualizes immediately even when its loaded projection is below the ordinary row threshold. Stable-key virtualizer anchoring preserves the visible item across prepends and appends; the manual scroll-height fallback applies only when completing pagination disables virtualization. Selection, timeline focus, folding, search, and bottom following address records by stable event or tool-call identity rather than requiring their DOM rows to exist. An explicit loading row covers records until initial positioning finishes and while an older Session page is pending.
|
||||
- A long ledger initially positions the loaded tail at the bottom and mounts only the viewport's row window plus bounded overscan. Request-only separators join the next measurable virtual item, with a terminal separator retaining its own fixed clearance, so the virtualizer never owns a zero-height item. Semantic DOM-safe row keys and ARIA indexes expose identity independently from mount position. A tail with known older history virtualizes immediately even when its loaded projection is below the ordinary row threshold. Stable-key virtualizer anchoring preserves the visible item across prepends and appends; the manual scroll-height fallback applies only when completing pagination disables virtualization. Selection, timeline focus, folding, search, and bottom following address records by stable event or tool-call identity rather than requiring their DOM rows to exist. An explicit loading row covers records until initial positioning finishes. While an older Session prefix remains unloaded, an interactive first row precedes the loaded records and requests one older page; the same row becomes a disabled loading status for a pending page and disappears only when paging completes.
|
||||
- The separate Waterfall tab is removed. A fixed Overview above the ledger projects every loaded record with known `startedAt` onto three semantic timing lanes using its own duration. While an older prefix remains unloaded and the viewport includes the loaded domain's start, a neutral ellipsis control covers the truncated edge and loads one earlier page without assigning unknown history a fabricated duration; hovering that control suppresses the ordinary timeline cursor. Finalized Assistant spans divide the recorded interval at the first non-empty token delta, so distinct TTFT and decoding colors retain their actual ratio; incomplete timing falls back to one Assistant color. Hovering for 500 ms exposes exact start/end, total duration, TTFT, and decoding time without relying on the browser's native tooltip delay. Dragging left or right commits an inclusive interval filter: any record whose active interval overlaps either boundary remains visible, records without known timing leave the focused ledger, and clearing the selection restores the full loaded ledger. Wheel gestures zoom the time domain. A right-button click clears the interval selection; dragging instead pans an already zoomed viewport without mutating it. The Overview keeps the full time domain while focused so the selection can be resized or cleared without losing orientation.
|
||||
- Live history updates retain the ledger's bottom position only while the user is already following its tail. Scrolling upward clears that follow state, so streamed chunks and newly appended records do not interrupt inspection of earlier rows. Tail following and virtualizer measurement react to row keys and heights rather than content identity, so text-only stream frames neither discard the measurement cache nor repeat a DOM scroll write.
|
||||
- Token streaming updates only the matching Trajectory Assistant Context, while publication is coalesced to at most once per animation frame. The target snapshot preserves the existing stage, layout, Request numbering, Overview, and search inputs; completed Assistant State retains assembled blocks, timing, and usage rather than every raw chunk payload, while Session keeps the raw Event window.
|
||||
|
||||
@@ -21,7 +21,7 @@ Status: implemented
|
||||
- 调用 schema 来自当前生效且已记录的请求头。无密钥快照 fixture(测试前置数据)有意将该目录替换为非数组 token `{{tools}}`,持久化检查边界会将其视为不可用,而不是尝试投影或虚构 schema。
|
||||
- 选择记录或请求后,Trajectory 内部会打开检查器,其标签页和概述区域随实体类型变化:Markdown 消息提供渲染内容、来源字段、提供方/模型字段和层级视图;工具提供 JSON 载荷/结果和 schema 视图;请求提供选项、用量、计时和结果跳转。可滚动的概述区域默认保持滚动条滑块透明,直到悬停或 `focus-within` 时才显示,同时保留滚动条预留空间和滚动行为。图片以媒体形式渲染,而不是显示为序列化数据。
|
||||
- 折叠轮次时保留其第一条记录,并用紧凑的步骤数和工具调用数替换后续所有行;折叠助手时对其工具调用后代应用相同操作。全局控件会折叠或展开这两个层级。
|
||||
- 长记录表初始时将已加载尾部置于底部,只挂载视口对应的行窗口及有界的额外缓冲行。仅含请求的分隔行并入下一个具备可测高度的虚拟项,末尾分隔行则保留固定留白,因此虚拟化器不会管理零高度项。可安全用于 DOM 的语义行键与 ARIA 索引使标识不依赖挂载位置。只要已知尾部之前仍有更早历史,即使当前已加载投影低于常规行数阈值,也会立即启用虚拟化。基于稳定键的虚拟化器锚定会在向前补页和尾部追加时保留当前可见项;只有分页完成导致虚拟化停用时,才使用手动滚动高度兜底。选择、时间线聚焦、折叠、搜索和末尾跟随均按稳定的事件或工具调用标识定位,不要求对应 DOM 行已存在。初始定位完成前以及更早 Session 页面仍在等待时,明确的加载行会遮住真实记录。
|
||||
- 长记录表初始时将已加载尾部置于底部,只挂载视口对应的行窗口及有界的额外缓冲行。仅含请求的分隔行并入下一个具备可测高度的虚拟项,末尾分隔行则保留固定留白,因此虚拟化器不会管理零高度项。可安全用于 DOM 的语义行键与 ARIA 索引使标识不依赖挂载位置。只要已知尾部之前仍有更早历史,即使当前已加载投影低于常规行数阈值,也会立即启用虚拟化。基于稳定键的虚拟化器锚定会在向前补页和尾部追加时保留当前可见项;只有分页完成导致虚拟化停用时,才使用手动滚动高度兜底。选择、时间线聚焦、折叠、搜索和末尾跟随均按稳定的事件或工具调用标识定位,不要求对应 DOM 行已存在。初始定位完成前,明确的加载行会遮住真实记录。更早的 Session 前缀仍未加载时,交互式首行位于已加载记录之前,可请求一页更早历史;页面加载期间,同一行会变为禁用的加载状态,仅在分页完成时消失。
|
||||
- 移除独立的 waterfall(瀑布式事件)标签页。固定在记录表上方的 Overview 区域将所有 `startedAt` 已知的已加载记录按各自耗时投影到三条语义计时轨道。仍有更早前缀尚未加载且 viewport 包含已加载时间域起点时,中性的省略号控件会遮住截断边缘并加载一页更早历史,而不会为未知历史虚构耗时;悬停在该控件上会隐藏普通的时间线光标。已完成的助手时间条以首个非空 token 增量为分界,用不同颜色按真实比例表示 TTFT 与解码时间;计时不完整时退化为单一助手色。悬停 500 ms 后会显示精确起止时刻、总耗时、TTFT 和解码时间,而不依赖浏览器原生 tooltip 的延迟。向左或向右拖动会提交包含边界的区间筛选:任何活动区间与所选区间任一边界重叠的记录都会保留,计时未知的记录会从聚焦后的记录表中移除,清除选择则恢复完整的已加载记录表。滚轮手势用于缩放时间域。右键单击会清除区间选择;右键拖动则只会平移已放大的 viewport,不会改变该选区。聚焦后,Overview 区域仍保留完整时间范围,以便在不失去方位的情况下调整或清除选择。
|
||||
- 实时历史更新仅在用户已经跟随记录表末尾时保留底部位置。向上滚动会清除跟随状态,因此流式分块和新追加的记录不会打断对旧记录的检查。末尾跟随与虚拟化器测量仅响应行键和高度,而非内容标识,因此仅含文本的流式帧既不会丢弃测量缓存,也不会重复执行 DOM 滚动写入。
|
||||
- token 流式输出只更新命中的 Trajectory Assistant Context,发布则合并为每个 animation frame 最多一次。target snapshot 继续提供既有 stage、layout、请求编号、Overview 与搜索输入;已完成的 Assistant State 只保留组装后的 blocks、计时与 usage,不保留每条原始 chunk payload,而 Session 继续保存原始 Event 窗口。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-10-npm-release-sequences.md
|
||||
2026-08-10-npm-release-sequences.md: e8138aef923e201cc0883232f48ce6921452ca00
|
||||
2026-08-10-npm-release-sequences.zh.md: 7ce9fa01dbe10cbdae5585f64392d0ca6a9fb868
|
||||
2026-08-10-npm-release-sequences.md: e74a4ac8f2aadd8665ec0db198c6a317a0c201bc
|
||||
2026-08-10-npm-release-sequences.zh.md: e152163976f945224f2524fccd7f831ba98e8161
|
||||
@@ -70,6 +70,10 @@ Publication runs only from GitHub Actions; there is no local publication path. P
|
||||
|
||||
The third state catches code that changed without a version bump. The first two provide idempotence — re-running publish over one artifact republishes nothing and needs no manual selection of packages. The same rule resolves the tension between one vendor release carrying several tags and a workflow that can only run from one ref: the workflow never infers which packages to publish from the tag it ran from.
|
||||
|
||||
All three sequences decide this way, including the native one: it publishes through its own script rather than a shell loop, because a loop of bare `npm publish` calls cannot be retried — the registry answers a repeat of an existing version permanently, so one failure partway through left no way forward.
|
||||
|
||||
Two registry behaviours shape how a publish is attempted. Writes are spaced by at least two seconds and retried with a backoff, because publishing several packages back to back outruns the registry's own processing and earns `E409 Failed to save packument`. And every retry re-reads the registry first: a reported failure can answer a write that landed anyway, so a version that now exists with this tarball's integrity counts as published rather than as a version to place again.
|
||||
|
||||
### Workspace-internal references use the `workspace:` protocol
|
||||
|
||||
Every reference to a workspace member uses `workspace:^`, so `pnpm pack` substitutes a range matching the target version: sibling `peerDependencies` follow the family version, and a reference to a vendored package follows that package's own line. The Landlock platform packages keep `workspace:*`, which publishes the exact version, because a platform package and its entry must agree exactly.
|
||||
|
||||
@@ -70,6 +70,10 @@ tag 只是 commit 指针,不是发布成功的证明。bump 会向 registry
|
||||
|
||||
第三态拦住「改了代码却没 bump 版本」。前两态给出幂等——同一个 artifact 重跑 publish 不会重复发布,也不需要人工挑拣包。同一条规则还解决了「一次 vendor 发布携带多个 tag,而 workflow 只能从一个 ref 触发」的矛盾:workflow 从不从触发它的 tag 去推断该发哪些包。
|
||||
|
||||
三条序列都按这套判定,native 也在内:它通过自己的脚本发布,而不是 shell 循环——一串裸 `npm publish` 无法重试,registry 对「重发已存在的版本」的回答是永久失败,因此中途失败一次就没有前路了。
|
||||
|
||||
registry 的两个行为决定了「怎么尝试一次发布」。写入之间至少间隔两秒并带退避重试,因为连续背靠背发多个包会超出 registry 自身的处理速度,换来 `E409 Failed to save packument`。而每次重试都先重查 registry:报出来的失败可能对应一次其实已经落地的写入,所以「该版本现在存在且 integrity 与本 tarball 相同」算作已发布,而不是又一个待放置的版本。
|
||||
|
||||
### workspace 内部引用走 `workspace:` 协议
|
||||
|
||||
所有指向 workspace 成员的引用都用 `workspace:^`,由 `pnpm pack` 替换成匹配目标版本的范围:兄弟包的 `peerDependencies` 跟随族版本,指向 vendored 包的引用跟随那个包自己的版本线。Landlock 平台包保留 `workspace:*`(发布成精确版本),因为平台包与它的入口必须版本完全一致。
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-13-published-document-fragments.md
|
||||
2026-08-13-published-document-fragments.md: 4146a592a97b5d8b4e1d3fbabd0f035074cc8001
|
||||
2026-08-13-published-document-fragments.zh.md: 6cf76dfa349bbd61d1dd51cb683b696e4c405435
|
||||
@@ -0,0 +1,27 @@
|
||||
# Agent Note: Validate published document fragments
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-08-13-published-document-fragments.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
`verify-md-links` validates fragments with GitHub's Markdown heading ids, while the documentation website renders headings with VitePress. Punctuation-heavy headings and translated headings can therefore pass source validation but produce links to ids absent from the published HTML. A successful VitePress build validates target pages, not fragment ids.
|
||||
|
||||
## Decision
|
||||
|
||||
`docs:build` and its MPA variant run `verify-doc-site-fragments` after VitePress emits `website/.dist`. The verifier parses every emitted HTML page, resolves each internal fragment link against VitePress clean URLs, and fails when the output is absent, routes are ambiguous, an href is malformed, or either the target page or requested id is missing. Unit tests cover those failures plus clean URLs, `.html` aliases, same-page links, encoded and literal ids, and external-link exclusion.
|
||||
|
||||
Any fragment target heading whose GitHub id differs from its VitePress id carries an explicit GitHub-compatible alias. Authored English and translated pages place the alias before the heading; translated pages use the English id shared by the bilingual pair. Generated config, tool, and persistence catalogs emit the alias from their owning generator. Source Markdown validation remains independent and continues to reject links that do not resolve under repository rendering.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Use locale-specific fragments.** Bilingual pairs intentionally preserve identical link targets. Locale-specific fragments would make the two sources disagree and would require every link producer to know the target locale's translated heading.
|
||||
|
||||
**Rely on VitePress heading ids.** Those ids depend on rendered punctuation and localized heading text. They do not preserve the GitHub ids already used by repository links and generated references.
|
||||
|
||||
**Check source Markdown only.** This leaves the published artifact unverified and cannot detect differences between the GitHub and VitePress slug algorithms.
|
||||
|
||||
## Consequences
|
||||
|
||||
Every production documentation build reads its emitted HTML once, adding a bounded post-build check to the existing site build. Cross-page fragment links now require an id that survives publication. Explicit aliases become part of the published reference and let headings change language or punctuation without invalidating established fragments.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Agent Note: 校验已发布文档的 fragment
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-08-13-published-document-fragments.md) | 中文
|
||||
|
||||
## Problem
|
||||
|
||||
`verify-md-links` 使用 GitHub 的 Markdown 标题 id 校验 fragment,而文档网站使用 VitePress 渲染标题。包含较多标点的标题与翻译后的标题可能通过源码校验,却在已发布 HTML 中没有对应 id。VitePress 构建成功只会校验目标页面,不会校验 fragment id。
|
||||
|
||||
## Decision
|
||||
|
||||
`docs:build` 及其 MPA 变体会在 VitePress 生成 `website/.dist` 后运行 `verify-doc-site-fragments`。该校验器解析每个生成的 HTML 页面,按照 VitePress clean URL 解析每个内部 fragment 链接,并在构建产物不存在、路由有歧义、href 格式错误、目标页面不存在或请求的 id 缺失时失败。单元测试覆盖这些失败,以及 clean URL、`.html` 别名、同页链接、编码和字面 id 与外部链接排除。
|
||||
|
||||
任何 GitHub id 与 VitePress id 不同的 fragment 目标标题都会带有与 GitHub 兼容的显式别名。英文手写页面和翻译页面会在标题前添加别名;翻译页面使用双语对侧文件共享的英文 id。生成的配置、工具和持久化目录由所属生成器输出别名。源码 Markdown 校验保持独立,仍会拒绝在仓库渲染规则下无法解析的链接。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**使用各语言专属的 fragment。** 双语对侧文件会刻意保留相同的链接目标。语言专属 fragment 会使两侧源码不一致,还会要求每个链接生成方都了解目标语言翻译后的标题。
|
||||
|
||||
**依赖 VitePress 标题 id。** 这些 id 取决于渲染后的标点与本地化标题文本,无法保留仓库链接和生成引用已经使用的 GitHub id。
|
||||
|
||||
**只检查 Markdown 源码。** 这种做法不会校验发布产物,也无法发现 GitHub 与 VitePress slug 算法之间的差异。
|
||||
|
||||
## Consequences
|
||||
|
||||
每次生产文档构建都会读取一次生成的 HTML,在现有网站构建后增加一个有界检查。跨页面 fragment 链接必须指向发布后仍存在的 id。显式别名成为已发布参考的一部分,使标题更换语言或标点后仍能保留既有 fragment。
|
||||
+2
-2
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/proposed/architecture/2026-07-29-durable-last-activity-index.md
|
||||
2026-07-29-durable-last-activity-index.md: 0e441f54a719b29a1a450c133e08cdf7d2c82e9e
|
||||
2026-07-29-durable-last-activity-index.zh.md: ebc2e2167d7743eafc5a4600fe9a0f687349e1a3
|
||||
2026-07-29-durable-last-activity-index.md: 99e50dd40b789db5d896cb7f9e25fa8893b02ae2
|
||||
2026-07-29-durable-last-activity-index.zh.md: e317fb192d53353295e6b52f631707ba6b400b66
|
||||
@@ -6,17 +6,17 @@ English | [中文](2026-07-29-durable-last-activity-index.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
A cold (persisted, unattached) session has no stored answer to "when was this last worked in". `dsh-host-apiproxy`'s `summarizeCold()` therefore approximates it with the log file's mtime where one exists — `locate()` resolves a per-session artifact for JSONL and `undefined` for SQLite, whose cold sessions fall back to `createdAt` — and the web client sorts its session tree by the resulting `updatedAt`. The two backends are wrong in opposite directions: JSONL reads too new, SQLite too old.
|
||||
A cold (persisted, unattached) session has no authoritative stored answer to "when did the user last prompt here". `dsh-host-apiproxy` serves `updatedAt` from the optional projection cache's `lastPromptAt`, falling back to `createdAt`, and the Web client sorts its Session tree by that value. The cache is fail-soft and checkpointed asynchronously, so a missing or delayed row makes a recently prompted Session sort too old.
|
||||
|
||||
mtime answers a different question: when the artifact was last written. Every durable write refreshes it, including writes that are not activity — a truncate-repair of a torn tail, the synthetic closers that balance an interrupted turn, and the [`session/end-seed` boundary](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md) a seeded session appends. (A `flush` with nothing pending is not among them: the coordinator returns without reaching the backend.) The visible consequence is stable and wrong in one direction: a session touched without being worked in promotes itself above sessions the user actually worked in afterwards, and each touch re-promotes it. `dsh-host-apiproxy` keeps `session.history` inspection-only, but any Agent-bound ordinary-session control resumes through `agentFor()` and is enough to promote the cold artifact.
|
||||
The gateway previously used JSONL artifact mtime when available. mtime answers a different question: when the artifact was last written. Every durable write refreshes it, including a truncate-repair of a torn tail, synthetic closers that balance an interrupted turn, and the [`session/end-seed` boundary](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md) appended during pickup. That approximation promoted a Session merely because it was opened. The [bounded cold blank verification](../../implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md) removed mtime ordering and accepted the cache's conservative "too old" failure direction as an interim tradeoff.
|
||||
|
||||
The attached projection has a real fix — `lastActivityTime()` skips boundaries — but it needs the event log, and the cold path deliberately does not read one. Reading the log to compute `updatedAt` would defeat the header-only listing that keeps `list()` scaling with session count rather than log size.
|
||||
An attached summary can fold the live event log and select the latest human-authored `user/message`, but the cold path deliberately does not read large logs. Reading every log to compute `updatedAt` would make `list()` scale with total conversation bytes rather than Session count. The 1 KiB cold read used for metadata verification makes eligible small-artifact recency exact, but it does not make large-log ordering exact.
|
||||
|
||||
The [boundary change](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md) raised the frequency of this defect, because a pickup now writes where nothing was written before; `dsh-host-apiproxy`'s README records it under Known Limitations. It did not introduce the approximation, and removing the approximation is a durable-format decision, which is why it is scoped here rather than there.
|
||||
Making cold ordering exact remains a durable-format decision, which is why it is scoped here rather than in the gateway workaround.
|
||||
|
||||
## Proposal
|
||||
|
||||
Store last-activity time where a listing already reads — the session index — so `summarizeCold()` can serve it without opening the log. The coordinator computes the value, because it sees every append and already owns per-id state; backends persist it. That makes it a new `PersistenceBackend` contract element rather than backend-local bookkeeping, and keeps one definition of "activity" shared with the in-log `lastActivityTime()`.
|
||||
Store the latest human-prompt time where a listing already reads — the Session index — so `summarizeCold()` can serve it without opening the log or depending on a cache checkpoint. The coordinator computes the value because it sees every append and already owns per-id state; backends persist it. That makes it a new `PersistenceBackend` contract element rather than backend-local bookkeeping, with the same event predicate as the attached projection: `user/message` whose `source.kind` is `user`.
|
||||
|
||||
The two shipped backends have opposite constraints, and the proposal is deliberately asymmetric about them:
|
||||
|
||||
@@ -25,7 +25,7 @@ The two shipped backends have opposite constraints, and the proposal is delibera
|
||||
|
||||
Three questions must be answered before implementation, and none of them is settled here:
|
||||
|
||||
**Which events count as activity?** `lastActivityTime()` answers this for the log by excluding `session/end-seed`. A stored field encodes the rule at write time, where the writer sees one batch rather than the whole log. The two must not drift, or the attached and cold surfaces will disagree about the same session.
|
||||
**How is the shared predicate owned?** A stored field encodes the rule at write time, where the writer sees one batch, while the attached summary folds a whole log. Both must use one exported event predicate or reducer so new message-source variants cannot make attached and cold ordering disagree.
|
||||
|
||||
**How do pre-field logs behave?** Existing artifacts have no value. Falling back to mtime keeps them at today's accuracy; falling back to `createdAt` is honest but reorders every existing session in the picker and the tree.
|
||||
|
||||
@@ -39,28 +39,29 @@ Three questions must be answered before implementation, and none of them is sett
|
||||
|
||||
**Write the boundary only when repair occurred.** Would reduce the frequency, and the [boundary note](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md) already rejected it: the predicate must hold for an orderly restart too. Trading a correctness invariant for timestamp accuracy is the wrong direction.
|
||||
|
||||
**Derive activity from a projection cache.** `session-projection-cache` already folds tails past a watermark, so a last-activity unit would ride existing machinery. Rejected as the primary shape because the cache is an optional composition entry; a listing served only when a cache plugin is mounted makes ordering depend on composition.
|
||||
**Derive activity from a projection cache.** This is the current interim implementation. `session-projection-cache` folds tails past a watermark without changing the persistence format, but it is optional and fail-soft. Its absence or checkpoint delay makes ordering depend on cache availability and freshness, so it cannot provide the authoritative value proposed here.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `SessionSummary.updatedAt` for a cold session equals the same value the attached projection reports for that session, verified by resuming, quitting without a turn, and asserting the order is unchanged across both paths.
|
||||
- A resumed-then-abandoned session does not sort above a session worked in afterwards, in the web session tree and the TUI resume picker, pinned by an assembled snapshot rather than unit tests alone.
|
||||
- The activity rule has one definition: a test proves the stored field and `lastActivityTime()` agree over a log containing boundaries, closers, and a plain turn.
|
||||
- The prompt-time rule has one definition: a test proves the stored field and attached fold agree over a log containing human prompts, injected user messages, boundaries, and closers.
|
||||
- Pre-field artifacts load and list without error under the chosen fallback, with the fallback's ordering consequence asserted.
|
||||
- SQLite's `SCHEMA_VERSION` bump rejects the old on-disk version per the repo's no-migration stance.
|
||||
|
||||
## Risks
|
||||
|
||||
**Two definitions of activity drift.** The stored field is computed per batch, the projection over a whole log. A new event type classified one way at write time and the other at read time yields a session whose cold and attached orderings disagree — a bug that only appears after a restart, which is where it is hardest to notice.
|
||||
**Two definitions of prompt time drift.** The stored field is computed per batch, the projection over a whole log. A new message source classified one way at write time and the other at read time yields a Session whose cold and attached orderings disagree — a bug that only appears after restart.
|
||||
|
||||
**A JSONL sidecar can disagree with its log.** A crash between the log append and the sidecar write leaves a stale value with no torn-tail marker to repair it. Every consumer would need to treat the sidecar as a hint, which is close to what mtime already is.
|
||||
|
||||
**The fallback reorders existing sessions.** Whichever fallback is chosen, users with existing logs see their picker and tree reorder once on upgrade. `createdAt` makes that reordering large.
|
||||
|
||||
**Cost may exceed the defect.** The defect is a misordering of abandoned sessions. If the honest answer for JSONL is "keep the approximation", this note's outcome may be documenting that decision rather than implementing a field — and that is an acceptable outcome.
|
||||
**Cost may exceed the defect.** The remaining defect is conservative misordering when projection metadata is missing or delayed. If the honest answer for JSONL is "keep the cache fallback", this note's outcome may be documenting that decision rather than implementing a field.
|
||||
|
||||
## Related
|
||||
|
||||
- [The end-seed log boundary](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md) — one of the non-activity writes mtime counts; `dsh-session` owns `lastActivityTime()`, the in-log projection a stored field must agree with.
|
||||
- [Bounded cold blank verification](../../implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md) — removes mtime ordering, defines the interim projection-cache fallback, and limits direct cold reads to small-artifact metadata verification.
|
||||
- [The end-seed log boundary](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md) — one of the non-prompt writes that made mtime unsuitable.
|
||||
- [Session persistence](../../implemented/architecture/2026-06-14-session-persistence.md) — the append-only and never-rewrite invariants that rule out a mutable JSONL header field.
|
||||
- [Shared persistence write coordinator](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md) — the append path a stored field would hook into.
|
||||
@@ -6,17 +6,17 @@ Status: proposed
|
||||
|
||||
## 问题
|
||||
|
||||
一个冷会话(已持久化、未附加)对「上次是什么时候在这里面工作过」没有任何已存储的答案。因此 `dsh-host-apiproxy` 的 `summarizeCold()` 在存在日志文件时用它的 mtime 来近似它——`locate()` 为 JSONL 解析出一个逐会话产物,为 SQLite 解析出 `undefined`,而 SQLite 的冷会话会回退到 `createdAt`——而 web 客户端就按由此得到的 `updatedAt` 为自己的会话树排序。这两个后端错的方向正好相反:JSONL 读出来偏新,SQLite 偏旧。
|
||||
一个冷会话(已持久化、未附加)对「用户上次是什么时候在这里发出 prompt」没有权威的已存储答案。`dsh-host-apiproxy` 从可选 projection cache 的 `lastPromptAt` 提供 `updatedAt`,缺失时回退到 `createdAt`,Web 客户端按该值为 Session 树排序。cache 采用 fail-soft 并异步写入 checkpoint,因此缺失或延迟的记录会让最近收到 prompt 的 Session 排得过旧。
|
||||
|
||||
mtime 回答的是另一个问题:这份产物上次是什么时候被写入的。每一次持久写入都会刷新它,包括那些并不是活动的写入:一次对撕裂尾部的截断修复、用来平衡被中断的轮次的那些合成 closer,以及带种子的会话会追加的 [`session/end-seed` 边界](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md)。(没有待处理内容的 `flush` 不在其中:协调器在到达后端之前就返回了。)用户可见的后果是稳定的,而且只朝一个方向错:一个被触碰过却没有在里面工作过的会话,会把自己排到用户此后真正工作过的那些会话之前,而且每次触碰都会重新把它排上去一次。`dsh-host-apiproxy` 让 `session.history` 保持只执行检查,但任何绑定到 Agent 的普通会话控件都会通过 `agentFor()` 恢复会话,足以把冷态产物排到前面。
|
||||
网关以前会在可用时采用 JSONL 产物的 mtime。mtime 回答的是另一件事:这份产物上次是什么时候被写入。每一次持久写入都会刷新它,包括对撕裂尾部的截断修复、平衡中断轮次的合成 closer,以及拾起时追加的 [`session/end-seed` 边界](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md)。这套近似会让 Session 仅仅因为被打开就提升排序。[有界冷空白验证](../../implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md)移除了 mtime 排序,并把 cache 保守的「过旧」错误方向作为现阶段取舍。
|
||||
|
||||
已附加会话的那个投影有真正的修复办法(`lastActivityTime()` 会跳过边界),但它需要事件日志,而冷路径有意不去读日志。为计算 `updatedAt` 而读取日志,会让只读 header 的列举失去意义,而正是它让 `list()` 的开销随会话数量而非日志体量增长。
|
||||
已附加摘要可以折叠实时事件日志并选择最新的真人 `user/message`,但冷路径有意不读取大日志。为计算 `updatedAt` 而读取每一份日志,会让 `list()` 的开销随对话总字节数而非 Session 数量增长。用于 metadata 验证的 1 KiB 冷读取可以让符合条件的小产物得到精确的最近时间,但不能让大日志的排序精确。
|
||||
|
||||
[边界那次变更](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md)提高了这个缺陷的出现频率,因为一次拾起如今会在此前完全无写入的路径上产生写入;`dsh-host-apiproxy` 的 README 已在 Known Limitations 中记录该项。它并没有引入这套近似做法,而移除这套近似是一项持久格式决策,因此它的范围划在本文,而不是那里。
|
||||
让冷排序变得精确仍是一项持久格式决策,因此其范围留在本文,而不是网关 workaround 中。
|
||||
|
||||
## 提案
|
||||
|
||||
把最后活动时间存到列举本就会读取的地方,也就是会话索引,这样 `summarizeCold()` 无需打开日志就能给出答案。该值由协调器计算,因为它看得到每一次追加,而且本就拥有每 id 状态;由后端负责持久化。这样它就成为 `PersistenceBackend` 约定中新增的一个要素,而不是各后端本地的账目,同时让「活动」只保留一个定义,与日志内的 `lastActivityTime()` 共用。
|
||||
把最新真人 prompt 时间存到列举本就会读取的 Session 索引,这样 `summarizeCold()` 无需打开日志或依赖 cache checkpoint 就能给出答案。该值由协调器计算,因为它看得到每一次追加,而且本就拥有每 id 状态;由后端负责持久化。这样它就成为 `PersistenceBackend` 约定中新增的一个要素,而不是各后端本地账目,并与已附加投影使用同一个事件谓词:`source.kind` 为 `user` 的 `user/message`。
|
||||
|
||||
两个已交付的后端受到的约束正好相反,本提案对它们有意采取不对称的处理:
|
||||
|
||||
@@ -25,7 +25,7 @@ mtime 回答的是另一个问题:这份产物上次是什么时候被写入
|
||||
|
||||
实现之前必须回答三个问题,本文对它们都没有定论:
|
||||
|
||||
**哪些事件算作活动?** 对日志而言,`lastActivityTime()` 通过排除 `session/end-seed` 回答了这个问题。一个已存储字段是在写入时编码这条规则的,而写入方在那里只看到一个批次,不是整份日志。两者不得发生漂移,否则已附加表层与冷表层会对同一个会话给出彼此矛盾的答案。
|
||||
**共享谓词由谁拥有?** 已存储字段在写入时编码规则,写入方只看到一个批次,而已附加摘要折叠整份日志。两者必须使用同一个导出的事件谓词或 reducer,避免新的消息来源变体让已附加排序与冷排序发生分歧。
|
||||
|
||||
**该字段引入之前的日志表现如何?** 既有产物里没有这个值。回退到 mtime 能让它们保持今天的准确度;回退到 `createdAt` 是诚实的,但会把选择器和会话树里每一个既有会话都重新排一次序。
|
||||
|
||||
@@ -39,28 +39,29 @@ mtime 回答的是另一个问题:这份产物上次是什么时候被写入
|
||||
|
||||
**仅在确实发生了修复时才写入边界。** 这能降低出现频率,而[边界 Agent Note](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md)已经否决过它:谓词对有序重启同样必须成立。用一条正确性不变式去换时间戳的准确度,方向是错的。
|
||||
|
||||
**从投影缓存派生活动时间。** `session-projection-cache` 本就会折叠水位线之后的尾部,因此一个最后活动单元可以搭乘既有机制。它作为主形态被否决,因为该缓存是一个可选的组合项;只有挂载了缓存插件才提供的列举,会让排序取决于如何组合。
|
||||
**从投影缓存派生活动时间。** 这是当前的过渡实现。`session-projection-cache` 会折叠水位线之后的尾部,无需改变持久格式,但它是可选且 fail-soft 的。缺失或 checkpoint 延迟会让排序取决于 cache 是否存在以及是否新鲜,因此无法提供本文所提议的权威值。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 冷会话的 `SessionSummary.updatedAt` 等于已附加会话的投影为同一个会话报告的那个值;验证方式是恢复、不跑轮次就退出,并断言两条路径上的顺序都没有变化。
|
||||
- 在 web 会话树和 TUI 恢复选择器中,一个恢复后即被弃置的会话不会排到此后工作过的会话之前;由一份组装后的快照钉住,而不是只靠单元测试。
|
||||
- 活动规则只有一个定义:一个测试证明,在一份同时包含边界、closer 和一个普通轮次的日志上,已存储字段与 `lastActivityTime()` 的结果一致。
|
||||
- prompt 时间规则只有一个定义:一个测试证明,在包含真人 prompt、注入式 user message、边界和 closer 的日志上,已存储字段与已附加折叠结果一致。
|
||||
- 在选定的回退方案下,该字段引入之前的产物能够无错误地加载和列举,并且该回退在排序上的后果有断言覆盖。
|
||||
- 按本仓库不做迁移的立场,SQLite 的 `SCHEMA_VERSION` 递增会拒绝旧的磁盘版本。
|
||||
|
||||
## 风险
|
||||
|
||||
**「活动」的两个定义发生漂移。** 已存储字段按批次计算,而投影在整份日志上计算。一种新事件类型若在写入时按一种方式归类、在读取时按另一种方式归类,就会产生一个冷排序与已附加排序彼此矛盾的会话;这个缺陷只在重启之后才显现,而那正是最难被注意到的地方。
|
||||
**prompt 时间的两个定义发生漂移。** 已存储字段按批次计算,而投影在整份日志上计算。一种新消息来源若在写入时按一种方式归类、在读取时按另一种方式归类,就会产生冷排序与已附加排序彼此矛盾的 Session;该缺陷只会在重启后显现。
|
||||
|
||||
**JSONL 的伴随文件可能与它的日志不一致。** 在日志追加与伴随文件写入之间发生崩溃,会留下一个陈旧的值,而且没有撕裂尾部标记可用来修复它。每个消费方都得把伴随文件当作一条提示来对待,而这与 mtime 今天的地位已经很接近了。
|
||||
|
||||
**回退方案会让既有会话重新排序。** 无论选定哪种回退,持有既有日志的用户都会在升级时看到自己的选择器和会话树重新排一次序。选 `createdAt` 会让这次重排的幅度很大。
|
||||
|
||||
**代价可能超过这个缺陷本身。** 该缺陷是被弃置会话的排序出错。如果对 JSONL 来说诚实的答案是「保留这套近似」,那么本文的结局可能是记录下这个决定,而不是实现一个字段,而这也是一个可以接受的结局。
|
||||
**代价可能超过这个缺陷本身。** 剩余缺陷是 projection metadata 缺失或延迟时的保守错序。如果对 JSONL 来说诚实的答案是「保留 cache 回退」,那么本文的结局可能是记录该决定,而不是实现一个字段。
|
||||
|
||||
## 相关
|
||||
|
||||
- [种子结束日志边界](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md)——mtime 会计入的非活动写入之一;`dsh-session` 拥有 `lastActivityTime()`,也就是一个已存储字段必须与之保持一致的那个日志内投影。
|
||||
- [有界冷空白验证](../../implemented/bug-fix/2026-08-13-bounded-cold-blank-verification.md)——移除 mtime 排序,定义 projection cache 的过渡回退,并把直接冷读取限制为小产物 metadata 验证。
|
||||
- [种子结束日志边界](../../implemented/architecture/2026-07-30-session-end-seed-log-boundary.md)——让 mtime 不适用的非 prompt 写入之一。
|
||||
- [会话持久化](../../implemented/architecture/2026-06-14-session-persistence.md)——仅追加与绝不重写这两条不变式,正是它们排除了可变的 JSONL header 字段。
|
||||
- [共享持久化写入协调器](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md)——一个已存储字段将挂入的那条追加路径。
|
||||
@@ -49,6 +49,7 @@ Write normal repository-relative Markdown links in canonical docs. The projector
|
||||
- An image is the exception: its file is copied into the generated tree and referenced from there, so the site serves it regardless of repository visibility. It must be a regular file inside the repository.
|
||||
- External URLs, site-absolute URLs, email links, and fragment-only links remain unchanged.
|
||||
- A missing repository-relative target fails projection instead of silently producing a broken link.
|
||||
- Cross-page fragments use the English GitHub heading id as their canonical id. If an authored heading emits a different VitePress id, place an explicit `<a id="..."></a>` immediately before it; add generated aliases in the owning generator.
|
||||
|
||||
Do not write website-specific routes into canonical Markdown just to satisfy VitePress. Use `sourceAliases` for directory-style repository links that should resolve to a mapped index page.
|
||||
|
||||
@@ -68,6 +69,8 @@ Run the focused website gate before treating the mapping as valid:
|
||||
pnpm docs:check
|
||||
```
|
||||
|
||||
If Markdown link checks pass but the site build reports a missing fragment, follow the `verify-doc-site-fragments` source and target paths. Preserve the English GitHub id with an explicit alias in authored Markdown or in the owning generator.
|
||||
|
||||
Before committing a documentation-site change, run:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -147,6 +147,12 @@ jobs:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
# The publish script is the only repository file this job needs, and it
|
||||
# imports nothing outside Node's builtins, so there is no install step.
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
@@ -167,12 +173,8 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Publish tarballs
|
||||
run: |
|
||||
version="${GITHUB_REF#refs/tags/landlock-run-v}"
|
||||
tag_args=()
|
||||
case "$version" in *-*) tag_args=(--tag next);; esac
|
||||
while IFS= read -r tarball; do
|
||||
# No --access: publishConfig.access in each manifest decides, and a
|
||||
# command-line flag would override it.
|
||||
npm publish "dist/npm/${tarball}" "${tag_args[@]}"
|
||||
done < dist/npm/publish-order.txt
|
||||
# Publication is decided per package against the registry, so re-running
|
||||
# this job over the same artifact skips what already landed instead of
|
||||
# failing on it. A bare `npm publish` loop could not be retried: the
|
||||
# registry answers a repeat of an existing version permanently.
|
||||
run: node ./scripts/publish-release.mjs dist/npm
|
||||
+2
-2
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write README.md
|
||||
README.md: 646262f0b8317a48cab9aa84bab87b7a2b8e85ec
|
||||
README.zh.md: 892da6f48cd8b60dd61332ec412f604a8062b27d
|
||||
README.md: 098b514f8311de092bab18bdd560722b1e485913
|
||||
README.zh.md: 639d519b6202ffe740d46e462feec2657d7e13ad
|
||||
@@ -38,6 +38,7 @@ pnpm dsh web
|
||||
|
||||
- Feel free to submit feedback or bug reports through [GitHub Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions).
|
||||
- Add the [`dsh-plugin`](https://github.com/topics/dsh-plugin) topic to your plugin repository for discoverability.
|
||||
- Join <a href="https://discord.gg/Ycq5dCaS4">DeepSeek Harness Discord community</a>.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
+19
-1
@@ -37,7 +37,25 @@ pnpm dsh web
|
||||
## 社区与支持
|
||||
|
||||
- 欢迎通过 [GitHub Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions) 提交反馈或 bug 报告。
|
||||
- 为你的插件仓库添加 [`dsh-plugin`](https://github.com/topics/dsh-plugin) 主题,便于被发现。
|
||||
- 为你的插件仓库添加 [`dsh-plugin`](https://github.com/topics/dsh-plugin) 话题,便于被发现。
|
||||
- 欢迎加入 DeepSeek Harness 企微群:扫码添加企微小助手并填写入群问卷,完成后小助手会邀请你入群。
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="center">企微小助手</th>
|
||||
<th align="center">入群问卷</th>
|
||||
<th align="center">微信公众号</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center"><img src="assets/community-wecom-assistant.png" alt="DeepSeek Harness 企微小助手二维码" width="180" height="180"></td>
|
||||
<td align="center"><a href="https://trtgsjkv6r.feishu.cn/share/base/form/shrcnIt5twSVdLGD52KJBckGCgg"><img src="assets/community-wecom-survey.png" alt="DeepSeek Harness 入群问卷二维码" width="180" height="180"></a></td>
|
||||
<td align="center"><img src="assets/community-wechat-official-account.png" alt="DeepSeek Harness 团队微信公众号二维码" width="180" height="180"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## 参与贡献
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/** Cold Session list visibility through the shipped compressed JSONL backend. */
|
||||
|
||||
import { mkdir, stat } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join } from 'node:path'
|
||||
import type { Browser, Page } from 'playwright'
|
||||
import { chromium } from 'playwright'
|
||||
import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest'
|
||||
import {
|
||||
captureStableAria, compareOrRefreshGolden, launchWebScaffold, seedBlankSession,
|
||||
watchConsole, webSnapshotMode, type WebScaffold,
|
||||
} from './scaffold.ts'
|
||||
import { newEnglishPage, saveFailureShot } from './support.ts'
|
||||
|
||||
const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/cold-blank-session', import.meta.url))
|
||||
const SIDEBAR_EXPECTED = join(SNAPSHOT_DIR, 'sidebar.expected.md')
|
||||
const MODE = webSnapshotMode()
|
||||
const SESSION_ID = 'cold-blank-session-web-e2e'
|
||||
const WORKSPACE_NAME = 'cold-blank-workspace'
|
||||
|
||||
describe('web e2e: cold blank Session visibility', () => {
|
||||
let scaffold: WebScaffold
|
||||
let browser: Browser
|
||||
let page: Page
|
||||
let tripwire: ReturnType<typeof watchConsole>
|
||||
|
||||
beforeAll(async () => {
|
||||
scaffold = await launchWebScaffold({})
|
||||
const cwd = join(scaffold.workspaceCwd, WORKSPACE_NAME)
|
||||
await mkdir(cwd, { recursive: true })
|
||||
await seedBlankSession(scaffold, SESSION_ID, cwd)
|
||||
const header = (await scaffold.ctx.sessionPersistence.list())
|
||||
.find(candidate => candidate.id === SESSION_ID)
|
||||
if (header === undefined) throw new Error('blank Session fixture did not materialize')
|
||||
const location = scaffold.ctx.sessionPersistence.locate(header)
|
||||
if (location === undefined) throw new Error('JSONL fixture has no physical artifact')
|
||||
expect((await stat(location.path)).size).toBeLessThanOrEqual(1024)
|
||||
|
||||
browser = await chromium.launch()
|
||||
page = await newEnglishPage(browser)
|
||||
tripwire = watchConsole(page)
|
||||
await page.goto(scaffold.baseUrl, { waitUntil: 'load' })
|
||||
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
|
||||
}, 120_000)
|
||||
|
||||
afterAll(async () => {
|
||||
await browser?.close()
|
||||
await scaffold?.close()
|
||||
})
|
||||
|
||||
it('keeps the verified cold blank Session out of the sidebar', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-cold-blank-session'))
|
||||
const tree = page.getByRole('tree', { name: 'Sessions' })
|
||||
await tree.waitFor({ timeout: 30_000 })
|
||||
expect(await tree.getByText(WORKSPACE_NAME, { exact: true }).count()).toBe(0)
|
||||
const sidebar = await captureStableAria(page, '[role="tree"][aria-label="Sessions"]', scaffold.workspaceCwd)
|
||||
await compareOrRefreshGolden(SIDEBAR_EXPECTED, sidebar, MODE)
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -11,12 +11,13 @@
|
||||
// gets an absolutely positioned seat instead, laid out against the padding box,
|
||||
// which the scrollbar never reduces.
|
||||
//
|
||||
// Without a shared reservation the two tabs disagree by exactly the bar's
|
||||
// width for as long as the transcript overflows: the card jumps sideways on
|
||||
// every tab switch, and inside Chat alone at the moment a growing transcript
|
||||
// starts to scroll. The column reserves the gutter unconditionally
|
||||
// (`scrollbar-gutter: stable`) and states the overlay branch as a scroll
|
||||
// container on the same axes, so both edges are the same edge.
|
||||
// The column handles the two edges without reserving the gutter on both: Chat
|
||||
// keeps `scrollbar-gutter: stable` so its seat's content box never jumps as the
|
||||
// transcript starts to scroll; the overlay branch does NOT reserve (the view
|
||||
// owns its own scrollers, so a reserved gutter would only narrow the view's
|
||||
// content by the bar's width), and the overlay seat instead gives back the
|
||||
// bar's width (`right: var(--dsh-scrollbar-width)`) so both seats measure the
|
||||
// same width and the card does not move.
|
||||
//
|
||||
// Only a real engine can show this. The seat's geometry is layout: jsdom gives
|
||||
// every element a zero-sized box and reports no scrollbar at all, so a unit spec
|
||||
@@ -27,18 +28,17 @@
|
||||
// The browser is launched WITHOUT Playwright's default `--hide-scrollbars`,
|
||||
// which is load-bearing rather than incidental. Under that argument a scroll
|
||||
// container's bar consumes no layout width at all, so the two tabs agree with
|
||||
// and without the reservation and every comparison below holds vacuously —
|
||||
// measured: the unreserved cascade leaves both tabs' bands at 0 there, against
|
||||
// 8 and 0 with the argument dropped. Dropping it is also the faithful
|
||||
// and without the compensation and every comparison below holds vacuously —
|
||||
// measured: the uncompensated cascade leaves both tabs' bands at 0 there,
|
||||
// against 8 and 0 with the argument dropped. Dropping it is also the faithful
|
||||
// configuration: ui-theme's scrollbar.css gives `::-webkit-scrollbar` a width,
|
||||
// and a bar that occupies layout space is what the product actually draws.
|
||||
//
|
||||
// The scenario runs that unreserved cascade in the page — `scrollbar-gutter: auto`
|
||||
// on the scroller, `overflow: hidden` on the overlay branch — and measures the
|
||||
// same two tabs through it, which is what keeps the equal rectangles above from
|
||||
// being explained by a tab switch that never reached the layout. It is the
|
||||
// reported symptom as a number: the card moves 4px, half the 8px band, on each
|
||||
// edge.
|
||||
// The scenario runs that uncompensated cascade in the page — the overlay seat's
|
||||
// `right` compensation dropped to 0 — and measures the same two tabs through
|
||||
// it, which is what keeps the equal rectangles above from being explained by a
|
||||
// tab switch that never reached the layout. It is the reported symptom as a
|
||||
// number: the card moves 4px, half the 8px band, on each edge.
|
||||
//
|
||||
// Zero model calls: a seeded cold session renders from its log, and switching
|
||||
// tabs asks the host for nothing. A stray stream would fail loud with NO_ADAPTER.
|
||||
@@ -62,9 +62,9 @@ const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/composer-tab-geometry',
|
||||
* Absolute coordinates are deliberately absent: they depend on the sidebar's
|
||||
* laid-out width and on font metrics, so committing them would produce a fixture
|
||||
* that has to be re-recorded per platform. What is recorded is the distance
|
||||
* between the two tabs' rectangles, which is zero when the reservation holds and
|
||||
* between the two tabs' rectangles, which is zero when the compensation holds and
|
||||
* the bar's width when it does not — including under the control, so the golden
|
||||
* carries the shift the unreserved cascade produces rather than only its absence.
|
||||
* carries the shift the uncompensated cascade produces rather than only its absence.
|
||||
*/
|
||||
const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md')
|
||||
const MODE = webSnapshotMode()
|
||||
@@ -114,15 +114,15 @@ async function setMeasuredViewport(
|
||||
}
|
||||
|
||||
/**
|
||||
* The unreserved cascade, injected into the page: the reservation dropped and
|
||||
* the overlay branch forced to a hidden box. `!important` beats the module
|
||||
* The uncompensated cascade, injected into the page: the overlay seat's `right`
|
||||
* compensation dropped to 0, so it measures the full padding box while Chat's
|
||||
* seat still rides the reserved content box. `!important` beats the module
|
||||
* rules without a rebuild, and the id lets the control be lifted again in the
|
||||
* same session.
|
||||
*/
|
||||
const CONTROL_STYLE_ID = 'composer-tab-geometry-control'
|
||||
const CONTROL_CSS = `
|
||||
[data-conversation-scroll] { scrollbar-gutter: auto !important; }
|
||||
[data-conversation-scroll]:has([data-conversation-composer-overlay]) { overflow: hidden !important; }
|
||||
[data-conversation-scroll]:has([data-conversation-composer-overlay]) > [data-composer-seat] { right: 0 !important; }
|
||||
`
|
||||
|
||||
/** The column scroller and the input card as the browser lays them out, in one tab. */
|
||||
@@ -221,11 +221,13 @@ async function compareTabs(page: Page): Promise<TabComparison> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the unreserved cascade in the page for one measurement, then lift it.
|
||||
* Run the uncompensated cascade in the page for one measurement, then lift it:
|
||||
* the overlay seat's `right` compensation dropped to 0, so it measures the
|
||||
* full padding box while Chat's seat still rides the reserved content box.
|
||||
* @param page - the page under test.
|
||||
* @returns the comparison as the column lays out without the reservation.
|
||||
* @returns the comparison as the column lays out without the compensation.
|
||||
*/
|
||||
async function compareTabsWithoutReservation(page: Page): Promise<TabComparison> {
|
||||
async function compareTabsWithoutCompensation(page: Page): Promise<TabComparison> {
|
||||
await page.evaluate(({ id, css }) => {
|
||||
const style = document.createElement('style')
|
||||
style.id = id
|
||||
@@ -268,7 +270,7 @@ async function openSeededSession(page: Page): Promise<void> {
|
||||
* Render the golden body.
|
||||
* @param wide - comparison at the viewport where the card sits at its width cap.
|
||||
* @param narrow - comparison at the viewport where the card shrinks with the column.
|
||||
* @param control - comparison at the wide viewport with the reservation removed.
|
||||
* @param control - comparison at the wide viewport with the compensation removed.
|
||||
* @returns the golden body, without a trailing newline.
|
||||
*/
|
||||
function renderGeometry(wide: TabComparison, narrow: TabComparison, control: TabComparison): string {
|
||||
@@ -291,7 +293,7 @@ function renderGeometry(wide: TabComparison, narrow: TabComparison, control: Tab
|
||||
'',
|
||||
...section(`Wide viewport (${String(WIDE_VIEWPORT.width)}px, card at its cap)`, wide),
|
||||
...section(`Narrow viewport (${String(NARROW_VIEWPORT.width)}px, card shrinking with the column)`, narrow),
|
||||
...section('Wide viewport, reservation removed in the page (control)', control),
|
||||
...section('Wide viewport, seat compensation removed in the page (control)', control),
|
||||
].join('\n').trimEnd()
|
||||
}
|
||||
|
||||
@@ -322,22 +324,29 @@ describe('web e2e: input card position across view tabs', () => {
|
||||
await scaffold?.close()
|
||||
})
|
||||
|
||||
it('reserves the same gutter in both tabs while the transcript scrolls', async () => {
|
||||
it('reserves the gutter in Chat and lets Trajectory own its width', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-composer-tab-geometry-band'))
|
||||
await setMeasuredViewport(page, WIDE_VIEWPORT, false)
|
||||
// Vacuity guard, in two parts. A transcript that does not overflow gives
|
||||
// Chat no scrollbar, and a hidden or overlaid bar gives it no width; either
|
||||
// would make the tabs agree without the reservation doing anything.
|
||||
// Vacuity guard. The scenario must be able to fail: on an engine that
|
||||
// does not implement `scrollbar-gutter`, Chat reserves nothing and the
|
||||
// overlay seat's fixed compensation stands alone, manufacturing an 8px
|
||||
// deviation the equal-rectangle assertions would catch. `stable` reserves
|
||||
// even without overflow, so a short transcript is not a vacuous case; the
|
||||
// poll still pins the measurement to the overflowing state the product
|
||||
// ships.
|
||||
await expect.poll(async () => (await measureTab(page)).scrolls, { timeout: 10_000 }).toBe(true)
|
||||
const comparison = await compareTabs(page)
|
||||
expect(comparison.chat.band).toBeGreaterThan(0)
|
||||
// The reservation reaches both states, which is the whole point: the same
|
||||
// band, on a box that scrolls and on one that only holds a view.
|
||||
// Chat keeps the unconditional reservation so its seat's content box never
|
||||
// jumps as the transcript starts to scroll.
|
||||
expect(comparison.chat.gutter).toBe('stable')
|
||||
expect(comparison.trajectory.gutter).toBe('stable')
|
||||
expect(comparison.trajectory.band).toBe(comparison.chat.band)
|
||||
// The overlay branch does NOT reserve: the view owns its own scrollers, so
|
||||
// a reserved gutter would only narrow the view's content by the bar's
|
||||
// width. The seat compensates instead, which the next test asserts.
|
||||
expect(comparison.trajectory.gutter).toBe('auto')
|
||||
expect(comparison.trajectory.band).toBe(0)
|
||||
// Declared as a scroll container on both axes rather than left to compute:
|
||||
// `overflow: hidden` would drop the reservation in WebKit, and a `visible`
|
||||
// `overflow: hidden` would drop any reservation in WebKit, and a `visible`
|
||||
// horizontal axis computes to `auto` beside a scrolling one.
|
||||
expect(comparison.trajectory.overflowY).toBe('auto')
|
||||
expect(comparison.trajectory.overflowX).toBe('hidden')
|
||||
@@ -351,7 +360,7 @@ describe('web e2e: input card position across view tabs', () => {
|
||||
await setMeasuredViewport(page, WIDE_VIEWPORT, false)
|
||||
const comparison = await compareTabs(page)
|
||||
// The reported symptom as a number. At this viewport the card sits at its
|
||||
// width cap, so the unreserved cascade's shift shows up as a centring
|
||||
// width cap, so the uncompensated cascade's shift shows up as a centring
|
||||
// difference — half the band on each edge — rather than as a width change.
|
||||
expect(comparison.leftShift).toBe(0)
|
||||
expect(comparison.rightShift).toBe(0)
|
||||
@@ -378,20 +387,21 @@ describe('web e2e: input card position across view tabs', () => {
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
it('moves the card again once the reservation is removed in the page', async () => {
|
||||
it('moves the card again once the seat compensation is removed in the page', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-composer-tab-geometry-control'))
|
||||
await setMeasuredViewport(page, WIDE_VIEWPORT, false)
|
||||
// The control: without it, equal rectangles could also mean the tab switch
|
||||
// never reached the layout. Under the unreserved cascade the Chat scroller
|
||||
// keeps its bar and the Trajectory branch becomes a hidden box with none,
|
||||
// and the card moves by half the band on each edge.
|
||||
const comparison = await compareTabsWithoutReservation(page)
|
||||
expect(comparison.chat.gutter).toBe('auto')
|
||||
// never reached the layout. Under the uncompensated cascade the overlay seat
|
||||
// loses its `right` compensation and measures the full padding box, so the
|
||||
// card moves by half the band on each edge. Chat's own reservation is
|
||||
// untouched — that is the side that must not change.
|
||||
const comparison = await compareTabsWithoutCompensation(page)
|
||||
expect(comparison.chat.gutter).toBe('stable')
|
||||
expect(comparison.chat.band).toBeGreaterThan(0)
|
||||
expect(comparison.trajectory.band).toBe(0)
|
||||
expect(comparison.leftShift).toBe(comparison.chat.band / 2)
|
||||
expect(comparison.rightShift).toBe(comparison.chat.band / 2)
|
||||
// Restoring the sheet restores the reservation, so the control cannot leak
|
||||
// Restoring the sheet restores the compensation, so the control cannot leak
|
||||
// into the remaining measurements.
|
||||
const restored = await compareTabs(page)
|
||||
expect(restored.leftShift).toBe(0)
|
||||
@@ -405,7 +415,7 @@ describe('web e2e: input card position across view tabs', () => {
|
||||
await setMeasuredViewport(page, NARROW_VIEWPORT, true)
|
||||
const narrow = await compareTabs(page)
|
||||
await setMeasuredViewport(page, WIDE_VIEWPORT, false)
|
||||
const control = await compareTabsWithoutReservation(page)
|
||||
const control = await compareTabsWithoutCompensation(page)
|
||||
await compareOrRefreshGolden(GEOMETRY_EXPECTED, renderGeometry(wide, narrow, control), MODE)
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
// (the plugin-row path discards the ReplayHandle; the direct install keeps
|
||||
// assertConsumed for the teardown fixture-consumption check).
|
||||
import { existsSync } from 'node:fs'
|
||||
import { mkdir, mkdtemp, readFile, readdir, realpath, rm, utimes, writeFile } from 'node:fs/promises'
|
||||
import { mkdir, mkdtemp, readFile, readdir, realpath, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
@@ -703,6 +703,38 @@ export async function seedSession(
|
||||
delegationDepth: 0,
|
||||
...agentPreset === undefined ? {} : { agentPreset },
|
||||
}
|
||||
await persistSeedSession(scaffold, meta, events)
|
||||
return meta.id
|
||||
}
|
||||
|
||||
/** Seed one materialized cold Session whose log has no turn/start event. */
|
||||
export async function seedBlankSession(
|
||||
scaffold: WebScaffold,
|
||||
id: string,
|
||||
cwd: string,
|
||||
): Promise<SessionId> {
|
||||
const meta: SessionHeader = {
|
||||
version: SESSION_FORMAT_VERSION,
|
||||
id: SessionId(id),
|
||||
createdAt: Date.now() - 60_000,
|
||||
cwd,
|
||||
delegationDepth: 0,
|
||||
}
|
||||
await persistSeedSession(scaffold, meta, [{
|
||||
type: 'session/end-seed',
|
||||
seq: 0,
|
||||
time: meta.createdAt,
|
||||
data: {},
|
||||
}])
|
||||
return meta.id
|
||||
}
|
||||
|
||||
/** Materialize one detached Session fixture through the shipped JSONL provider. */
|
||||
async function persistSeedSession(
|
||||
scaffold: WebScaffold,
|
||||
meta: SessionHeader,
|
||||
events: readonly SessionEvent[],
|
||||
): Promise<void> {
|
||||
const seeder = new Context()
|
||||
try {
|
||||
await seeder.plugin(SessionStore)
|
||||
@@ -711,16 +743,9 @@ export async function seedSession(
|
||||
await seeder.plugin(JsonlSessionPersistence, { root: scaffold.persistenceRoot })
|
||||
await seeder.sessionPersistence.create(meta)
|
||||
await seeder.sessionPersistence.append(meta.id, events)
|
||||
// Deterministic sidebar order: cold summaries take updatedAt from mtime.
|
||||
const located = seeder.sessionPersistence.locate(meta)
|
||||
if (located !== undefined) {
|
||||
const backdated = new Date(meta.createdAt)
|
||||
await utimes(located.path, backdated, backdated)
|
||||
}
|
||||
} finally {
|
||||
await seeder.fiber.dispose()
|
||||
}
|
||||
return meta.id
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
- tree "Sessions": No sessions yet
|
||||
@@ -5,9 +5,9 @@
|
||||
- Chat: scrollbar-gutter stable, overflow hidden/auto
|
||||
- Chat scroller scrolls: true
|
||||
- Chat reserved band: 8px
|
||||
- Trajectory: scrollbar-gutter stable, overflow hidden/auto
|
||||
- Trajectory: scrollbar-gutter auto, overflow hidden/auto
|
||||
- Trajectory scroller scrolls: false
|
||||
- Trajectory reserved band: 8px
|
||||
- Trajectory reserved band: 0px
|
||||
- input card left edge moves between tabs: 0px
|
||||
- input card right edge moves between tabs: 0px
|
||||
- input card width changes between tabs: 0px
|
||||
@@ -17,19 +17,19 @@
|
||||
- Chat: scrollbar-gutter stable, overflow hidden/auto
|
||||
- Chat scroller scrolls: true
|
||||
- Chat reserved band: 8px
|
||||
- Trajectory: scrollbar-gutter stable, overflow hidden/auto
|
||||
- Trajectory: scrollbar-gutter auto, overflow hidden/auto
|
||||
- Trajectory scroller scrolls: false
|
||||
- Trajectory reserved band: 8px
|
||||
- Trajectory reserved band: 0px
|
||||
- input card left edge moves between tabs: 0px
|
||||
- input card right edge moves between tabs: 0px
|
||||
- input card width changes between tabs: 0px
|
||||
|
||||
## Wide viewport, reservation removed in the page (control)
|
||||
## Wide viewport, seat compensation removed in the page (control)
|
||||
|
||||
- Chat: scrollbar-gutter auto, overflow hidden/auto
|
||||
- Chat: scrollbar-gutter stable, overflow hidden/auto
|
||||
- Chat scroller scrolls: true
|
||||
- Chat reserved band: 8px
|
||||
- Trajectory: scrollbar-gutter auto, overflow hidden/hidden
|
||||
- Trajectory: scrollbar-gutter auto, overflow hidden/auto
|
||||
- Trajectory scroller scrolls: false
|
||||
- Trajectory reserved band: 0px
|
||||
- input card left edge moves between tabs: 4px
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
- row "Load earlier history":
|
||||
- cell "Load earlier history":
|
||||
- button "Load earlier history":
|
||||
- status
|
||||
@@ -3,6 +3,7 @@
|
||||
// DOM mounting stays bounded, and every scroll range remains reachable.
|
||||
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join } from 'node:path'
|
||||
import type { Browser, Page } from 'playwright'
|
||||
import { chromium } from 'playwright'
|
||||
@@ -11,6 +12,8 @@ import type { StreamChunk } from '@deepseek-ai/dsh-llm'
|
||||
import type { ReplayEntry } from '@deepseek-ai/dsh-llm-replay'
|
||||
import { createChatScrollFixture } from './chat-scroll-fixture.ts'
|
||||
import {
|
||||
captureStableAria,
|
||||
compareOrRefreshGolden,
|
||||
launchWebScaffold,
|
||||
seedSession,
|
||||
watchConsole,
|
||||
@@ -20,6 +23,10 @@ import {
|
||||
import { newEnglishPage, saveFailureShot } from './support.ts'
|
||||
|
||||
const MODE = webSnapshotMode()
|
||||
const LOAD_MORE_EXPECTED = fileURLToPath(new URL(
|
||||
'./snapshots/trajectory-virtualization/load-more.expected.md',
|
||||
import.meta.url,
|
||||
))
|
||||
const SESSION_ID = 'trajectory-virtualization-e2e'
|
||||
const FIXTURE = createChatScrollFixture({
|
||||
markerPrefix: 'TRAJECTORY_VIRTUAL',
|
||||
@@ -150,10 +157,16 @@ async function loadToFirstTurn(page: Page): Promise<void> {
|
||||
await scrollToRatio(page, 0)
|
||||
if (await page.getByText(marker, { exact: false }).count() > 0) return
|
||||
const before = await logicalRows(page)
|
||||
const anchor = await firstVisibleRow(page)
|
||||
await expect.poll(async () => ({
|
||||
marker: await page.getByText(marker, { exact: false }).count() > 0,
|
||||
rows: await logicalRows(page),
|
||||
}), { timeout: 30_000 }).not.toEqual({ marker: false, rows: before })
|
||||
await nextPaint(page)
|
||||
await expect.poll(async () => {
|
||||
const top = await rowTop(page, anchor.key)
|
||||
return top === null ? Number.POSITIVE_INFINITY : Math.abs(top - anchor.top)
|
||||
}, { timeout: 15_000 }).toBeLessThanOrEqual(GEOMETRY_TOLERANCE)
|
||||
}
|
||||
throw new Error('trajectory did not reach the first turn after twelve older-page requests')
|
||||
}
|
||||
@@ -230,8 +243,27 @@ describe('web e2e: Trajectory virtualization over tail-paged history', () => {
|
||||
expect(await page.getByText('Initial System Prompt', { exact: true }).count()).toBe(0)
|
||||
expect(await mountedRows(page)).toBeLessThanOrEqual(MAX_MOUNTED_ROWS)
|
||||
|
||||
await scrollToRatio(page, 0)
|
||||
const loadMore = page.locator('[data-history-load] button')
|
||||
await loadMore.waitFor({ timeout: 15_000 })
|
||||
expect(await loadMore.textContent()).toBe('Load earlier history')
|
||||
const loadMoreSnapshot = await captureStableAria(
|
||||
page,
|
||||
'[data-history-load]',
|
||||
scaffold.workspaceCwd,
|
||||
)
|
||||
await compareOrRefreshGolden(LOAD_MORE_EXPECTED, loadMoreSnapshot, MODE)
|
||||
// Avoid Playwright scrolling the offscreen first row into the automatic-load threshold.
|
||||
await loadMore.evaluate((button: HTMLButtonElement) => { button.click() })
|
||||
await expect.poll(() => held, { timeout: 15_000 }).toBe(true)
|
||||
await expect.poll(async () => ({
|
||||
disabled: await loadMore.isDisabled(),
|
||||
label: await loadMore.getAttribute('aria-label'),
|
||||
}), { timeout: 15_000 }).toEqual({
|
||||
disabled: true,
|
||||
label: 'Loading earlier history…',
|
||||
})
|
||||
|
||||
await scrollToRatio(page, 0)
|
||||
const anchor = await firstVisibleRow(page)
|
||||
const selectedRow = page.locator(
|
||||
`[data-trajectory-scroll] tr[data-trajectory-row-key=${JSON.stringify(anchor.key)}]`,
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"tests/replay-round-trip.e2e.ts",
|
||||
"tests/hmr-live.e2e.ts",
|
||||
"tests/seeded-history.e2e.ts",
|
||||
"tests/cold-blank-session.e2e.ts",
|
||||
"tests/stats-paged-history.e2e.ts",
|
||||
"tests/sidebar-scrollbar.e2e.ts",
|
||||
"tests/conversation-column-overflow.e2e.ts",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 30 KiB |
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/architecture.md
|
||||
architecture.md: 77000ce9d4608d440e1d903eb80a42f2ed6435ef
|
||||
architecture.zh.md: 268724d52c82e31c4fc2b51db59823f3720f9b91
|
||||
architecture.zh.md: f2f5310f665b86b86587307e7ce31c5841b96317
|
||||
@@ -50,6 +50,8 @@ dsh --profile web --dump-config
|
||||
| [`core/scope`](subsystems/scope.md) | 按 agent 划分作用域的注册原语 | 库,无 ctx 键 |
|
||||
| [`llm/llm`](subsystems/llm-streaming.md) | 消息与流式词汇表,以及适配器 seam | `ctx.llm` |
|
||||
|
||||
<a id="events"></a>
|
||||
|
||||
## 事件
|
||||
|
||||
事件就是扩展点,而选对事件域是大多数改动的第一个决定。
|
||||
@@ -60,6 +62,8 @@ dsh --profile web --dump-config
|
||||
|
||||
[事件映射](event-producer-consumer.md)列出每个事件的生产方与消费方。
|
||||
|
||||
<a id="turn-flow"></a>
|
||||
|
||||
## 轮次流程
|
||||
|
||||
一个**步骤**是一次模型请求加上它调用的工具。一个**轮次**包含零个或多个步骤:它在领取首条输入之前打开,并在不再欠下任何工作时关闭。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/config-catalog.md
|
||||
config-catalog.md: 19bfa6d1fb847de4a7207f42dabd67d43f288361
|
||||
config-catalog.zh.md: fda208e8fcd2ff6dd697efed84a4073ecbd5a912
|
||||
config-catalog.md: 20919b3fdc5ab26255465949d72bdce8d356a529
|
||||
config-catalog.zh.md: 8dfb49df5e3f5906af859a4de83ebc44f315a0bd
|
||||
@@ -9,6 +9,8 @@ This file is GENERATED from source (`scripts/gen-config-catalog.ts`) and verifie
|
||||
|
||||
A `Requires:` line lists the service keys the plugin `inject`s: its `cordis.yml` tree must also load providers for those services. Scope is the harness tier (`packages/`); the vendored cordis plugins a config tree may also load (`hmr`, the console logger, …) are pinned upstream source ([vendoring policy](../vendor/README.md)) and not catalogued here.
|
||||
|
||||
<a id="deepseek-aidsh-acp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-acp`
|
||||
|
||||
Requires: `agents`
|
||||
@@ -29,6 +31,8 @@ Depends on: `Stream` (`@agentclientprotocol/sdk`)
|
||||
|
||||
Source: [`packages/acp/acp/src/index.ts:70`](../packages/acp/acp/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-acp-demo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-acp-demo`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -82,6 +86,8 @@ Depends on: [`agentCore`](../packages/examples/agent-spine-demo/src/index.ts) ·
|
||||
|
||||
Source: [`packages/examples/acp-demo/src/index.ts:39`](../packages/examples/acp-demo/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-default-model"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-default-model`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -96,6 +102,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/core/agent-default-model/src/index.ts:41`](../packages/core/agent-default-model/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-instructions"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-instructions`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -124,6 +132,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/context/agent-instructions/src/config.ts:18`](../packages/context/agent-instructions/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-loop"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-loop`
|
||||
|
||||
Requires: `agents` · `sessions` · `llm` · `tools` · `systemPrompt`
|
||||
@@ -154,6 +164,8 @@ Depends on: [`AgentOptions`](subsystems/core.md) · [`SessionId`](subsystems/cor
|
||||
|
||||
Source: [`packages/core/agent-loop/src/index.ts:255`](../packages/core/agent-loop/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-presets"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-presets`
|
||||
|
||||
Requires: `loader`
|
||||
@@ -190,6 +202,8 @@ export type PresetTrust = 'system' | 'user'
|
||||
|
||||
Source: [`packages/preset/agent-presets/src/preset.ts:52`](../packages/preset/agent-presets/src/preset.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-spine-demo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-spine-demo`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -280,6 +294,8 @@ Depends on: [`AgentLoopConfig`](#deepseek-aidsh-agent-loop) · [`GoalDomainConfi
|
||||
|
||||
Source: [`packages/examples/agent-spine-demo/src/index.ts:92`](../packages/examples/agent-spine-demo/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-tool-presentation"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-tool-presentation`
|
||||
|
||||
Requires: `tools`
|
||||
@@ -302,6 +318,8 @@ Depends on: [`ToolPresentationMode`](subsystems/tools.md)
|
||||
|
||||
Source: [`packages/core/agent-tool-presentation/src/index.ts:38`](../packages/core/agent-tool-presentation/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-attachment-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-attachment-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -322,6 +340,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/attachment/attachment-local/src/index.ts:24`](../packages/attachment/attachment-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-bash-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-bash-local`
|
||||
|
||||
Requires: `subprocess`
|
||||
@@ -346,6 +366,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/shell/bash-local/src/index.ts:41`](../packages/shell/bash-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-bash-sandbox"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-bash-sandbox`
|
||||
|
||||
Requires: `subprocess` · `sandbox` · `sandboxPolicy`
|
||||
@@ -365,6 +387,8 @@ Depends on: [`LocalConfig`](#deepseek-aidsh-bash-local)
|
||||
|
||||
Source: [`packages/shell/bash-sandbox/src/index.ts:35`](../packages/shell/bash-sandbox/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-client-connection"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-client-connection`
|
||||
|
||||
Requires: `webServer`
|
||||
@@ -388,6 +412,8 @@ export interface ConnectionConfig {
|
||||
|
||||
Source: [`packages/client/connection/src/index.ts:50`](../packages/client/connection/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-client-hmr"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-client-hmr`
|
||||
|
||||
Requires: `clientModules` · `webServer`
|
||||
@@ -402,6 +428,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/client/hmr/src/index.ts:31`](../packages/client/hmr/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-code-runtime-worker-thread"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-code-runtime-worker-thread`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -437,6 +465,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/code-runtime/code-runtime-worker-thread/src/index.ts:25`](../packages/code-runtime/code-runtime-worker-thread/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-compaction-basic"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-compaction-basic`
|
||||
|
||||
Requires: `llm` · `tokenMeter` · `sessions`
|
||||
@@ -481,6 +511,8 @@ export interface ModelCompactPolicyConfig extends CompactionPolicyConfig {
|
||||
|
||||
Source: [`packages/compaction/compaction-basic/src/types.ts:38`](../packages/compaction/compaction-basic/src/types.ts)
|
||||
|
||||
<a id="deepseek-aidsh-compaction-tool-result-pruner"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-compaction-tool-result-pruner`
|
||||
|
||||
Requires: `tokenMeter`
|
||||
@@ -499,6 +531,8 @@ export interface ToolResultPruneConfig {
|
||||
|
||||
Source: [`packages/compaction/compaction-tool-result-pruner/src/types.ts:4`](../packages/compaction/compaction-tool-result-pruner/src/types.ts)
|
||||
|
||||
<a id="deepseek-aidsh-cordis-host-runner"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-cordis-host-runner`
|
||||
|
||||
Requires: `tools`
|
||||
@@ -513,6 +547,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/extensions/cordis-host-runner/src/index.ts:88`](../packages/extensions/cordis-host-runner/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-credentials-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-credentials-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -531,6 +567,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/credentials/credentials-local/src/index.ts:55`](../packages/credentials/credentials-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-e2b"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-e2b`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -547,6 +585,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/e2b/e2b/src/index.ts:43`](../packages/e2b/e2b/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-fs-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-fs-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -564,6 +604,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/fs/fs-local/src/index.ts:41`](../packages/fs/fs-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-fs-sandbox"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-fs-sandbox`
|
||||
|
||||
Requires: `sandboxPolicy`
|
||||
@@ -582,6 +624,8 @@ Depends on: [`LocalConfig`](#deepseek-aidsh-fs-local)
|
||||
|
||||
Source: [`packages/fs/fs-sandbox/src/index.ts:49`](../packages/fs/fs-sandbox/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-goal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-goal`
|
||||
|
||||
Requires: `agents`
|
||||
@@ -596,6 +640,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/goal/goal/src/index.ts:116`](../packages/goal/goal/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-headless"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-headless`
|
||||
|
||||
Requires: `agentDefaultModel` · `agents` · `sessions`
|
||||
@@ -610,6 +656,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/bundle/headless/src/index.ts:31`](../packages/bundle/headless/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-hooks-claude-code"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-hooks-claude-code`
|
||||
|
||||
Requires: `shell`
|
||||
@@ -646,6 +694,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/hooks/hooks-claude-code/src/index.ts:45`](../packages/hooks/hooks-claude-code/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-hooks-codex"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-hooks-codex`
|
||||
|
||||
Requires: `shell`
|
||||
@@ -671,6 +721,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/hooks/hooks-codex/src/index.ts:44`](../packages/hooks/hooks-codex/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-apiproxy"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-apiproxy`
|
||||
|
||||
Requires: `agentDefaultModel` · `agents` · `attachments` · `directoryPicker` · `llm` · `sessions` · `subagents` · `sessionQuery` · `tools` · `userQuestions` · `workspaceRegistry`
|
||||
@@ -692,11 +744,19 @@ export interface Config {
|
||||
* @default 6
|
||||
*/
|
||||
sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
||||
/**
|
||||
* Maximum physical size of a cold Session artifact eligible for blankness
|
||||
* verification. Zero disables probes.
|
||||
* @default 1024
|
||||
*/
|
||||
coldBlankProbeMaxBytes?: number
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/host/apiproxy/src/index.ts:41`](../packages/host/apiproxy/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-directory-picker-browse"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-directory-picker-browse`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -709,6 +769,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/host/directory-picker-browse/src/index.ts:181`](../packages/host/directory-picker-browse/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-frontend-static"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-frontend-static`
|
||||
|
||||
Requires: `webServer`
|
||||
@@ -723,6 +785,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/host/frontend-static/src/index.ts:28`](../packages/host/frontend-static/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-webserver"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-webserver`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -737,6 +801,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/host/webserver/src/index.ts:45`](../packages/host/webserver/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-invariants"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-invariants`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -753,6 +819,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/runtime-diagnostics/invariants/src/index.ts:15`](../packages/runtime-diagnostics/invariants/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-jobs-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-jobs-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -768,6 +836,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/jobs/jobs-local/src/index.ts:31`](../packages/jobs/jobs-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-deepseek"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-deepseek`
|
||||
|
||||
Requires: `llm`
|
||||
@@ -821,6 +891,8 @@ Depends on: [`RetryPolicyConfig`](../packages/llm/llm/src/index.ts)
|
||||
|
||||
Source: [`packages/llm/llm-deepseek/src/index.ts:62`](../packages/llm/llm-deepseek/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-pi-ai"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-pi-ai`
|
||||
|
||||
Requires: `llm`
|
||||
@@ -1009,6 +1081,8 @@ Depends on: `Api` (`@earendil-works/pi-ai`) · `CacheRetention` (`@earendil-work
|
||||
|
||||
Source: [`packages/llm/llm-pi-ai/src/config.ts:172`](../packages/llm/llm-pi-ai/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-replay"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-replay`
|
||||
|
||||
Requires: `llm`
|
||||
@@ -1075,6 +1149,8 @@ Depends on: [`ModelModality`](../packages/llm/llm/src/index.ts) · [`RetryPolicy
|
||||
|
||||
Source: [`packages/test-support/llm-replay/src/index.ts:776`](../packages/test-support/llm-replay/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-retry"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-retry`
|
||||
|
||||
Requires: `agents`
|
||||
@@ -1086,6 +1162,8 @@ export type Config = Readonly<Record<string, never>>
|
||||
|
||||
Source: [`packages/llm/llm-retry/src/index.ts:24`](../packages/llm/llm-retry/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-lsp-stdio"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-lsp-stdio`
|
||||
|
||||
Requires: `fs` · `lsp` · `subprocess`
|
||||
@@ -1126,6 +1204,8 @@ export interface LspLocalServerConfig {
|
||||
|
||||
Source: [`packages/lsp/lsp-stdio/src/index.ts:82`](../packages/lsp/lsp-stdio/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-mcp-client"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-mcp-client`
|
||||
|
||||
Requires: `tools`
|
||||
@@ -1197,6 +1277,8 @@ export interface ReconnectConfig {
|
||||
|
||||
Source: [`packages/mcp/mcp-client/src/index.ts:98`](../packages/mcp/mcp-client/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-message-feedback"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-message-feedback`
|
||||
|
||||
Requires: `storageDomain` · `sessionPersistence` · `sessions`
|
||||
@@ -1211,6 +1293,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/feedback/message-feedback/src/index.ts:49`](../packages/feedback/message-feedback/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-permission-presets"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-permission-presets`
|
||||
|
||||
Requires: `shell` · `approval` · `sessions`
|
||||
@@ -1248,6 +1332,8 @@ Depends on: [`ApprovalPolicy`](subsystems/approval.md) · [`SandboxMode`](subsys
|
||||
|
||||
Source: [`packages/interaction/permission-presets/src/index.ts:140`](../packages/interaction/permission-presets/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-persona"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-persona`
|
||||
|
||||
Requires: `systemPrompt`
|
||||
@@ -1270,6 +1356,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/preset/persona/src/index.ts:34`](../packages/preset/persona/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-plan-mode"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-plan-mode`
|
||||
|
||||
Requires: `tools` · `systemPrompt`
|
||||
@@ -1284,6 +1372,8 @@ export interface PlanModeConfig {
|
||||
|
||||
Source: [`packages/plan/plan-mode/src/index.ts:70`](../packages/plan/plan-mode/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-pwsh-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-pwsh-local`
|
||||
|
||||
Requires: `subprocess`
|
||||
@@ -1315,6 +1405,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/shell/pwsh-local/src/index.ts:58`](../packages/shell/pwsh-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-pwsh-sandbox"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-pwsh-sandbox`
|
||||
|
||||
Requires: `subprocess` · `sandbox` · `sandboxPolicy`
|
||||
@@ -1335,6 +1427,8 @@ Depends on: [`LocalConfig`](#deepseek-aidsh-pwsh-local)
|
||||
|
||||
Source: [`packages/shell/pwsh-sandbox/src/index.ts:40`](../packages/shell/pwsh-sandbox/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-repeat-tool-reminder"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-repeat-tool-reminder`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1367,6 +1461,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/guard/repeat-tool-reminder/src/index.ts:28`](../packages/guard/repeat-tool-reminder/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-sandbox-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-sandbox-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1397,6 +1493,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/sandbox/sandbox-local/src/index.ts:44`](../packages/sandbox/sandbox-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-sandbox-policy"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-sandbox-policy`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1422,6 +1520,8 @@ Depends on: [`SandboxMode`](subsystems/sandbox.md)
|
||||
|
||||
Source: [`packages/sandbox/sandbox-policy/src/index.ts:67`](../packages/sandbox/sandbox-policy/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-sdk-jsonrpc-server"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-sdk-jsonrpc-server`
|
||||
|
||||
Requires: `agents`
|
||||
@@ -1444,6 +1544,8 @@ Depends on: `Readable` (`node:stream`) · `Writable` (`node:stream`)
|
||||
|
||||
Source: [`packages/sdk/server/src/index.ts:25`](../packages/sdk/server/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-persistence-jsonl"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-persistence-jsonl`
|
||||
|
||||
Requires: `sessions`
|
||||
@@ -1481,6 +1583,8 @@ export type JsonlCompression = 'zstd' | 'none'
|
||||
|
||||
Source: [`packages/session/session-persistence-jsonl/src/index.ts:60`](../packages/session/session-persistence-jsonl/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-persistence-sqlite"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-persistence-sqlite`
|
||||
|
||||
Requires: `sessions`
|
||||
@@ -1524,6 +1628,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist'
|
||||
|
||||
Source: [`packages/session/session-persistence-sqlite/src/index.ts:70`](../packages/session/session-persistence-sqlite/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-projection-cache"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-projection-cache`
|
||||
|
||||
Requires: `storageDomain` · `sessionProjections` · `sessionPersistence` · `sessions`
|
||||
@@ -1545,6 +1651,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/session/session-projection-cache/src/index.ts:42`](../packages/session/session-projection-cache/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-query-sqlite"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-query-sqlite`
|
||||
|
||||
Requires: `sessions`
|
||||
@@ -1589,6 +1697,8 @@ Depends on: [`SessionQueryConfig`](../packages/session-query/session-query/src/i
|
||||
|
||||
Source: [`packages/session-query/session-query-sqlite/src/index.ts:89`](../packages/session-query/session-query-sqlite/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-reference"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-reference`
|
||||
|
||||
Requires: `sessionQuery`
|
||||
@@ -1607,6 +1717,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/context/session-reference/src/config.ts:11`](../packages/context/session-reference/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-telemetry-otel"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-telemetry-otel`
|
||||
|
||||
Requires: `sessions`
|
||||
@@ -1651,6 +1763,8 @@ Depends on: `BatchLogRecordProcessorOptions` (`@opentelemetry/sdk-logs`) · `OTL
|
||||
|
||||
Source: [`packages/session/session-telemetry-otel/src/index.ts:91`](../packages/session/session-telemetry-otel/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-title"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-title`
|
||||
|
||||
Requires: `sessions`
|
||||
@@ -1669,6 +1783,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/session/session-title/src/index.ts:79`](../packages/session/session-title/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-title-all-prompts-llm"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-title-all-prompts-llm`
|
||||
|
||||
Requires: `sessionTitle` · `llm` · `sessions`
|
||||
@@ -1682,6 +1798,8 @@ Depends on: [`SessionTitleLlmConfig`](../packages/session/session-title-llm/src/
|
||||
|
||||
Source: [`packages/session/session-title-all-prompts-llm/src/index.ts:15`](../packages/session/session-title-all-prompts-llm/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-title-first-prompt-llm"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-title-first-prompt-llm`
|
||||
|
||||
Requires: `sessionTitle` · `llm` · `sessions`
|
||||
@@ -1695,6 +1813,8 @@ Depends on: [`SessionTitleLlmConfig`](../packages/session/session-title-llm/src/
|
||||
|
||||
Source: [`packages/session/session-title-first-prompt-llm/src/index.ts:15`](../packages/session/session-title-first-prompt-llm/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-settings-file"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-settings-file`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1713,6 +1833,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/settings/settings-file/src/index.ts:21`](../packages/settings/settings-file/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-shell-env"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-shell-env`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1725,6 +1847,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/shell/shell-env/src/index.ts:29`](../packages/shell/shell-env/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-skill"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-skill`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1737,6 +1861,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/skill/skill/src/index.ts:279`](../packages/skill/skill/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-skill-filesystem"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-skill-filesystem`
|
||||
|
||||
Requires: `skills`
|
||||
@@ -1773,6 +1899,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/skill/skill-filesystem/src/index.ts:49`](../packages/skill/skill-filesystem/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-spill-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-spill-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1789,6 +1917,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/spill/spill-local/src/index.ts:22`](../packages/spill/spill-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-spill-policy"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-spill-policy`
|
||||
|
||||
Requires: `tools`
|
||||
@@ -1807,6 +1937,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/spill/spill-policy/src/index.ts:60`](../packages/spill/spill-policy/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-storage-domain"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-storage-domain`
|
||||
|
||||
Requires: `storage`
|
||||
@@ -1828,6 +1960,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/storage/storage-domain/src/index.ts:52`](../packages/storage/storage-domain/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-storage-json"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-storage-json`
|
||||
|
||||
Requires: `storage`
|
||||
@@ -1847,6 +1981,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/storage/storage-json/src/index.ts:27`](../packages/storage/storage-json/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-storage-sqlite"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-storage-sqlite`
|
||||
|
||||
Requires: `storage`
|
||||
@@ -1885,6 +2021,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist'
|
||||
|
||||
Source: [`packages/storage/storage-sqlite/src/index.ts:24`](../packages/storage/storage-sqlite/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-acp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-acp`
|
||||
|
||||
Requires: `subagents` · `subprocess`
|
||||
@@ -1936,6 +2074,8 @@ export type PermissionPolicy = 'allow' | 'reject'
|
||||
|
||||
Source: [`packages/subagent/subagent-acp/src/index.ts:27`](../packages/subagent/subagent-acp/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-claude-code"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-claude-code`
|
||||
|
||||
Requires: `subagents` · `subprocess`
|
||||
@@ -1955,6 +2095,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/subagent/subagent-claude-code/src/index.ts:32`](../packages/subagent/subagent-claude-code/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-codex"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-codex`
|
||||
|
||||
Requires: `subagents` · `subprocess`
|
||||
@@ -1974,6 +2116,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/subagent/subagent-codex/src/index.ts:30`](../packages/subagent/subagent-codex/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-dsh-sdk"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-dsh-sdk`
|
||||
|
||||
Requires: `subagents`
|
||||
@@ -2025,6 +2169,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/subagent/subagent-dsh-sdk/src/index.ts:29`](../packages/subagent/subagent-dsh-sdk/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-fork-in-process"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-fork-in-process`
|
||||
|
||||
Requires: `subagents`
|
||||
@@ -2039,6 +2185,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/subagent/subagent-fork-in-process/src/index.ts:31`](../packages/subagent/subagent-fork-in-process/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-spawn-in-process"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-spawn-in-process`
|
||||
|
||||
Requires: `subagents`
|
||||
@@ -2053,6 +2201,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/subagent/subagent-spawn-in-process/src/index.ts:25`](../packages/subagent/subagent-spawn-in-process/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subprocess-e2b"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subprocess-e2b`
|
||||
|
||||
Requires: `e2b`
|
||||
@@ -2067,6 +2217,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/e2b/subprocess-e2b/src/index.ts:25`](../packages/e2b/subprocess-e2b/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-system-prompt"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-system-prompt`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2092,6 +2244,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/core/system-prompt/src/index.ts:186`](../packages/core/system-prompt/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-terminal-bash"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-terminal-bash`
|
||||
|
||||
Requires: `terminals` · `sandboxPolicy` · `subprocess`
|
||||
@@ -2135,6 +2289,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/terminal/terminal-bash/src/config.ts:6`](../packages/terminal/terminal-bash/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-time-context"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-time-context`
|
||||
|
||||
Requires: `agents`
|
||||
@@ -2151,6 +2307,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/context/time-context/src/index.ts:27`](../packages/context/time-context/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tmux-context"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tmux-context`
|
||||
|
||||
Requires: `agents`
|
||||
@@ -2165,6 +2323,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/context/tmux-context/src/index.ts:34`](../packages/context/tmux-context/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-token-meter"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-token-meter`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2174,6 +2334,8 @@ export type TokenMeterConfig = Record<string, never>
|
||||
|
||||
Source: [`packages/llm/token-meter/src/types.ts:12`](../packages/llm/token-meter/src/types.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash`
|
||||
|
||||
Requires: `tools` · `shell` · `systemPrompt` · `shellEnv`
|
||||
@@ -2188,6 +2350,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/shell/tool-bash/src/index.ts:34`](../packages/shell/tool-bash/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash-persistent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash-persistent`
|
||||
|
||||
Requires: `tools` · `terminals`
|
||||
@@ -2208,6 +2372,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/shell/tool-bash-persistent/src/index.ts:405`](../packages/shell/tool-bash-persistent/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs`
|
||||
|
||||
Requires: `tools` · `fs` · `systemPrompt`
|
||||
@@ -2228,6 +2394,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/fs/tool-fs/src/index.ts:25`](../packages/fs/tool-fs/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs-search"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs-search`
|
||||
|
||||
Requires: `tools` · `systemPrompt` · `subprocess`
|
||||
@@ -2261,6 +2429,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/fs/tool-fs-search/src/index.ts:73`](../packages/fs/tool-fs-search/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-goal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-goal`
|
||||
|
||||
Requires: `agents` · `goals` · `tools` · `systemPrompt`
|
||||
@@ -2275,6 +2445,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/goal/tool-goal/src/index.ts:26`](../packages/goal/tool-goal/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-jobs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-jobs`
|
||||
|
||||
Requires: `tools` · `jobs` · `systemPrompt`
|
||||
@@ -2307,6 +2479,8 @@ export type CompletionDelivery = 'quiet' | 'wakeup'
|
||||
|
||||
Source: [`packages/jobs/tool-jobs/src/index.ts:32`](../packages/jobs/tool-jobs/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-lsp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-lsp`
|
||||
|
||||
Requires: `tools` · `lsp` · `systemPrompt`
|
||||
@@ -2325,6 +2499,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/lsp/tool-lsp/src/index.ts:58`](../packages/lsp/tool-lsp/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-pwsh"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-pwsh`
|
||||
|
||||
Requires: `tools` · `shell` · `systemPrompt` · `shellEnv`
|
||||
@@ -2339,6 +2515,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/shell/tool-pwsh/src/index.ts:52`](../packages/shell/tool-pwsh/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-ralph"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ralph`
|
||||
|
||||
Requires: `tools` · `workflowEngine` · `subagents` · `systemPrompt`
|
||||
@@ -2359,6 +2537,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/workflow/tool-ralph/src/index.ts:23`](../packages/workflow/tool-ralph/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-session-query"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-session-query`
|
||||
|
||||
Requires: `tools` · `systemPrompt` · `sessionQuery`
|
||||
@@ -2375,6 +2555,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/session-query/tool-session-query/src/index.ts:29`](../packages/session-query/tool-session-query/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-skill"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-skill`
|
||||
|
||||
Requires: `agents` · `tools` · `skills`
|
||||
@@ -2389,6 +2571,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/skill/tool-skill/src/index.ts:61`](../packages/skill/tool-skill/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-str-replace-editor"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-str-replace-editor`
|
||||
|
||||
Requires: `tools` · `fs`
|
||||
@@ -2405,6 +2589,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/fs/tool-str-replace-editor/src/index.ts:497`](../packages/fs/tool-str-replace-editor/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent`
|
||||
|
||||
Requires: `tools` · `subagents` · `systemPrompt`
|
||||
@@ -2468,6 +2654,8 @@ Depends on: [`AgentOptions`](subsystems/core.md)
|
||||
|
||||
Source: [`packages/subagent/tool-subagent/src/index.ts:29`](../packages/subagent/tool-subagent/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent-report"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent-report`
|
||||
|
||||
Requires: `subagents` · `tools` · `systemPrompt`
|
||||
@@ -2488,6 +2676,8 @@ Depends on: [`SubagentReportDelivery`](subsystems/subagent.md)
|
||||
|
||||
Source: [`packages/subagent/tool-subagent-report/src/index.ts:27`](../packages/subagent/tool-subagent-report/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-terminal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-terminal`
|
||||
|
||||
Requires: `terminals` · `tools` · `systemPrompt`
|
||||
@@ -2504,6 +2694,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/terminal/tool-terminal/src/index.ts:35`](../packages/terminal/tool-terminal/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-todo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-todo`
|
||||
|
||||
Requires: `tools`
|
||||
@@ -2524,6 +2716,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/todo/tool-todo/src/index.ts:29`](../packages/todo/tool-todo/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-web"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-web`
|
||||
|
||||
Requires: `tools` · `web` · `systemPrompt`
|
||||
@@ -2548,6 +2742,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/web/tool-web/src/index.ts:37`](../packages/web/tool-web/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-workflow"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-workflow`
|
||||
|
||||
Requires: `tools` · `workflowEngine` · `systemPrompt`
|
||||
@@ -2564,6 +2760,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/workflow/tool-workflow/src/index.ts:33`](../packages/workflow/tool-workflow/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tools"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tools`
|
||||
|
||||
Requires: `systemPrompt`
|
||||
@@ -2598,6 +2796,8 @@ export type ToolPresentationMode = 'native' | 'code' | 'both'
|
||||
|
||||
Source: [`packages/core/tools/src/index.ts:654`](../packages/core/tools/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-typert-loader"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-typert-loader`
|
||||
|
||||
Requires: `typert` · `loader`
|
||||
@@ -2612,6 +2812,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/typert/loader/src/index.ts:47`](../packages/typert/loader/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-user-approval"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-user-approval`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2641,6 +2843,8 @@ export type ApprovalPolicy = 'ask' | 'never'
|
||||
|
||||
Source: [`packages/interaction/user-approval/src/index.ts:177`](../packages/interaction/user-approval/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2660,6 +2864,8 @@ export interface WebRuntimeConfig {
|
||||
|
||||
Source: [`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-app"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-app`
|
||||
|
||||
Requires: `webServer`
|
||||
@@ -2683,6 +2889,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/bundle/web-app/src/index.ts:38`](../packages/bundle/web-app/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-fetch-http"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-fetch-http`
|
||||
|
||||
Requires: `web`
|
||||
@@ -2707,6 +2915,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/web/web-fetch-http/src/index.ts:34`](../packages/web/web-fetch-http/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-search-deepseek"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-search-deepseek`
|
||||
|
||||
Requires: `web`
|
||||
@@ -2733,6 +2943,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/web/web-search-deepseek/src/index.ts:46`](../packages/web/web-search-deepseek/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-search-exa"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-search-exa`
|
||||
|
||||
Requires: `web`
|
||||
@@ -2755,6 +2967,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/web/web-search-exa/src/index.ts:38`](../packages/web/web-search-exa/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-search-perplexity"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-search-perplexity`
|
||||
|
||||
Requires: `web`
|
||||
@@ -2777,6 +2991,8 @@ export interface Config {
|
||||
|
||||
Source: [`packages/web/web-search-perplexity/src/index.ts:32`](../packages/web/web-search-perplexity/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-workflow-worker-thread"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-workflow-worker-thread`
|
||||
|
||||
Requires: `subagents`
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
`Requires:` 行列出插件通过 `inject` 注入的服务键:其 `cordis.yml` 树还必须加载这些服务的提供者。范围限定为 harness 层级(`packages/`);配置树还可能加载的 vendored cordis 插件(`hmr`、控制台日志记录器等)固定为上游源代码(参见 [vendoring policy](../vendor/README.md)),未收录于此目录。
|
||||
|
||||
<a id="deepseek-aidsh-acp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-acp`
|
||||
|
||||
需要:`agents`
|
||||
@@ -31,6 +33,8 @@ export interface AcpConfig {
|
||||
|
||||
来源:[`packages/acp/acp/src/index.ts:70`](../packages/acp/acp/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-acp-demo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-acp-demo`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -84,6 +88,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/examples/acp-demo/src/index.ts:39`](../packages/examples/acp-demo/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-default-model"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-default-model`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -98,6 +104,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/core/agent-default-model/src/index.ts:41`](../packages/core/agent-default-model/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-instructions"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-instructions`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -126,6 +134,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/context/agent-instructions/src/config.ts:18`](../packages/context/agent-instructions/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-loop"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-loop`
|
||||
|
||||
需要:`agents` · `sessions` · `llm` · `tools` · `systemPrompt`
|
||||
@@ -156,6 +166,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/core/agent-loop/src/index.ts:255`](../packages/core/agent-loop/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-presets"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-presets`
|
||||
|
||||
需要:`loader`
|
||||
@@ -192,6 +204,8 @@ export type PresetTrust = 'system' | 'user'
|
||||
|
||||
来源:[`packages/preset/agent-presets/src/preset.ts:52`](../packages/preset/agent-presets/src/preset.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-spine-demo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-spine-demo`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -282,6 +296,8 @@ export interface GoalConfig {
|
||||
|
||||
来源:[`packages/examples/agent-spine-demo/src/index.ts:92`](../packages/examples/agent-spine-demo/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-agent-tool-presentation"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-agent-tool-presentation`
|
||||
|
||||
需要:`tools`
|
||||
@@ -304,6 +320,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/core/agent-tool-presentation/src/index.ts:38`](../packages/core/agent-tool-presentation/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-attachment-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-attachment-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -324,6 +342,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/attachment/attachment-local/src/index.ts:24`](../packages/attachment/attachment-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-bash-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-bash-local`
|
||||
|
||||
需要:`subprocess`
|
||||
@@ -348,6 +368,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/shell/bash-local/src/index.ts:41`](../packages/shell/bash-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-bash-sandbox"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-bash-sandbox`
|
||||
|
||||
需要:`subprocess` · `sandbox` · `sandboxPolicy`
|
||||
@@ -367,6 +389,8 @@ export type Config = LocalConfig
|
||||
|
||||
来源:[`packages/shell/bash-sandbox/src/index.ts:35`](../packages/shell/bash-sandbox/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-client-connection"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-client-connection`
|
||||
|
||||
需要:`webServer`
|
||||
@@ -390,6 +414,8 @@ export interface ConnectionConfig {
|
||||
|
||||
来源:[`packages/client/connection/src/index.ts:50`](../packages/client/connection/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-client-hmr"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-client-hmr`
|
||||
|
||||
需要:`clientModuleHost` · `webServer`
|
||||
@@ -404,6 +430,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/client/hmr/src/index.ts:31`](../packages/client/hmr/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-code-runtime-worker-thread"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-code-runtime-worker-thread`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -439,6 +467,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/code-runtime/code-runtime-worker-thread/src/index.ts:25`](../packages/code-runtime/code-runtime-worker-thread/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-compaction-basic"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-compaction-basic`
|
||||
|
||||
需要:`llm` · `tokenMeter` · `sessions`
|
||||
@@ -483,6 +513,8 @@ export interface ModelCompactPolicyConfig extends CompactionPolicyConfig {
|
||||
|
||||
来源:[`packages/compaction/compaction-basic/src/types.ts:38`](../packages/compaction/compaction-basic/src/types.ts)
|
||||
|
||||
<a id="deepseek-aidsh-compaction-tool-result-pruner"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-compaction-tool-result-pruner`
|
||||
|
||||
需要:`tokenMeter`
|
||||
@@ -501,6 +533,8 @@ export interface ToolResultPruneConfig {
|
||||
|
||||
来源:[`packages/compaction/compaction-tool-result-pruner/src/types.ts:4`](../packages/compaction/compaction-tool-result-pruner/src/types.ts)
|
||||
|
||||
<a id="deepseek-aidsh-cordis-host-runner"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-cordis-host-runner`
|
||||
|
||||
需要:`tools`
|
||||
@@ -515,6 +549,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/extensions/cordis-host-runner/src/index.ts:88`](../packages/extensions/cordis-host-runner/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-credentials-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-credentials-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -533,6 +569,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/credentials/credentials-local/src/index.ts:55`](../packages/credentials/credentials-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-e2b"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-e2b`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -549,6 +587,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/e2b/e2b/src/index.ts:43`](../packages/e2b/e2b/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-fs-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-fs-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -566,6 +606,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/fs/fs-local/src/index.ts:41`](../packages/fs/fs-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-fs-sandbox"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-fs-sandbox`
|
||||
|
||||
需要:`sandboxPolicy`
|
||||
@@ -584,6 +626,8 @@ export type Config = LocalConfig
|
||||
|
||||
来源:[`packages/fs/fs-sandbox/src/index.ts:49`](../packages/fs/fs-sandbox/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-goal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-goal`
|
||||
|
||||
需要:`agents`
|
||||
@@ -598,6 +642,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/goal/goal/src/index.ts:116`](../packages/goal/goal/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-headless"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-headless`
|
||||
|
||||
需要:`agentDefaultModel` · `agents` · `sessions`
|
||||
@@ -612,6 +658,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/bundle/headless/src/index.ts:31`](../packages/bundle/headless/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-hooks-claude-code"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-hooks-claude-code`
|
||||
|
||||
需要:`bash`
|
||||
@@ -648,6 +696,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/hooks/hooks-claude-code/src/index.ts:45`](../packages/hooks/hooks-claude-code/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-hooks-codex"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-hooks-codex`
|
||||
|
||||
需要:`bash`
|
||||
@@ -673,6 +723,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/hooks/hooks-codex/src/index.ts:44`](../packages/hooks/hooks-codex/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-apiproxy"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-apiproxy`
|
||||
|
||||
需要:`agentDefaultModel` · `agents` · `attachments` · `directoryPicker` · `llm` · `sessions` · `subagents` · `sessionQuery` · `tools` · `userInteraction` · `workspace`
|
||||
@@ -694,11 +746,19 @@ export interface Config {
|
||||
* @default 6
|
||||
*/
|
||||
sessionExportCompressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
||||
/**
|
||||
* Maximum physical size of a cold Session artifact eligible for blankness
|
||||
* verification. Zero disables probes.
|
||||
* @default 1024
|
||||
*/
|
||||
coldBlankProbeMaxBytes?: number
|
||||
}
|
||||
```
|
||||
|
||||
来源:[`packages/host/apiproxy/src/index.ts:41`](../packages/host/apiproxy/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-directory-picker-browse"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-directory-picker-browse`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -711,6 +771,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/host/directory-picker-browse/src/index.ts:181`](../packages/host/directory-picker-browse/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-frontend-static"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-frontend-static`
|
||||
|
||||
需要:`webServer`
|
||||
@@ -725,6 +787,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/host/frontend-static/src/index.ts:28`](../packages/host/frontend-static/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-host-webserver"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-host-webserver`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -739,6 +803,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/host/webserver/src/index.ts:45`](../packages/host/webserver/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-invariants"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-invariants`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -755,6 +821,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/runtime-diagnostics/invariants/src/index.ts:15`](../packages/runtime-diagnostics/invariants/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-jobs-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-jobs-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -770,6 +838,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/jobs/jobs-local/src/index.ts:31`](../packages/jobs/jobs-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-deepseek"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-deepseek`
|
||||
|
||||
需要:`llm`
|
||||
@@ -823,6 +893,8 @@ export interface DeepSeekCatalogModel {
|
||||
|
||||
来源:[`packages/llm/llm-deepseek/src/index.ts:62`](../packages/llm/llm-deepseek/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-pi-ai"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-pi-ai`
|
||||
|
||||
需要:`llm`
|
||||
@@ -1011,6 +1083,8 @@ type WithheldThinkingFormat = 'chat-template' | 'qwen-chat-template'
|
||||
|
||||
来源:[`packages/llm/llm-pi-ai/src/config.ts:172`](../packages/llm/llm-pi-ai/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-replay"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-replay`
|
||||
|
||||
需要:`llm`
|
||||
@@ -1077,6 +1151,8 @@ export interface ReplayModelConfig {
|
||||
|
||||
来源:[`packages/test-support/llm-replay/src/index.ts:776`](../packages/test-support/llm-replay/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-llm-retry"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-llm-retry`
|
||||
|
||||
需要:`agents`
|
||||
@@ -1088,6 +1164,8 @@ export type Config = Readonly<Record<string, never>>
|
||||
|
||||
来源:[`packages/llm/llm-retry/src/index.ts:24`](../packages/llm/llm-retry/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-lsp-stdio"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-lsp-stdio`
|
||||
|
||||
需要:`fs` · `lsp` · `subprocess`
|
||||
@@ -1128,6 +1206,8 @@ export interface LspLocalServerConfig {
|
||||
|
||||
来源:[`packages/lsp/lsp-stdio/src/index.ts:82`](../packages/lsp/lsp-stdio/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-mcp-client"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-mcp-client`
|
||||
|
||||
需要:`tools`
|
||||
@@ -1199,6 +1279,8 @@ export interface ReconnectConfig {
|
||||
|
||||
来源:[`packages/mcp/mcp-client/src/index.ts:98`](../packages/mcp/mcp-client/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-message-feedback"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-message-feedback`
|
||||
|
||||
需要:`storageDomain` · `sessionPersistence` · `sessions`
|
||||
@@ -1213,6 +1295,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/feedback/message-feedback/src/index.ts:49`](../packages/feedback/message-feedback/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-permission-presets"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-permission-presets`
|
||||
|
||||
需要:`bash` · `approval` · `sessions`
|
||||
@@ -1250,6 +1334,8 @@ export interface PresetSpec {
|
||||
|
||||
来源:[`packages/interaction/permission-presets/src/index.ts:140`](../packages/interaction/permission-presets/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-persona"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-persona`
|
||||
|
||||
需要:`systemPrompt`
|
||||
@@ -1272,6 +1358,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/preset/persona/src/index.ts:34`](../packages/preset/persona/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-plan-mode"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-plan-mode`
|
||||
|
||||
需要:`tools` · `systemPrompt`
|
||||
@@ -1286,6 +1374,8 @@ export interface PlanModeConfig {
|
||||
|
||||
来源:[`packages/plan/plan-mode/src/index.ts:70`](../packages/plan/plan-mode/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-pwsh-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-pwsh-local`
|
||||
|
||||
需要:`subprocess`
|
||||
@@ -1317,6 +1407,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/shell/pwsh-local/src/index.ts:58`](../packages/shell/pwsh-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-pwsh-sandbox"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-pwsh-sandbox`
|
||||
|
||||
需要:`subprocess` · `sandbox` · `sandboxPolicy`
|
||||
@@ -1337,6 +1429,8 @@ export type Config = LocalConfig
|
||||
|
||||
来源:[`packages/shell/pwsh-sandbox/src/index.ts:40`](../packages/shell/pwsh-sandbox/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-repeat-tool-reminder"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-repeat-tool-reminder`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1369,6 +1463,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/guard/repeat-tool-reminder/src/index.ts:28`](../packages/guard/repeat-tool-reminder/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-sandbox-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-sandbox-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1399,6 +1495,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/sandbox/sandbox-local/src/index.ts:44`](../packages/sandbox/sandbox-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-sandbox-policy"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-sandbox-policy`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1424,6 +1522,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/sandbox/sandbox-policy/src/index.ts:67`](../packages/sandbox/sandbox-policy/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-sdk-jsonrpc-server"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-sdk-jsonrpc-server`
|
||||
|
||||
需要:`agents`
|
||||
@@ -1446,6 +1546,8 @@ export interface JsonRpcConfig {
|
||||
|
||||
来源:[`packages/sdk/server/src/index.ts:29`](../packages/sdk/server/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-persistence-jsonl"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-persistence-jsonl`
|
||||
|
||||
需要:`sessions`
|
||||
@@ -1483,6 +1585,8 @@ export type JsonlCompression = 'zstd' | 'none'
|
||||
|
||||
来源:[`packages/session/session-persistence-jsonl/src/index.ts:60`](../packages/session/session-persistence-jsonl/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-persistence-sqlite"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-persistence-sqlite`
|
||||
|
||||
需要:`sessions`
|
||||
@@ -1526,6 +1630,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist'
|
||||
|
||||
来源:[`packages/session/session-persistence-sqlite/src/index.ts:70`](../packages/session/session-persistence-sqlite/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-projection-cache"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-projection-cache`
|
||||
|
||||
需要:`storageDomain` · `sessionProjections` · `sessionPersistence` · `sessions`
|
||||
@@ -1547,6 +1653,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/session/session-projection-cache/src/index.ts:42`](../packages/session/session-projection-cache/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-query-sqlite"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-query-sqlite`
|
||||
|
||||
需要:`sessions`
|
||||
@@ -1591,6 +1699,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist'
|
||||
|
||||
来源:[`packages/session-query/session-query-sqlite/src/index.ts:89`](../packages/session-query/session-query-sqlite/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-reference"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-reference`
|
||||
|
||||
需要:`sessionQuery`
|
||||
@@ -1609,6 +1719,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/context/session-reference/src/config.ts:11`](../packages/context/session-reference/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-telemetry-otel"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-telemetry-otel`
|
||||
|
||||
需要:`sessions`
|
||||
@@ -1653,6 +1765,8 @@ export enum SessionTelemetryMode {
|
||||
|
||||
来源:[`packages/session/session-telemetry-otel/src/index.ts:91`](../packages/session/session-telemetry-otel/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-title"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-title`
|
||||
|
||||
需要:`sessions`
|
||||
@@ -1671,6 +1785,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/session/session-title/src/index.ts:79`](../packages/session/session-title/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-title-all-prompts-llm"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-title-all-prompts-llm`
|
||||
|
||||
需要:`sessionTitle` · `llm` · `sessions`
|
||||
@@ -1684,6 +1800,8 @@ export type Config = SessionTitleLlmConfig
|
||||
|
||||
来源:[`packages/session/session-title-all-prompts-llm/src/index.ts:15`](../packages/session/session-title-all-prompts-llm/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-session-title-first-prompt-llm"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-session-title-first-prompt-llm`
|
||||
|
||||
需要:`sessionTitle` · `llm` · `sessions`
|
||||
@@ -1697,6 +1815,8 @@ export type Config = SessionTitleLlmConfig
|
||||
|
||||
来源:[`packages/session/session-title-first-prompt-llm/src/index.ts:15`](../packages/session/session-title-first-prompt-llm/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-settings-file"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-settings-file`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1715,6 +1835,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/settings/settings-file/src/index.ts:21`](../packages/settings/settings-file/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-shell-env"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-shell-env`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1727,6 +1849,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/shell/shell-env/src/index.ts:29`](../packages/shell/shell-env/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-skill"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-skill`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1739,6 +1863,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/skill/skill/src/index.ts:279`](../packages/skill/skill/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-skill-filesystem"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-skill-filesystem`
|
||||
|
||||
需要:`skills`
|
||||
@@ -1775,6 +1901,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/skill/skill-filesystem/src/index.ts:49`](../packages/skill/skill-filesystem/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-spill-local"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-spill-local`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -1791,6 +1919,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/spill/spill-local/src/index.ts:22`](../packages/spill/spill-local/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-spill-policy"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-spill-policy`
|
||||
|
||||
需要:`tools`
|
||||
@@ -1809,6 +1939,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/spill/spill-policy/src/index.ts:60`](../packages/spill/spill-policy/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-storage-domain"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-storage-domain`
|
||||
|
||||
需要:`storage`
|
||||
@@ -1830,6 +1962,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/storage/storage-domain/src/index.ts:52`](../packages/storage/storage-domain/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-storage-json"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-storage-json`
|
||||
|
||||
需要:`storage`
|
||||
@@ -1849,6 +1983,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/storage/storage-json/src/index.ts:27`](../packages/storage/storage-json/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-storage-sqlite"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-storage-sqlite`
|
||||
|
||||
需要:`storage`
|
||||
@@ -1887,6 +2023,8 @@ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist'
|
||||
|
||||
来源:[`packages/storage/storage-sqlite/src/index.ts:24`](../packages/storage/storage-sqlite/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-acp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-acp`
|
||||
|
||||
需要:`subagents` · `subprocess`
|
||||
@@ -1938,6 +2076,8 @@ export type PermissionPolicy = 'allow' | 'reject'
|
||||
|
||||
来源:[`packages/subagent/subagent-acp/src/index.ts:27`](../packages/subagent/subagent-acp/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-claude-code"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-claude-code`
|
||||
|
||||
需要:`subagents` · `subprocess`
|
||||
@@ -1957,6 +2097,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/subagent-claude-code/src/index.ts:32`](../packages/subagent/subagent-claude-code/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-codex"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-codex`
|
||||
|
||||
需要:`subagents` · `subprocess`
|
||||
@@ -1976,6 +2118,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/subagent-codex/src/index.ts:30`](../packages/subagent/subagent-codex/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-dsh-sdk"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-dsh-sdk`
|
||||
|
||||
需要:`subagents`
|
||||
@@ -2027,6 +2171,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/subagent-dsh-sdk/src/index.ts:29`](../packages/subagent/subagent-dsh-sdk/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-fork-in-process"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-fork-in-process`
|
||||
|
||||
需要:`subagents`
|
||||
@@ -2041,6 +2187,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/subagent-fork-in-process/src/index.ts:31`](../packages/subagent/subagent-fork-in-process/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subagent-spawn-in-process"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subagent-spawn-in-process`
|
||||
|
||||
需要:`subagents`
|
||||
@@ -2055,6 +2203,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/subagent-spawn-in-process/src/index.ts:25`](../packages/subagent/subagent-spawn-in-process/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-subprocess-e2b"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-subprocess-e2b`
|
||||
|
||||
需要:`e2b`
|
||||
@@ -2069,6 +2219,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/e2b/subprocess-e2b/src/index.ts:25`](../packages/e2b/subprocess-e2b/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-system-prompt"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-system-prompt`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2094,6 +2246,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/core/system-prompt/src/index.ts:186`](../packages/core/system-prompt/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-terminal-bash"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-terminal-bash`
|
||||
|
||||
需要:`pty` · `sandboxPolicy` · `subprocess`
|
||||
@@ -2137,6 +2291,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/terminal/terminal-bash/src/config.ts:6`](../packages/terminal/terminal-bash/src/config.ts)
|
||||
|
||||
<a id="deepseek-aidsh-time-context"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-time-context`
|
||||
|
||||
需要:`agents`
|
||||
@@ -2153,6 +2309,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/context/time-context/src/index.ts:27`](../packages/context/time-context/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tmux-context"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tmux-context`
|
||||
|
||||
需要:`agents`
|
||||
@@ -2167,6 +2325,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/context/tmux-context/src/index.ts:34`](../packages/context/tmux-context/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-token-meter"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-token-meter`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2176,6 +2336,8 @@ export type TokenMeterConfig = Record<string, never>
|
||||
|
||||
来源:[`packages/llm/token-meter/src/types.ts:12`](../packages/llm/token-meter/src/types.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash`
|
||||
|
||||
需要:`tools` · `bash` · `systemPrompt` · `bashEnv`
|
||||
@@ -2190,6 +2352,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/shell/tool-bash/src/index.ts:34`](../packages/shell/tool-bash/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash-persistent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash-persistent`
|
||||
|
||||
需要:`tools` · `pty`
|
||||
@@ -2210,6 +2374,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/shell/tool-bash-persistent/src/index.ts:405`](../packages/shell/tool-bash-persistent/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs`
|
||||
|
||||
需要:`tools` · `fs` · `systemPrompt`
|
||||
@@ -2230,6 +2396,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/fs/tool-fs/src/index.ts:25`](../packages/fs/tool-fs/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs-search"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs-search`
|
||||
|
||||
需要:`tools` · `systemPrompt` · `subprocess`
|
||||
@@ -2263,6 +2431,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/fs/tool-fs-search/src/index.ts:73`](../packages/fs/tool-fs-search/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-goal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-goal`
|
||||
|
||||
需要:`agents` · `goals` · `tools` · `systemPrompt`
|
||||
@@ -2277,6 +2447,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/goal/tool-goal/src/index.ts:26`](../packages/goal/tool-goal/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-jobs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-jobs`
|
||||
|
||||
需要:`tools` · `tasks` · `systemPrompt`
|
||||
@@ -2309,6 +2481,8 @@ export type CompletionDelivery = 'quiet' | 'wakeup'
|
||||
|
||||
来源:[`packages/jobs/tool-jobs/src/index.ts:32`](../packages/jobs/tool-jobs/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-lsp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-lsp`
|
||||
|
||||
需要:`tools` · `lsp` · `systemPrompt`
|
||||
@@ -2327,6 +2501,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/lsp/tool-lsp/src/index.ts:58`](../packages/lsp/tool-lsp/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-pwsh"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-pwsh`
|
||||
|
||||
需要:`tools` · `bash` · `systemPrompt` · `bashEnv`
|
||||
@@ -2341,6 +2517,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/shell/tool-pwsh/src/index.ts:52`](../packages/shell/tool-pwsh/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-ralph"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ralph`
|
||||
|
||||
需要:`tools` · `workflows` · `subagents` · `systemPrompt`
|
||||
@@ -2361,6 +2539,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/workflow/tool-ralph/src/index.ts:23`](../packages/workflow/tool-ralph/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-session-query"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-session-query`
|
||||
|
||||
需要:`tools` · `systemPrompt` · `sessionQuery`
|
||||
@@ -2377,6 +2557,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/session-query/tool-session-query/src/index.ts:29`](../packages/session-query/tool-session-query/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-skill"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-skill`
|
||||
|
||||
需要:`agents` · `tools` · `skills`
|
||||
@@ -2391,6 +2573,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/skill/tool-skill/src/index.ts:61`](../packages/skill/tool-skill/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-str-replace-editor"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-str-replace-editor`
|
||||
|
||||
需要:`tools` · `fs`
|
||||
@@ -2407,6 +2591,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/fs/tool-str-replace-editor/src/index.ts:497`](../packages/fs/tool-str-replace-editor/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent`
|
||||
|
||||
需要:`tools` · `subagents` · `systemPrompt`
|
||||
@@ -2470,6 +2656,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/tool-subagent/src/index.ts:29`](../packages/subagent/tool-subagent/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent-report"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent-report`
|
||||
|
||||
需要:`subagents` · `tools` · `systemPrompt`
|
||||
@@ -2490,6 +2678,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/subagent/tool-subagent-report/src/index.ts:27`](../packages/subagent/tool-subagent-report/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-terminal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-terminal`
|
||||
|
||||
需要:`pty` · `tools` · `systemPrompt`
|
||||
@@ -2506,6 +2696,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/terminal/tool-terminal/src/index.ts:35`](../packages/terminal/tool-terminal/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-todo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-todo`
|
||||
|
||||
需要:`tools`
|
||||
@@ -2526,6 +2718,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/todo/tool-todo/src/index.ts:29`](../packages/todo/tool-todo/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-web"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-web`
|
||||
|
||||
需要:`tools` · `web` · `systemPrompt`
|
||||
@@ -2550,6 +2744,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/web/tool-web/src/index.ts:37`](../packages/web/tool-web/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-workflow"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-workflow`
|
||||
|
||||
需要:`tools` · `workflows` · `systemPrompt`
|
||||
@@ -2566,6 +2762,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/workflow/tool-workflow/src/index.ts:33`](../packages/workflow/tool-workflow/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tools"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tools`
|
||||
|
||||
需要:`systemPrompt`
|
||||
@@ -2600,6 +2798,8 @@ export type ToolPresentationMode = 'native' | 'code' | 'both'
|
||||
|
||||
来源:[`packages/core/tools/src/index.ts:654`](../packages/core/tools/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-typert-loader"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-typert-loader`
|
||||
|
||||
需要:`typert` · `loader`
|
||||
@@ -2614,6 +2814,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/typert/loader/src/index.ts:47`](../packages/typert/loader/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-user-approval"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-user-approval`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2643,6 +2845,8 @@ export type ApprovalPolicy = 'ask' | 'never'
|
||||
|
||||
来源:[`packages/interaction/user-approval/src/index.ts:177`](../packages/interaction/user-approval/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web`
|
||||
|
||||
```ts config-catalog
|
||||
@@ -2662,6 +2866,8 @@ export interface WebRuntimeConfig {
|
||||
|
||||
来源:[`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-app"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-app`
|
||||
|
||||
需要:`webServer`
|
||||
@@ -2685,6 +2891,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/bundle/web-app/src/index.ts:38`](../packages/bundle/web-app/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-fetch-http"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-fetch-http`
|
||||
|
||||
需要:`web`
|
||||
@@ -2709,6 +2917,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/web/web-fetch-http/src/index.ts:34`](../packages/web/web-fetch-http/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-search-deepseek"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-search-deepseek`
|
||||
|
||||
需要:`web`
|
||||
@@ -2735,6 +2945,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/web/web-search-deepseek/src/index.ts:46`](../packages/web/web-search-deepseek/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-search-exa"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-search-exa`
|
||||
|
||||
需要:`web`
|
||||
@@ -2757,6 +2969,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/web/web-search-exa/src/index.ts:38`](../packages/web/web-search-exa/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-web-search-perplexity"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-web-search-perplexity`
|
||||
|
||||
需要:`web`
|
||||
@@ -2779,6 +2993,8 @@ export interface Config {
|
||||
|
||||
来源:[`packages/web/web-search-perplexity/src/index.ts:32`](../packages/web/web-search-perplexity/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-workflow-worker-thread"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-workflow-worker-thread`
|
||||
|
||||
需要:`subagents`
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cookbook/adding-a-tool.md
|
||||
adding-a-tool.md: 37516521de4d00de964003fd6f877831774fdcd3
|
||||
adding-a-tool.zh.md: 9455fa3b8d8b87632724ad4b035f184cb0c17993
|
||||
adding-a-tool.zh.md: 27a90ce19653333a0a6afd989115e614a1c8f9f4
|
||||
@@ -54,6 +54,8 @@ export function apply(ctx: Context) {
|
||||
|
||||
producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 `done`,以及可选的消费式 `readOutput`(负责有界输出的格式化)。预先中止的调用属于失败,因为此时没有任务,其 id 无法满足成功输出 schema。`ctx.jobs.start()` 发布 id 后,应使用任务自有的取消信号,而不是 `exec.signal`:之后取消外层调用只会停止等待本次调用,不会终止已经发布的工作;该生命周期归 `job_kill`、owner dispose 和服务 teardown 所有。前台工作仍与 `exec.signal` 耦合。流式 producer 的示例和完整约定见[后台任务运行时 Agent Note](../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md)与 `dsh-tool-bash`。
|
||||
|
||||
<a id="execution-policy-and-observation"></a>
|
||||
|
||||
## 执行策略与观测
|
||||
|
||||
尽量不要把部署策略内建到工具中。使用 `tools/pre-execute` 实现可扩展的允许/拒绝/询问策略(见[权限门禁示例](extension-cookbook.md#a-hook-plugin-permission-gate-example));使用 `ctx.tools.guard()` 设置最终的单调拒绝,后续监听器无法撤销;使用 `tools/execute` 为分发添加截止时间、重试或指标收集;使用 `tools/post-execute` 替换展示内容或返回值、阻止结果,或附加模型可见上下文;使用 `tools/result` 观测不可变的归一化结果而不改变它。替换内容不会阻止程序化访问 `value`;保密策略会屏蔽或替换该值。沙箱实现也可以在工具的执行器实现中运行;[`dsh-tools` README](../../packages/core/tools/README.md#extension-points) 定义每个扩展点的输入、顺序、返回值和失败行为。
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cookbook/extension-cookbook.md
|
||||
extension-cookbook.md: 9618a3522c5566636fe3e49f7eca93d1e113d51a
|
||||
extension-cookbook.zh.md: 7b82d7d1ff239cc2139ee424613e818669f3e2e8
|
||||
extension-cookbook.zh.md: 540bc6867016d095ccae0fb0fdc79bc1b1c26290
|
||||
@@ -8,6 +8,8 @@ harness 扩展的参考模式。代码片段省略了 import 和辅助实现,
|
||||
|
||||
工具在 `ctx.tools` 上注册。带注解的 `defineTool` 示例(类型化的 `execute` 参数、结果构造、`run_in_background` 模式)见 [adding-a-tool.md](adding-a-tool.md)——该指南是工具定义的真源。`ctx.tools.register()` 也直接接受原始 JSON Schema `ToolDefinition`(MCP 来源的工具就是这样到达的);`defineTool` 是第一方工具使用的类型化辅助函数。
|
||||
|
||||
<a id="a-hook-plugin-permission-gate-example"></a>
|
||||
|
||||
## 钩子插件(以权限门禁为例)
|
||||
|
||||
这个权限门禁是钩子插件的一个示例。它从 `tools/pre-execute` 门禁返回一个类型化的决策,用于允许或拒绝一次调用;沙箱、权限和 plan-mode 插件都可以使用该扩展点。钩子插件也可以拦截其他扩展点,本身并不等同于权限门禁。「原生钩子」是在拦截点上运行的普通 Cordis 插件,不需要外部协议。
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cordis-primer.md
|
||||
cordis-primer.md: 2a3afe180623d89b006dfa3e73aba5567c15bbe9
|
||||
cordis-primer.zh.md: bdce14cf9f157959d6419f88c9c69570102b9c0c
|
||||
cordis-primer.zh.md: d4d60f60717ffdc01499fdffadba2808557b285f
|
||||
@@ -12,6 +12,8 @@ Cordis 是 DeepSeek Harness 底层以 vendor 方式引入的插件框架。本
|
||||
- **类型化事件用于通信。** 服务通过 TypeScript 声明合并注册事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel` 或 `serial` 方式分发,分别对应监听者观察、包装、并行扇出或按序执行。
|
||||
- **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()` 或 `ctx.on()` 安装,reload 和 teardown 时会按预期撤销。
|
||||
|
||||
<a id="dispatch-modes"></a>
|
||||
|
||||
## 分发模式
|
||||
|
||||
每个事件具有以下分发模式之一,且只能通过对应方法分发。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cordis-tutorial/03-services.md
|
||||
03-services.md: 32007284be99ef46b4621089c9b3a80317e77189
|
||||
03-services.zh.md: d82be29aa69686b8dc10cc6a45a658683c017cbd
|
||||
03-services.md: ebfc400dbbc701a3c164c7d30c371dec879d7d73
|
||||
03-services.zh.md: fcfd8be7f7fe654a4f4943cf591b5ab7bfc27fc6
|
||||
@@ -75,7 +75,7 @@ Swap the two lines in `cordis.yml` and rerun: same output. Try removing `./greet
|
||||
|
||||
`inject` is not a one-shot boot check. If a required service disappears while the app runs — its provider was unloaded or hot-replaced — every dependent plugin is unloaded too, and loads again when the service returns. Combined with effects ([chapter 2](02-lifecycle-and-effects.md)), this prevents a running consumer from retaining a reference to an unavailable service: its own registrations are unwound when the dependency disappears.
|
||||
|
||||
This is also why service replacement works in config: unload the `dsh-bash-local` entry, mount a different `bash` provider, and every plugin injecting `'bash'` cleanly restarts against the new implementation.
|
||||
This is also why service replacement works in config: unload the `dsh-bash-local` entry, mount a different `shell` provider, and every plugin injecting `'shell'` cleanly restarts against the new implementation.
|
||||
|
||||
## Optional dependencies
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ Hello, world!
|
||||
|
||||
`inject` 并非一次性的启动检查。如果应用运行期间所需服务消失,例如提供方被卸载或热替换,每个依赖插件也会随之卸载,并在服务恢复后再次加载。结合 effect([第 2 章](02-lifecycle-and-effects.md)),这能防止运行中的消费方保留对不可用服务的引用:依赖消失时,它自己的注册也会撤销。
|
||||
|
||||
这也是配置中可以替换服务的原因:卸载 Cordis 配置项 `dsh-bash-local`,挂载另一个 `bash` 提供方,所有注入 `'bash'` 的插件都会重新启动并使用新实现。
|
||||
这也是配置中可以替换服务的原因:卸载 Cordis 配置项 `dsh-bash-local`,挂载另一个 `shell` 提供方,所有注入 `'shell'` 的插件都会重新启动并使用新实现。
|
||||
|
||||
## 可选依赖
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cordis-tutorial/06-composition-and-hmr.md
|
||||
06-composition-and-hmr.md: 87ea26014657ae8c8199e1ebb486556c827d96ca
|
||||
06-composition-and-hmr.zh.md: 830f55de7c1be351fe701cb068197543602619a7
|
||||
06-composition-and-hmr.md: 2b53aa28be99851e77a71de76337f2beb4003e8d
|
||||
06-composition-and-hmr.zh.md: cd4afa1d5465a5442bfd6b771ebcd61c46fe2983
|
||||
@@ -18,7 +18,7 @@ A config entry accepts metadata beyond `name` and `config`:
|
||||
|
||||
`id` gives the entry a stable identity so the loader can tell an edit to an existing entry apart from a removal plus an addition. `disabled: true` unmounts a plugin without deleting its entry — flip it back and the plugin (and everything PENDING on its services) loads again.
|
||||
|
||||
Groups nest a sub-list of entries that load and unload as one unit, and `isolate` gives a group its own instance of a service name — two groups can each see a differently-configured `bash` without affecting each other. The [Cordis primer](../cordis-primer.md) and the [service isolation example](../user/develop/framework/service.md#service-isolation) cover the details.
|
||||
Groups nest a sub-list of entries that load and unload as one unit, and `isolate` gives a group its own instance of a service name — two groups can each see a differently configured `shell` provider without affecting each other. The [Cordis primer](../cordis-primer.md) and the [service isolation example](../user/develop/framework/service.md#service-isolation) cover the details.
|
||||
|
||||
## Hot module replacement
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Cordis 配置项除了 `name` 和 `config`,还接受其他元数据:
|
||||
|
||||
`id` 为 Cordis 配置项提供稳定标识,使 loader 能区分修改现有 Cordis 配置项与先删除再添加。`disabled: true` 会卸载插件而不删除其 Cordis 配置项;改回原值后,插件以及所有因依赖其服务而处于 PENDING 的插件都会再次加载。
|
||||
|
||||
组可以嵌套一份 Cordis 配置项子列表,并将其作为一个单元加载和卸载;`isolate` 则为一个组提供某项服务名称的独立实例,因此两个组可以各自看到配置不同的 `bash`,互不影响。[Cordis 入门](../cordis-primer.md)和[服务隔离示例](../user/develop/framework/service.md#service-isolation)介绍了详细内容。
|
||||
组可以嵌套一份 Cordis 配置项子列表,并将其作为一个单元加载和卸载;`isolate` 则为一个组提供某项服务名称的独立实例,因此两个组可以各自看到配置不同的 `shell` 提供方,互不影响。[Cordis 入门](../cordis-primer.md)和[服务隔离示例](../user/develop/framework/service.md#service-isolation)介绍了详细内容。
|
||||
|
||||
## 热模块替换
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cordis-tutorial/index.md
|
||||
index.md: c51965e186ce8d78b577c1005c1c3e1831b91be1
|
||||
index.zh.md: 8811930eba0f3e24ecbc47521e65582502257473
|
||||
index.zh.md: 22e1918672a34219ca0cf5efaa43a8eb693e6996
|
||||
@@ -10,6 +10,8 @@ Cordis 是 DeepSeek Harness 底层的插件框架:它是一个小型运行时
|
||||
|
||||
如果你要为 harness 本身编写插件——由 `cordis.yml` 加载、在 Web UI 中驱动,而不是下面这个启动器——请从[第一个 Harness 插件](../user/develop/basic/index.md)开始。
|
||||
|
||||
<a id="setup"></a>
|
||||
|
||||
## 准备工作
|
||||
|
||||
你需要克隆本仓库并安装依赖;[开发指南](../development.md#setup-tutorial)列出了前置条件。本教程不需要 API 密钥;所有示例均可在无密钥环境中运行。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/defensive-patterns.md
|
||||
defensive-patterns.md: b6e643cad6180ea35a363f2c4131b2c24f5f70af
|
||||
defensive-patterns.zh.md: e1a6abdfd2138a51a13ceaf418bf6df1d0c65579
|
||||
defensive-patterns.md: 9db582354628a13abd43c5bd052dbbfd6e52f79f
|
||||
defensive-patterns.zh.md: 7bebbe3c1964f2b826afc523eaa4af7be180e36e
|
||||
@@ -27,3 +27,7 @@ A user-supplied listener that throws must not reject the promise it runs inside
|
||||
## Never hand untrusted output the ambient environment or predictable paths
|
||||
|
||||
Spawned commands get a scrubbed env (drop `*KEY*`/`*SECRET*`/`*TOKEN*`/`*PASSWORD*`) so harness credentials cannot leak into output, `env`, or spill files. Temp/spill files use a private (0700) dir, random names, and exclusive owner-only opens (`'wx'`, `0o600`) — predictable world-readable paths invite symlink races and disclosure.
|
||||
|
||||
## Unlink link-shaped paths
|
||||
|
||||
A path that may be a symlink or Windows junction is removed with `lstatSync().isSymbolicLink()` then `unlinkSync`: unlink deletes only the link and refuses a real directory, so it never follows the link into its target. Windows `rmSync(link)` throws `ERR_FS_EISDIR` on a junction; recursive deletion may descend through one into its target. Reserve recursive `rmSync` for known real directories.
|
||||
@@ -26,4 +26,8 @@
|
||||
|
||||
## 绝不将环境变量或可预测路径暴露给不可信输出
|
||||
|
||||
启动的命令应使用经过清理的环境变量,移除名称匹配 `*KEY*`、`*SECRET*`、`*TOKEN*` 或 `*PASSWORD*` 的项,防止 harness 凭证通过命令输出、`env` 或 spill 文件泄漏。临时文件和 spill 文件应放在权限为 0700 的私有目录中,使用随机文件名,并以独占且仅所有者可访问的方式打开(`'wx'`、`0o600`);可预测且所有用户均可读的路径会引发符号链接竞态和信息泄露。
|
||||
启动的命令应使用经过清理的环境变量,移除名称匹配 `*KEY*`、`*SECRET*`、`*TOKEN*` 或 `*PASSWORD*` 的项,防止 harness 凭证通过命令输出、`env` 或 spill 文件泄漏。临时文件和 spill 文件应放在权限为 0700 的私有目录中,使用随机文件名,并以独占且仅所有者可访问的方式打开(`'wx'`、`0o600`);可预测且全局可读的路径会引发符号链接竞态和信息泄露。
|
||||
|
||||
## 用 unlink 删除链接形态的路径
|
||||
|
||||
可能是符号链接或 Windows junction 的路径,应先用 `lstatSync().isSymbolicLink()` 判断,再用 `unlinkSync` 删除:unlink 只删除链接本身并拒绝真实目录,因此绝不会跟随链接进入其目标。Windows 上对 junction 调用 `rmSync(link)` 会抛 `ERR_FS_EISDIR`;递归删除可能穿过 junction 进入其目标。真实目录才使用带 `recursive` 的 `rmSync`。
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/persistence-catalog.md
|
||||
persistence-catalog.md: 032f7ae45d05b688fd317e9aa46363f658f19b76
|
||||
persistence-catalog.zh.md: 4f3ace46f7abb2d87be1cd66cbead0ac6b0cccda
|
||||
persistence-catalog.md: c400298f7d37c590918820bcbda10e6550f197e8
|
||||
persistence-catalog.zh.md: 65ec0e3fbdd226c51a371dc9a90f10db5c929c7a
|
||||
@@ -96,6 +96,8 @@ Sources: [`packages/core/session/src/types.ts:336`](../packages/core/session/src
|
||||
|
||||
### `agent/*`
|
||||
|
||||
<a id="agentinboxspliced--log-only"></a>
|
||||
|
||||
#### `agent/inbox/spliced` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -117,6 +119,8 @@ Source: [`packages/core/agent/src/types.ts:19`](../packages/core/agent/src/types
|
||||
|
||||
### `agent-preset/*`
|
||||
|
||||
<a id="agent-presetselected--log-only"></a>
|
||||
|
||||
#### `agent-preset/selected` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -133,6 +137,8 @@ Source: [`packages/preset/agent-presets/src/session.ts:26`](../packages/preset/a
|
||||
|
||||
### `approval/*`
|
||||
|
||||
<a id="approvalasked--log-only"></a>
|
||||
|
||||
#### `approval/asked` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -156,6 +162,8 @@ Types: [CallId](subsystems/core.md)
|
||||
|
||||
Source: [`packages/interaction/user-approval/src/index.ts:44`](../packages/interaction/user-approval/src/index.ts)
|
||||
|
||||
<a id="approvaldecided--log-only"></a>
|
||||
|
||||
#### `approval/decided` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -172,6 +180,8 @@ Source: [`packages/interaction/user-approval/src/index.ts:44`](../packages/inter
|
||||
|
||||
Source: [`packages/interaction/user-approval/src/index.ts:55`](../packages/interaction/user-approval/src/index.ts)
|
||||
|
||||
<a id="approvalpolicy--log-only"></a>
|
||||
|
||||
#### `approval/policy` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -194,6 +204,8 @@ Source: [`packages/interaction/user-approval/src/index.ts:67`](../packages/inter
|
||||
|
||||
### `assistant/*`
|
||||
|
||||
<a id="assistantchunk--log-only"></a>
|
||||
|
||||
#### `assistant/chunk` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -205,6 +217,8 @@ Types: [StreamChunk](subsystems/llm-streaming.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:266`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="assistantmessage--surface"></a>
|
||||
|
||||
#### `assistant/message` — surface
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -223,6 +237,8 @@ Source: [`packages/core/session/src/types.ts:273`](../packages/core/session/src/
|
||||
|
||||
### `command/*`
|
||||
|
||||
<a id="commanddone--log-only"></a>
|
||||
|
||||
#### `command/done` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -242,6 +258,8 @@ Source: [`packages/core/session/src/types.ts:273`](../packages/core/session/src/
|
||||
|
||||
Source: [`packages/interaction/commands/src/types.ts:95`](../packages/interaction/commands/src/types.ts)
|
||||
|
||||
<a id="commandrun--log-only"></a>
|
||||
|
||||
#### `command/run` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -262,6 +280,8 @@ Source: [`packages/interaction/commands/src/types.ts:88`](../packages/interactio
|
||||
|
||||
### `compaction/*`
|
||||
|
||||
<a id="compactionend--log-only"></a>
|
||||
|
||||
#### `compaction/end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -274,6 +294,8 @@ Source: [`packages/interaction/commands/src/types.ts:88`](../packages/interactio
|
||||
|
||||
Source: [`packages/compaction/compaction/src/types.ts:71`](../packages/compaction/compaction/src/types.ts)
|
||||
|
||||
<a id="compactionprune--log-only"></a>
|
||||
|
||||
#### `compaction/prune` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -298,6 +320,8 @@ Source: [`packages/compaction/compaction/src/types.ts:71`](../packages/compactio
|
||||
|
||||
Source: [`packages/compaction/compaction/src/types.ts:81`](../packages/compaction/compaction/src/types.ts)
|
||||
|
||||
<a id="compactionstart--log-only"></a>
|
||||
|
||||
#### `compaction/start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -311,6 +335,8 @@ Source: [`packages/compaction/compaction/src/types.ts:81`](../packages/compactio
|
||||
|
||||
Source: [`packages/compaction/compaction/src/types.ts:23`](../packages/compaction/compaction/src/types.ts)
|
||||
|
||||
<a id="compactionsummary--log-only"></a>
|
||||
|
||||
#### `compaction/summary` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -365,6 +391,8 @@ Source: [`packages/compaction/compaction/src/types.ts:33`](../packages/compactio
|
||||
|
||||
### `feedback/*`
|
||||
|
||||
<a id="feedbackrecord--log-only"></a>
|
||||
|
||||
#### `feedback/record` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -379,6 +407,8 @@ Source: [`packages/feedback/command-feedback/src/index.ts:62`](../packages/feedb
|
||||
|
||||
### `goal/*`
|
||||
|
||||
<a id="goalchange--log-only"></a>
|
||||
|
||||
#### `goal/change` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -392,6 +422,8 @@ Source: [`packages/goal/goal/src/domain.ts:66`](../packages/goal/goal/src/domain
|
||||
|
||||
### `hook/*`
|
||||
|
||||
<a id="hookinvoked--log-only"></a>
|
||||
|
||||
#### `hook/invoked` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -415,6 +447,8 @@ Source: [`packages/goal/goal/src/domain.ts:66`](../packages/goal/goal/src/domain
|
||||
|
||||
Source: [`packages/hooks/hook-protocol/src/types.ts:19`](../packages/hooks/hook-protocol/src/types.ts)
|
||||
|
||||
<a id="hookresult--log-only"></a>
|
||||
|
||||
#### `hook/result` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -438,6 +472,8 @@ Source: [`packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook-
|
||||
|
||||
### `llm/*`
|
||||
|
||||
<a id="llmretry--log-only"></a>
|
||||
|
||||
#### `llm/retry` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -447,6 +483,8 @@ Source: [`packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook-
|
||||
|
||||
Source: [`packages/llm/llm-retry/src/types.ts:9`](../packages/llm/llm-retry/src/types.ts)
|
||||
|
||||
<a id="llmretry-started--log-only"></a>
|
||||
|
||||
#### `llm/retry-started` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -458,6 +496,8 @@ Source: [`packages/llm/llm-retry/src/types.ts:11`](../packages/llm/llm-retry/src
|
||||
|
||||
### `permission/*`
|
||||
|
||||
<a id="permissionpreset--log-only"></a>
|
||||
|
||||
#### `permission/preset` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -474,6 +514,8 @@ Source: [`packages/interaction/permission-presets/src/index.ts:50`](../packages/
|
||||
|
||||
### `plan/*`
|
||||
|
||||
<a id="planmode--log-only"></a>
|
||||
|
||||
#### `plan/mode` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -489,6 +531,8 @@ Source: [`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/s
|
||||
|
||||
### `request/*`
|
||||
|
||||
<a id="requestcontext--log-only"></a>
|
||||
|
||||
#### `request/context` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -501,6 +545,8 @@ Source: [`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/s
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:309`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="requestheader--log-only"></a>
|
||||
|
||||
#### `request/header` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -515,6 +561,8 @@ Source: [`packages/core/session/src/types.ts:304`](../packages/core/session/src/
|
||||
|
||||
### `sandbox/*`
|
||||
|
||||
<a id="sandboxmode--log-only"></a>
|
||||
|
||||
#### `sandbox/mode` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -536,6 +584,8 @@ Source: [`packages/sandbox/sandbox-policy/src/session-mode.ts:33`](../packages/s
|
||||
|
||||
### `schedule/*`
|
||||
|
||||
<a id="schedulechange--log-only"></a>
|
||||
|
||||
#### `schedule/change` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -552,6 +602,8 @@ Source: [`packages/schedule/schedule/src/types.ts:219`](../packages/schedule/sch
|
||||
|
||||
### `session/*`
|
||||
|
||||
<a id="sessionend-seed--log-only"></a>
|
||||
|
||||
#### `session/end-seed` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -582,6 +634,8 @@ Source: [`packages/schedule/schedule/src/types.ts:219`](../packages/schedule/sch
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="sessiontitle--log-only"></a>
|
||||
|
||||
#### `session/title` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -596,6 +650,8 @@ Types: [SessionTitleEventData](subsystems/session-title.md)
|
||||
|
||||
Source: [`packages/session/session-title/src/index.ts:100`](../packages/session/session-title/src/index.ts)
|
||||
|
||||
<a id="sessiontitle-llm-request--log-only"></a>
|
||||
|
||||
#### `session/title-llm-request` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -609,6 +665,8 @@ Source: [`packages/session/session-title-llm/src/index.ts:43`](../packages/sessi
|
||||
|
||||
### `step/*`
|
||||
|
||||
<a id="stepend--log-only"></a>
|
||||
|
||||
#### `step/end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -618,6 +676,8 @@ Source: [`packages/session/session-title-llm/src/index.ts:43`](../packages/sessi
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="stepstart--log-only"></a>
|
||||
|
||||
#### `step/start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -629,6 +689,8 @@ Source: [`packages/core/session/src/types.ts:254`](../packages/core/session/src/
|
||||
|
||||
### `subagent/*`
|
||||
|
||||
<a id="subagentdescriptor--log-only"></a>
|
||||
|
||||
#### `subagent/descriptor` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -646,6 +708,8 @@ Source: [`packages/subagent/subagent/src/descriptor.ts:37`](../packages/subagent
|
||||
|
||||
### `todo/*`
|
||||
|
||||
<a id="todowrite--log-only"></a>
|
||||
|
||||
#### `todo/write` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -659,6 +723,8 @@ Source: [`packages/core/session/src/types.ts:299`](../packages/core/session/src/
|
||||
|
||||
### `tool/*`
|
||||
|
||||
<a id="toolcall--log-only"></a>
|
||||
|
||||
#### `tool/call` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -674,6 +740,8 @@ Types: [CallId](subsystems/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:279`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="toolcode-dispatch--log-only"></a>
|
||||
|
||||
#### `tool/code-dispatch` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -697,6 +765,8 @@ Source: [`packages/core/session/src/types.ts:279`](../packages/core/session/src/
|
||||
|
||||
Source: [`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types.ts)
|
||||
|
||||
<a id="toolcode-dispatch-start--log-only"></a>
|
||||
|
||||
#### `tool/code-dispatch-start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -718,6 +788,8 @@ Source: [`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types
|
||||
|
||||
Source: [`packages/core/tools/src/types.ts:40`](../packages/core/tools/src/types.ts)
|
||||
|
||||
<a id="toolresult--surface"></a>
|
||||
|
||||
#### `tool/result` — surface
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -745,6 +817,8 @@ Source: [`packages/core/session/src/types.ts:291`](../packages/core/session/src/
|
||||
|
||||
### `tool-workflow/*`
|
||||
|
||||
<a id="tool-workflowagent-end--log-only"></a>
|
||||
|
||||
#### `tool-workflow/agent-end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -757,6 +831,8 @@ Source: [`packages/core/session/src/types.ts:291`](../packages/core/session/src/
|
||||
|
||||
Source: [`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow/tool-workflow/src/types.ts)
|
||||
|
||||
<a id="tool-workflowagent-start--log-only"></a>
|
||||
|
||||
#### `tool-workflow/agent-start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -769,6 +845,8 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow
|
||||
|
||||
Source: [`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow/tool-workflow/src/types.ts)
|
||||
|
||||
<a id="tool-workflowrun-end--log-only"></a>
|
||||
|
||||
#### `tool-workflow/run-end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -781,6 +859,8 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow
|
||||
|
||||
Source: [`packages/workflow/tool-workflow/src/types.ts:62`](../packages/workflow/tool-workflow/src/types.ts)
|
||||
|
||||
<a id="tool-workflowrun-start--log-only"></a>
|
||||
|
||||
#### `tool-workflow/run-start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -795,6 +875,8 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:47`](../packages/workflow
|
||||
|
||||
### `turn/*`
|
||||
|
||||
<a id="turnend--log-only"></a>
|
||||
|
||||
#### `turn/end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -813,6 +895,8 @@ Types: [TurnEndReason](subsystems/session.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:252`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="turnstart--log-only"></a>
|
||||
|
||||
#### `turn/start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -829,6 +913,8 @@ Source: [`packages/core/session/src/types.ts:243`](../packages/core/session/src/
|
||||
|
||||
### `user/*`
|
||||
|
||||
<a id="usermessage--surface"></a>
|
||||
|
||||
#### `user/message` — surface
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -846,6 +932,8 @@ Source: [`packages/core/session/src/types.ts:264`](../packages/core/session/src/
|
||||
|
||||
### `web/*`
|
||||
|
||||
<a id="webdeepseek-search-llm-request--log-only"></a>
|
||||
|
||||
#### `web/deepseek-search-llm-request` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
|
||||
@@ -98,6 +98,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `agent/*`
|
||||
|
||||
<a id="agentinboxspliced--log-only"></a>
|
||||
|
||||
#### `agent/inbox/spliced` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -119,6 +121,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `agent-preset/*`
|
||||
|
||||
<a id="agent-presetselected--log-only"></a>
|
||||
|
||||
#### `agent-preset/selected` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -135,6 +139,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `approval/*`
|
||||
|
||||
<a id="approvalasked--log-only"></a>
|
||||
|
||||
#### `approval/asked` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -158,6 +164,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/interaction/user-approval/src/index.ts:44`](../packages/interaction/user-approval/src/index.ts)
|
||||
|
||||
<a id="approvaldecided--log-only"></a>
|
||||
|
||||
#### `approval/decided` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -174,6 +182,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/interaction/user-approval/src/index.ts:55`](../packages/interaction/user-approval/src/index.ts)
|
||||
|
||||
<a id="approvalpolicy--log-only"></a>
|
||||
|
||||
#### `approval/policy` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -196,6 +206,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `assistant/*`
|
||||
|
||||
<a id="assistantchunk--log-only"></a>
|
||||
|
||||
#### `assistant/chunk` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -207,6 +219,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/session/src/types.ts:266`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="assistantmessage--surface"></a>
|
||||
|
||||
#### `assistant/message` — surface
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -225,6 +239,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `command/*`
|
||||
|
||||
<a id="commanddone--log-only"></a>
|
||||
|
||||
#### `command/done` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -244,6 +260,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/interaction/commands/src/types.ts:95`](../packages/interaction/commands/src/types.ts)
|
||||
|
||||
<a id="commandrun--log-only"></a>
|
||||
|
||||
#### `command/run` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -264,6 +282,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `compaction/*`
|
||||
|
||||
<a id="compactionend--log-only"></a>
|
||||
|
||||
#### `compaction/end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -276,6 +296,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/compaction/compaction/src/types.ts:71`](../packages/compaction/compaction/src/types.ts)
|
||||
|
||||
<a id="compactionprune--log-only"></a>
|
||||
|
||||
#### `compaction/prune` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -300,6 +322,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/compaction/compaction/src/types.ts:81`](../packages/compaction/compaction/src/types.ts)
|
||||
|
||||
<a id="compactionstart--log-only"></a>
|
||||
|
||||
#### `compaction/start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -313,6 +337,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/compaction/compaction/src/types.ts:23`](../packages/compaction/compaction/src/types.ts)
|
||||
|
||||
<a id="compactionsummary--log-only"></a>
|
||||
|
||||
#### `compaction/summary` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -367,6 +393,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `feedback/*`
|
||||
|
||||
<a id="feedbackrecord--log-only"></a>
|
||||
|
||||
#### `feedback/record` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -381,6 +409,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `goal/*`
|
||||
|
||||
<a id="goalchange--log-only"></a>
|
||||
|
||||
#### `goal/change` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -394,6 +424,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `hook/*`
|
||||
|
||||
<a id="hookinvoked--log-only"></a>
|
||||
|
||||
#### `hook/invoked` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -417,6 +449,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/hooks/hook-protocol/src/types.ts:19`](../packages/hooks/hook-protocol/src/types.ts)
|
||||
|
||||
<a id="hookresult--log-only"></a>
|
||||
|
||||
#### `hook/result` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -440,6 +474,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `llm/*`
|
||||
|
||||
<a id="llmretry--log-only"></a>
|
||||
|
||||
#### `llm/retry` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -449,6 +485,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/llm/llm-retry/src/types.ts:9`](../packages/llm/llm-retry/src/types.ts)
|
||||
|
||||
<a id="llmretry-started--log-only"></a>
|
||||
|
||||
#### `llm/retry-started` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -460,6 +498,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `permission/*`
|
||||
|
||||
<a id="permissionpreset--log-only"></a>
|
||||
|
||||
#### `permission/preset` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -476,6 +516,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `plan/*`
|
||||
|
||||
<a id="planmode--log-only"></a>
|
||||
|
||||
#### `plan/mode` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -491,6 +533,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `request/*`
|
||||
|
||||
<a id="requestcontext--log-only"></a>
|
||||
|
||||
#### `request/context` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -503,6 +547,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/session/src/types.ts:309`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="requestheader--log-only"></a>
|
||||
|
||||
#### `request/header` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -517,6 +563,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `sandbox/*`
|
||||
|
||||
<a id="sandboxmode--log-only"></a>
|
||||
|
||||
#### `sandbox/mode` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -538,6 +586,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `schedule/*`
|
||||
|
||||
<a id="schedulechange--log-only"></a>
|
||||
|
||||
#### `schedule/change` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -554,6 +604,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `session/*`
|
||||
|
||||
<a id="sessionend-seed--log-only"></a>
|
||||
|
||||
#### `session/end-seed` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -584,6 +636,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="sessiontitle--log-only"></a>
|
||||
|
||||
#### `session/title` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -598,6 +652,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/session/session-title/src/index.ts:100`](../packages/session/session-title/src/index.ts)
|
||||
|
||||
<a id="sessiontitle-llm-request--log-only"></a>
|
||||
|
||||
#### `session/title-llm-request` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -611,6 +667,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `step/*`
|
||||
|
||||
<a id="stepend--log-only"></a>
|
||||
|
||||
#### `step/end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -620,6 +678,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="stepstart--log-only"></a>
|
||||
|
||||
#### `step/start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -631,6 +691,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `subagent/*`
|
||||
|
||||
<a id="subagentdescriptor--log-only"></a>
|
||||
|
||||
#### `subagent/descriptor` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -648,6 +710,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `todo/*`
|
||||
|
||||
<a id="todowrite--log-only"></a>
|
||||
|
||||
#### `todo/write` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -661,6 +725,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `tool/*`
|
||||
|
||||
<a id="toolcall--log-only"></a>
|
||||
|
||||
#### `tool/call` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -676,6 +742,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/session/src/types.ts:279`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="toolcode-dispatch--log-only"></a>
|
||||
|
||||
#### `tool/code-dispatch` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -699,6 +767,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/tools/src/types.ts:56`](../packages/core/tools/src/types.ts)
|
||||
|
||||
<a id="toolcode-dispatch-start--log-only"></a>
|
||||
|
||||
#### `tool/code-dispatch-start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -720,6 +790,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/tools/src/types.ts:40`](../packages/core/tools/src/types.ts)
|
||||
|
||||
<a id="toolresult--surface"></a>
|
||||
|
||||
#### `tool/result` — surface
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -747,6 +819,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `tool-workflow/*`
|
||||
|
||||
<a id="tool-workflowagent-end--log-only"></a>
|
||||
|
||||
#### `tool-workflow/agent-end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -759,6 +833,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/workflow/tool-workflow/src/types.ts:57`](../packages/workflow/tool-workflow/src/types.ts)
|
||||
|
||||
<a id="tool-workflowagent-start--log-only"></a>
|
||||
|
||||
#### `tool-workflow/agent-start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -771,6 +847,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/workflow/tool-workflow/src/types.ts:52`](../packages/workflow/tool-workflow/src/types.ts)
|
||||
|
||||
<a id="tool-workflowrun-end--log-only"></a>
|
||||
|
||||
#### `tool-workflow/run-end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -783,6 +861,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/workflow/tool-workflow/src/types.ts:62`](../packages/workflow/tool-workflow/src/types.ts)
|
||||
|
||||
<a id="tool-workflowrun-start--log-only"></a>
|
||||
|
||||
#### `tool-workflow/run-start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -797,6 +877,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `turn/*`
|
||||
|
||||
<a id="turnend--log-only"></a>
|
||||
|
||||
#### `turn/end` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -815,6 +897,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
来源:[`packages/core/session/src/types.ts:252`](../packages/core/session/src/types.ts)
|
||||
|
||||
<a id="turnstart--log-only"></a>
|
||||
|
||||
#### `turn/start` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -831,6 +915,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `user/*`
|
||||
|
||||
<a id="usermessage--surface"></a>
|
||||
|
||||
#### `user/message` — surface
|
||||
|
||||
```ts persistence-catalog
|
||||
@@ -848,6 +934,8 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
||||
|
||||
### `web/*`
|
||||
|
||||
<a id="webdeepseek-search-llm-request--log-only"></a>
|
||||
|
||||
#### `web/deepseek-search-llm-request` — log-only
|
||||
|
||||
```ts persistence-catalog
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/core.md
|
||||
core.md: 6eda80cbd164168c3c4a846c9bc50a8fc12b0c92
|
||||
core.zh.md: 14c2e78bc3fff959fb0c0040eae0f382985ecdf4
|
||||
core.md: d14ad52e57572d5b0b110a0b16ff734e3499bdf5
|
||||
core.zh.md: 9ace28731f2532f571b66f2e7f6a3ea4a2c4e345
|
||||
@@ -257,6 +257,8 @@ Its full fields, the `defineTool`/`ValueSchemaSpec`/`ParameterSchemaSpec` typed
|
||||
|
||||
Two patterns recur across every subsystem and are documented once, here.
|
||||
|
||||
<a id="the-map--derived-union-pattern"></a>
|
||||
|
||||
### The `…Map → derived-union` pattern
|
||||
|
||||
Almost every extensible sum type in the harness follows one pattern: an interface keyed by a discriminant tag (the `…Map`), from which the union is derived with `keyof`. Plugins add variants by **declaration merging** — no edit to the owning package.
|
||||
|
||||
@@ -263,6 +263,8 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
|
||||
|
||||
两个模式在每个子系统中反复出现,只在此处记录一次。
|
||||
|
||||
<a id="the-map--derived-union-pattern"></a>
|
||||
|
||||
### `…Map → derived-union` 模式
|
||||
|
||||
harness 中几乎所有可扩展的和类型都遵循同一模式:一个以判别标签为键的接口(`…Map`),联合类型由 `keyof` 派生。插件通过**声明合并**添加变体——无需修改拥有该类型的包。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/llm-streaming.md
|
||||
llm-streaming.md: 0f395245332e735c04997bd1ca82f66fa9286104
|
||||
llm-streaming.md: 0d3a0d53c875c9d943146ba44b775d81fc9cae01
|
||||
llm-streaming.zh.md: fbaa47d14d57e7377be4db6ecaa04f11997572a6
|
||||
@@ -151,6 +151,8 @@ type ContextFormed =
|
||||
| { readonly form: 'recall' }
|
||||
```
|
||||
|
||||
<a id="streamchunk--the-raw-protocol"></a>
|
||||
|
||||
## `StreamChunk` — the raw protocol
|
||||
|
||||
A streaming response interleaves several typed blocks (text, reasoning, multiple tool calls). `index` ties each delta to its block; `block-end` carries the fully-assembled `ContentBlock` so consumers don't have to re-assemble deltas themselves. It is a **closed** discriminated union — a `switch` over `type` ends with `assertNever`, so adding a variant breaks compilation at every consumer that must handle it.
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/persistence.md
|
||||
persistence.md: fde8348d64a200eda5133abf66deedee6be09857
|
||||
persistence.zh.md: a2a836d81d153a2697c1d739345501e7e6770eef
|
||||
persistence.md: 5b1b224e419aca205baba69894ed64467b8fb4e1
|
||||
persistence.zh.md: a91e7d66b92270c82287d054e619b665e96ea206
|
||||
@@ -36,6 +36,8 @@ interface SessionLocation {
|
||||
}
|
||||
```
|
||||
|
||||
<a id="sessionheader--metadata-beside-the-log"></a>
|
||||
|
||||
## `SessionHeader` — metadata beside the log
|
||||
|
||||
Per-session metadata travels **separately** from the event log: format version, cwd, lineage, and the seed boundary are storage concerns, not conversation events, so they stay out of `SessionEventMap` and never reach `deriveMessages()`. The header is attached to a `Session` via `session.header`.
|
||||
|
||||
@@ -36,6 +36,8 @@ interface SessionLocation {
|
||||
}
|
||||
```
|
||||
|
||||
<a id="sessionheader--metadata-beside-the-log"></a>
|
||||
|
||||
## `SessionHeader`:日志旁的元数据
|
||||
|
||||
每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血统与 seed 边界是存储层关注点而非对话事件,因此不进入 `SessionEventMap`,也不会到达 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/session.md
|
||||
session.md: 4c40971fe58952b32635aa5eb767a42f73108b00
|
||||
session.zh.md: d958b03fcdad91b58cc277636e599cce46a2c7fb
|
||||
session.md: aea9d00b38e384e7a973ce168c3a75a62e70a8bb
|
||||
session.zh.md: 8c56029af5144569f1ab6df73a8fe2278f9ef5b4
|
||||
@@ -149,6 +149,8 @@ interface TodoItem {
|
||||
}
|
||||
```
|
||||
|
||||
<a id="the-request-header-event-requestheader"></a>
|
||||
|
||||
### The request header event: `request/header`
|
||||
|
||||
The request envelope — the `EpochHeader` (call config + markers for adapter-supplied defaults + rendered system prompt + assembled tool schemas) — is logged session state, so every conversation request is a pure function of the log (the reconstructability Agent Note). A full `request/header` snapshot with reason `'initial'` or `'resume'` records each loop-instance boundary; a later changed request records another full snapshot with reason `'change'`. `foldRequestHeader(events)` reconstructs the header by selecting the latest snapshot. The event is not a `SurfaceEventType`: it produces no LLM message.
|
||||
@@ -586,7 +588,7 @@ An explicitly supplied empty seed writes `session/end-seed` at seq 0, which dist
|
||||
|
||||
It exists because seed history and live work are otherwise byte-identical, which defeats any plugin owning a standalone open/close bracket: an unmatched `compaction/start` reads the same whether the writer crashed mid-compaction or is compacting right now. An opening marker before `session/end-seed` came from the constructor seed and belongs to an ended lifecycle, whatever ended it (a crash, a succeeding process, or a fork out of a still-running parent), so its owner may treat it as dead. That covers only brackets *this* session inherited: a concurrently live session holding an open bracket over the same history has its own boundary elsewhere, so tolerating concurrent writers needs a liveness signal beyond the log. Core writes the boundary and reads nothing from it — a bracket's vocabulary stays with its owning plugin, which is why crash repair closes turn/step/tool boundaries and never `compaction/*`.
|
||||
|
||||
Activity ordering excludes the boundary through `lastActivityTime(events)`: picking a session up is not work, and lazy resume means browsing writes one, so a resume picker or session list ordering by log tail would float every opened session to the top.
|
||||
Consumers that order Sessions by human activity exclude this boundary: picking a Session up is not work, so ordering by the log tail would float every opened Session to the top.
|
||||
|
||||
## Plugin-contributed log-only events
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@ interface TurnEndReasonMap {
|
||||
|
||||
它之所以必要,是因为种子历史与实时工作在字节层面完全相同,这会让任何拥有独立开/闭括号的插件失效:一个未配对的 `compaction/start`,无论写入方是在压缩中途崩溃、还是此刻正在压缩,读起来都一样。在 `session/end-seed` 之前的开启标记来自构造种子,并且属于一个已结束的生命周期,无论结束原因为何(崩溃、进程接替,或从仍在运行的父会话 fork 出来),因此其所有方可以视之为已死。这只覆盖*本*会话继承的括号:另一个并发存活的会话可能在同一段历史上持有开放括号,而它自己的边界在别处,因此容忍并发写入方还需要日志之外的存活信号。核心写入该边界但不从中读取任何内容——括号的词汇表仍归其所属插件,这也正是崩溃修复只关闭轮次/步骤/工具边界而从不处理 `compaction/*` 的原因。
|
||||
|
||||
活动排序通过 `lastActivityTime(events)` 排除该边界:接手会话不算工作,而惰性恢复意味着浏览就会写入一个,因此按日志尾部排序的恢复选择器或会话列表会把每个打开过的会话顶到最前。
|
||||
按真人活动排序 Session 的消费方会排除该边界:接手 Session 不算工作,因此按日志尾部排序会把每个打开过的 Session 顶到最前。
|
||||
|
||||
## 插件贡献的仅日志事件
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/tool-catalog.md
|
||||
tool-catalog.md: 3d73ed1ef5346f620808e9d6b04299291ba1ed4c
|
||||
tool-catalog.zh.md: 90573928a24630e802d98441bc0e340baf582b23
|
||||
tool-catalog.md: 50563c97c6cd5496871ea7fa52c4823a56b088fd
|
||||
tool-catalog.zh.md: ed0c7e3f70cffbecd3d20a1556bcb0cd4204df00
|
||||
@@ -40,6 +40,8 @@ This table connects model-visible tool names to the plugin package and service s
|
||||
| `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`, `ctx.workflowEngine`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents the script children)` | `tool/call`, `tool/result` | - | - |
|
||||
| `@deepseek-ai/dsh-tool-web` | `web_fetch`, `web_search` | `ctx.tools`, `ctx.web`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. |
|
||||
|
||||
<a id="deepseek-aidsh-tool-ask-user"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ask-user`
|
||||
|
||||
### `ask_user_question`
|
||||
@@ -112,6 +114,8 @@ Source: [`packages/interaction/tool-ask-user/src/index.ts`](../packages/interact
|
||||
|
||||
ask_user_question pauses the tool call until the active UI provider returns a human answer.
|
||||
|
||||
<a id="deepseek-aidsh-tools"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tools`
|
||||
|
||||
### `run_code`
|
||||
@@ -142,6 +146,8 @@ Source: [`packages/core/tools/src/code-mode.ts`](../packages/core/tools/src/code
|
||||
|
||||
Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
|
||||
|
||||
<a id="deepseek-aidsh-plan-mode"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-plan-mode`
|
||||
|
||||
### `exit_plan_mode`
|
||||
@@ -167,6 +173,8 @@ Source: [`packages/plan/plan-mode/src/index.ts`](../packages/plan/plan-mode/src/
|
||||
|
||||
exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary.
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash`
|
||||
|
||||
### `bash`
|
||||
@@ -209,6 +217,8 @@ Source: [`packages/shell/tool-bash/src/index.ts`](../packages/shell/tool-bash/sr
|
||||
|
||||
The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.jobs` runtime and is collected/stopped through the `job_*` tools from `@deepseek-ai/dsh-tool-jobs`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled.
|
||||
|
||||
<a id="deepseek-aidsh-tool-pwsh"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-pwsh`
|
||||
|
||||
### `pwsh`
|
||||
@@ -251,6 +261,8 @@ Source: [`packages/shell/tool-pwsh/src/index.ts`](../packages/shell/tool-pwsh/sr
|
||||
|
||||
The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as `@deepseek-ai/dsh-pwsh-local` backs `ctx.shell`); it mirrors the bash tool call-for-call minus sandbox controls — `run_in_background` runs register with the generic `ctx.jobs` runtime and are collected/stopped through the `job_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-shell-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\...` paths and `$env:NAME` variables.
|
||||
|
||||
<a id="deepseek-aidsh-tool-cordis"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-cordis`
|
||||
|
||||
### `cordis_define`
|
||||
@@ -487,6 +499,8 @@ Source: [`packages/extensions/tool-cordis/src/index.ts`](../packages/extensions/
|
||||
|
||||
Not in any shipped tree (a deliberate opt-in — dynamic package code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). The toolset injects `ctx.dynamicCordisRunner` from `@deepseek-ai/dsh-cordis-host-runner`, which owns the definition registry and the vm sandbox; a composition missing it never activates the tools. A running package may register ADDITIONAL model-visible tools until it is stopped, undefined, or DSH restarts; a full changed request header logs those tool-set changes.
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash-persistent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash-persistent`
|
||||
|
||||
### `bash`
|
||||
@@ -512,6 +526,8 @@ Source: [`packages/shell/tool-bash-persistent/src/index.ts`](../packages/shell/t
|
||||
|
||||
One owner-isolated persistent bash tool; deployment composition supplies the PTY backend and may override the model-facing environment description.
|
||||
|
||||
<a id="deepseek-aidsh-tool-str-replace-editor"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-str-replace-editor`
|
||||
|
||||
### `str_replace_editor`
|
||||
@@ -580,6 +596,8 @@ Source: [`packages/fs/tool-str-replace-editor/src/index.ts`](../packages/fs/tool
|
||||
|
||||
Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal API.
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs`
|
||||
|
||||
### `edit`
|
||||
@@ -695,6 +713,8 @@ Source: [`packages/fs/tool-fs/src/index.ts`](../packages/fs/tool-fs/src/index.ts
|
||||
|
||||
The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-observation-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. `read_image` is not registered without `ctx.attachments`; its schema is route-independent, and execution refuses unless the exact routed model declares image input.
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs-search"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs-search`
|
||||
|
||||
### `glob`
|
||||
@@ -753,6 +773,8 @@ Source: [`packages/fs/tool-fs-search/src/index.ts`](../packages/fs/tool-fs-searc
|
||||
|
||||
glob and grep are unconditional discovery tools that spawn the packaged ripgrep binary (`@vscode/ripgrep`) through ctx.subprocess as ordinary foreground calls (never background jobs) — no host `rg` install and no shell layer. The catalog uses `sampleOverCapGlobResults: true`; deployments must choose that behavior explicitly. Capped results save the complete formatted list through the optional ctx.spillStore backend; returned locators are follow-up-readable/searchable when the backend exposes local paths in co-located deployments.
|
||||
|
||||
<a id="deepseek-aidsh-tool-terminal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-terminal`
|
||||
|
||||
### `terminal_close`
|
||||
@@ -916,6 +938,8 @@ Source: [`packages/terminal/tool-terminal/src/index.ts`](../packages/terminal/to
|
||||
|
||||
The six terminal tools are opt-in and complement one-shot shell/filesystem tools. `terminal_send(run_in_background: true)` registers with `ctx.jobs`; TUI, named key sequences, BEL, resize, auto-start, and cross-agent sharing are absent from the schema.
|
||||
|
||||
<a id="deepseek-aidsh-tool-goal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-goal`
|
||||
|
||||
### `create_goal`
|
||||
@@ -1008,6 +1032,8 @@ Source: [`packages/goal/tool-goal/src/index.ts`](../packages/goal/tool-goal/src/
|
||||
|
||||
create, edit, pause, and resume require direct-human root authority; complete and blocked also accept the exact current goal round. The default blocked lower bound is three admitted rounds.
|
||||
|
||||
<a id="deepseek-aidsh-schedule"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-schedule`
|
||||
|
||||
### `schedule_create`
|
||||
@@ -1103,6 +1129,8 @@ Source: [`packages/schedule/schedule/src/tools.ts`](../packages/schedule/schedul
|
||||
|
||||
Registered only inside live root Agent scopes created after the opt-in Schedule plugin loads. Version 1 accepts after_seconds, explicit absolute at, and bounded fixed-rate every_seconds, and discloses session-local delivery; management reads and mutations require the shared Session persistence barrier.
|
||||
|
||||
<a id="deepseek-aidsh-tool-lsp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-lsp`
|
||||
|
||||
### `lsp`
|
||||
@@ -1149,6 +1177,8 @@ Source: [`packages/lsp/tool-lsp/src/index.ts`](../packages/lsp/tool-lsp/src/inde
|
||||
|
||||
The lsp tool keeps provider selection and language-server subprocesses behind ctx.lsp, so its model-visible schema stays stable across providers. Requires a registered provider (e.g. `@deepseek-ai/dsh-lsp-stdio`) at runtime; without one, a query returns the structured `LSP_UNAVAILABLE` error rather than changing the schema.
|
||||
|
||||
<a id="deepseek-aidsh-tool-ralph"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ralph`
|
||||
|
||||
### `ralph`
|
||||
@@ -1178,6 +1208,8 @@ Source: [`packages/workflow/tool-ralph/src/index.ts`](../packages/workflow/tool-
|
||||
|
||||
A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap.
|
||||
|
||||
<a id="deepseek-aidsh-tool-skill"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-skill`
|
||||
|
||||
### `skill`
|
||||
@@ -1201,6 +1233,8 @@ Load the full instructions for an available skill. Call this with the exact skil
|
||||
|
||||
Source: [`packages/skill/tool-skill/src/index.ts`](../packages/skill/tool-skill/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-session-query"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-session-query`
|
||||
|
||||
### `session_event_read`
|
||||
@@ -1434,6 +1468,8 @@ Source: [`packages/session-query/tool-session-query/src/index.ts`](../packages/s
|
||||
|
||||
The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies.
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent`
|
||||
|
||||
### `subagent`
|
||||
@@ -1468,6 +1504,8 @@ Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/to
|
||||
|
||||
The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance's description, `run_in_background` parameter, and system-prompt policy follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable` and defaults omitted calls to background with automatic settlement delivery, while `subagent_fork` stays `one-shot` and defaults them to foreground — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent-control"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent-control`
|
||||
|
||||
### `interrupt_agent`
|
||||
@@ -1541,6 +1579,8 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/sub
|
||||
|
||||
The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` and `interrupt_agent` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows use the sessionProjections and live Agent registries).
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent-report"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent-report`
|
||||
|
||||
### `report`
|
||||
@@ -1566,6 +1606,8 @@ Source: [`packages/subagent/tool-subagent-report/src/index.ts`](../packages/suba
|
||||
|
||||
Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global `toolFilter`. The same contribution installs the child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing `send_message` tool is installed independently.
|
||||
|
||||
<a id="deepseek-aidsh-tool-jobs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-jobs`
|
||||
|
||||
### `job_kill`
|
||||
@@ -1637,6 +1679,8 @@ Source: [`packages/jobs/tool-jobs/src/index.ts`](../packages/jobs/tool-jobs/src/
|
||||
|
||||
The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' `ctx.jobs.start()`.
|
||||
|
||||
<a id="deepseek-aidsh-tool-todo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-todo`
|
||||
|
||||
### `todo_write`
|
||||
@@ -1685,6 +1729,8 @@ Source: [`packages/todo/tool-todo/src/index.ts`](../packages/todo/tool-todo/src/
|
||||
|
||||
todo_write is session-owned state; UIs render the latest todo/write event as a checklist. `allowParallelInProgress` is required with no default, so the catalog states its choice: `true`, whose description invites several `in_progress` items. A deployment choosing `false` receives the same tool with a description asking for exactly one active task.
|
||||
|
||||
<a id="deepseek-aidsh-tool-workflow"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-workflow`
|
||||
|
||||
### `workflow`
|
||||
@@ -1778,6 +1824,8 @@ Constraints: concurrency and total-agent caps apply; no filesystem, network, tim
|
||||
|
||||
Source: [`packages/workflow/tool-workflow/src/index.ts`](../packages/workflow/tool-workflow/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-web"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-web`
|
||||
|
||||
### `web_fetch`
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
| `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`、`ctx.workflowEngine`、`ctx.systemPrompt`、`a calling Agent (exec.agent parents the script children)` | `tool/call`、`tool/result` | - | - |
|
||||
| `@deepseek-ai/dsh-tool-web` | `web_fetch`、`web_search` | `ctx.tools`、`ctx.web`、`ctx.systemPrompt` | `tool/call`、`tool/result` | - | web_search 和 web_fetch 将提供方选择置于 ctx.web 之后,使模型可见 schema 在更换后端时保持稳定。 |
|
||||
|
||||
<a id="deepseek-aidsh-tool-ask-user"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ask-user`
|
||||
|
||||
### `ask_user_question`
|
||||
@@ -114,6 +116,8 @@
|
||||
|
||||
ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类答案。
|
||||
|
||||
<a id="deepseek-aidsh-tools"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tools`
|
||||
|
||||
### `run_code`
|
||||
@@ -144,6 +148,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类
|
||||
|
||||
在 `mode: code`/`mode: both` 下,它由工具注册表所有,作为可过滤能力层之外的保留传输机制(参见 Code Mode Agent Note)。在 `code` 下,它是注册表对协议格式的唯一贡献;其他可见能力在使用已加载运行时语言生成的 SDK 章节中声明。程序通过 binding 调用这些能力,调用按照原生并发约定调度:启动顺序和策略遵循提交顺序,并发安全的函数体最多重叠执行 `maxParallelSubCalls` 个。调用会重新进入完整且受守卫保护的工具流水线,并将每个嵌套执行关联到此外层结果。
|
||||
|
||||
<a id="deepseek-aidsh-plan-mode"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-plan-mode`
|
||||
|
||||
### `exit_plan_mode`
|
||||
@@ -169,6 +175,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类
|
||||
|
||||
规划未激活时,exit_plan_mode 仍保留在面向模型的 schema 中,这样状态转换不会在规划策略变更之外额外造成工具目录变动。其执行路径会拒绝规划模式之外的调用;在规划模式下,它通过用户交互 seam 提交计划(批准/根据反馈继续规划),批准后会在步骤边界记录规划模式已停用。
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash`
|
||||
|
||||
### `bash`
|
||||
@@ -211,6 +219,8 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类
|
||||
|
||||
bash 工具是 bash 执行器 seam 面向模型的消费方。使用 `run_in_background` 的运行会注册到通用 `ctx.jobs` 运行时,并通过 `job_*` 工具(来自 `@deepseek-ai/dsh-tool-jobs`)收集/停止;禁用 `enableRunInBackground` 配置(默认为 true)后,该参数会被完全移除。
|
||||
|
||||
<a id="deepseek-aidsh-tool-pwsh"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-pwsh`
|
||||
|
||||
### `pwsh`
|
||||
@@ -253,6 +263,8 @@ bash 工具是 bash 执行器 seam 面向模型的消费方。使用 `run_in_bac
|
||||
|
||||
pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费方(由 `@deepseek-ai/dsh-pwsh-local` 等 PowerShell 执行器为 `ctx.shell` 提供后端);除沙箱接口外,它逐项对应 bash 工具调用。使用 `run_in_background` 的运行会注册到通用 `ctx.jobs` 运行时,并通过 `job_*` 工具收集/停止;托管的 `DSH_*` 环境来自 `@deepseek-ai/dsh-shell-env`。每次调用都在新进程中运行,不使用持久 PTY 会话。路径采用原生 `C:\...` 形式,变量采用 `$env:NAME`。
|
||||
|
||||
<a id="deepseek-aidsh-tool-cordis"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-cordis`
|
||||
|
||||
### `cordis_define`
|
||||
@@ -489,6 +501,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费
|
||||
|
||||
不在任何随产品发布的树中,需要显式选择启用;动态 Package 代码可以访问真实运行时,见 .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md。该工具集注入 `@deepseek-ai/dsh-cordis-host-runner` 提供的 `ctx.dynamicCordisRunner`,后者拥有定义注册表和 vm 沙箱;组合缺少它时这些工具不会激活。运行中的 Package 在停止、undefine 或 DSH 重启前可以注册**额外的**模型可见工具;发生这类工具集变化时,系统会记录完整且有变动的请求头。
|
||||
|
||||
<a id="deepseek-aidsh-tool-bash-persistent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-bash-persistent`
|
||||
|
||||
### `bash`
|
||||
@@ -514,6 +528,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费
|
||||
|
||||
一个按所有者隔离的持久 bash 工具;部署组合提供 PTY 后端,并可覆盖面向模型的环境描述。
|
||||
|
||||
<a id="deepseek-aidsh-tool-str-replace-editor"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-str-replace-editor`
|
||||
|
||||
### `str_replace_editor`
|
||||
@@ -584,6 +600,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费
|
||||
|
||||
基于文件系统 seam 的独立查看/创建/唯一字面量替换/按行插入工具;可与任何 shell 或终端接口组合。
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs`
|
||||
|
||||
### `edit`
|
||||
@@ -699,6 +717,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费
|
||||
|
||||
先读后写/编辑策略由 `@deepseek-ai/dsh-fs-observation-policy` 添加;它是一个 `fs/*` 事件门禁插件,不会改变 schema。加载这些工具的部署按预期也应加载该插件。没有 `ctx.attachments` 时 `read_image` 不会注册;其 schema 与路由无关,执行时除非确切路由的模型声明图像输入,否则拒绝。
|
||||
|
||||
<a id="deepseek-aidsh-tool-fs-search"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-fs-search`
|
||||
|
||||
### `glob`
|
||||
@@ -757,6 +777,8 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费
|
||||
|
||||
glob 和 grep 是无条件可用的发现工具,通过 ctx.subprocess spawn 随包提供的 ripgrep 二进制文件(`@vscode/ripgrep`),并作为普通前台调用运行,绝不作为后台任务;无需在宿主机安装 `rg`,也不经过 shell 层。本目录使用 `sampleOverCapGlobResults: true`;部署必须显式选择该行为。结果超过上限时,会通过可选的 ctx.spillStore 后端保存完整的格式化列表;在共置部署中,如果后端公开本地路径,返回的定位信息可供后续读取/搜索。
|
||||
|
||||
<a id="deepseek-aidsh-tool-terminal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-terminal`
|
||||
|
||||
### `terminal_close`
|
||||
@@ -920,6 +942,8 @@ glob 和 grep 是无条件可用的发现工具,通过 ctx.subprocess spawn
|
||||
|
||||
这 6 个终端工具需要选择启用,用于补充一次性 bash/文件系统工具。`terminal_send(run_in_background: true)` 会注册到 `ctx.jobs`;schema 不包含 TUI、具名按键序列、BEL、调整尺寸、自动启动和跨 agent 共享。
|
||||
|
||||
<a id="deepseek-aidsh-tool-goal"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-goal`
|
||||
|
||||
### `create_goal`
|
||||
@@ -1012,6 +1036,8 @@ glob 和 grep 是无条件可用的发现工具,通过 ctx.subprocess spawn
|
||||
|
||||
create、edit、pause 和 resume 要求直接来自人类的根权限;complete 和 blocked 也接受确切的当前 Goal Round。blocked 的默认下限是 3 个获准的 Round。
|
||||
|
||||
<a id="deepseek-aidsh-schedule"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-schedule`
|
||||
|
||||
### `schedule_create`
|
||||
@@ -1107,6 +1133,8 @@ create、edit、pause 和 resume 要求直接来自人类的根权限;complete
|
||||
|
||||
仅在选择启用的 Schedule 插件加载后创建的 live 根 Agent scope 内注册。版本 1 接受 after_seconds、显式绝对 at 和有界固定速率 every_seconds,并披露 session-local 交付;管理读取与变更必须通过共享的 Session 持久化 barrier。
|
||||
|
||||
<a id="deepseek-aidsh-tool-lsp"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-lsp`
|
||||
|
||||
### `lsp`
|
||||
@@ -1153,6 +1181,8 @@ create、edit、pause 和 resume 要求直接来自人类的根权限;complete
|
||||
|
||||
lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,因此其模型可见 schema 在更换提供方时保持稳定。运行时要求已注册提供方,例如 `@deepseek-ai/dsh-lsp-stdio`;如果没有提供方,查询会返回结构化 `LSP_UNAVAILABLE` 错误,而不会改变 schema。
|
||||
|
||||
<a id="deepseek-aidsh-tool-ralph"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ralph`
|
||||
|
||||
### `ralph`
|
||||
@@ -1182,6 +1212,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
固定的前台工作流会在每个 Round 启动一个全新的结构化子级;模型只能选择不可变目标和可选的 Round 上限。
|
||||
|
||||
<a id="deepseek-aidsh-tool-skill"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-skill`
|
||||
|
||||
### `skill`
|
||||
@@ -1205,6 +1237,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
来源:[`packages/skill/tool-skill/src/index.ts`](../packages/skill/tool-skill/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-session-query"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-session-query`
|
||||
|
||||
### `session_event_read`
|
||||
@@ -1438,6 +1472,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
这 5 个只读工具会隐藏提供方游标,并根据不可变的调用 agent 会话为每个结果授权。该包需要选择启用;需要强制截止时间或限制行内输出的组合还会挂载通用超时或 spill 策略。
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent`
|
||||
|
||||
### `subagent`
|
||||
@@ -1472,6 +1508,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
注册的工具名称取决于加载时 `toolName` 配置(默认为 `subagent`);上述 schema 对应默认值。随产品发布的组合会为每个 subagent 后端加载一次该包,因此模型还会看到绑定到 fork 后端的 `subagent_fork`。每个实例的描述、`run_in_background` 参数与 system prompt 策略取决于它自己的 `backgroundMode` 和 `enableRunInBackground`,因此两个随附 schema 并不相同:`subagent` 为 `continuable`,省略参数时默认后台运行,并由 runtime 自动投递结束结果;`subagent_fork` 保持 `one-shot`,省略参数时默认前台运行。详见 `packages/bundle/base/cordis.patch.yml` 和 `examples/acp-agent/cordis.yml`。
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent-control"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent-control`
|
||||
|
||||
### `interrupt_agent`
|
||||
@@ -1545,6 +1583,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
这些是控制可继续后台 subagent 的全局命名工具:绑定提供方的 `tool-subagent` 实例注册不同的委派工具;本包注册一次 `send_message` 和 `interrupt_agent`,另由 `list_agents` 通过单独加载的 `/list-agents` 插件提供,其目录行使用 sessionProjections 和实时 Agent 注册表。
|
||||
|
||||
<a id="deepseek-aidsh-tool-subagent-report"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-subagent-report`
|
||||
|
||||
### `report`
|
||||
@@ -1570,6 +1610,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
按可继续的进程内子级注册,而非全局注册,因此该 schema 仅在这种子级内部可见,并且不受其全局 `toolFilter` 影响。同一份贡献还会安装子级作用域的 `tool:report` 系统提示词 section,本目录不渲染该 section。面向父级的 `send_message` 工具单独安装。
|
||||
|
||||
<a id="deepseek-aidsh-tool-jobs"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-jobs`
|
||||
|
||||
### `job_kill`
|
||||
@@ -1641,6 +1683,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
与任务种类无关的后台任务控制器:后台 bash 命令、PTY 发送和 subagent 都通过相同的 3 个工具读取、列出和终止。加载该插件会挂接控制器,从而启用生产方的 `ctx.jobs.start()`。
|
||||
|
||||
<a id="deepseek-aidsh-tool-todo"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-todo`
|
||||
|
||||
### `todo_write`
|
||||
@@ -1689,6 +1733,8 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
|
||||
|
||||
todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为检查清单。`allowParallelInProgress` 是没有默认值的必填项,因此本目录明确选择 `true`,对应描述允许同时存在多个 `in_progress` 项。选择 `false` 的部署会获得同一工具,但描述会要求只能有 1 个活动任务。
|
||||
|
||||
<a id="deepseek-aidsh-tool-workflow"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-workflow`
|
||||
|
||||
### `workflow`
|
||||
@@ -1783,6 +1829,8 @@ todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为
|
||||
|
||||
来源:[`packages/workflow/tool-workflow/src/index.ts`](../packages/workflow/tool-workflow/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-tool-web"></a>
|
||||
|
||||
## `@deepseek-ai/dsh-tool-web`
|
||||
|
||||
### `web_fetch`
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/basic/index.md
|
||||
index.md: 494b7869be6ffdf5767fac260b36b2585305b516
|
||||
index.zh.md: a55b8e31151c5cfa5445069974be9fa022fea1eb
|
||||
index.md: 08199624e638aaf4a36b04446c39c228b2af6025
|
||||
index.zh.md: c45a30d0bfffaf4a6c78303f9ca043c3397c8a08
|
||||
@@ -45,14 +45,16 @@ export function apply(ctx: Context) {
|
||||
|
||||
## Register it in cordis.yml
|
||||
|
||||
Create `scratch-plugin/cordis.yml` as a Web overlay that inserts the local plugin:
|
||||
Run `pwd` from the repository root, then create `scratch-plugin/cordis.yml` as a Web overlay that inserts the local plugin. Replace `/absolute/path/to/deepseek-harness` below with the printed path:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
- id: hello
|
||||
name: './src/my-plugin.ts'
|
||||
name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'
|
||||
```
|
||||
|
||||
The plugin path must be absolute. A patch file contributes configuration but does not change the profile directory from which the loader resolves module paths.
|
||||
|
||||
Start the Web UI with that overlay:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -45,14 +45,16 @@ export function apply(ctx: Context) {
|
||||
|
||||
## 注册到 cordis.yml
|
||||
|
||||
创建 `scratch-plugin/cordis.yml`,作为插入本地插件的 Web 覆盖层:
|
||||
在仓库根目录运行 `pwd`,然后创建 `scratch-plugin/cordis.yml`,作为插入本地插件的 Web 覆盖层。请将下文的 `/absolute/path/to/deepseek-harness` 替换为命令打印的路径:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
- id: hello
|
||||
name: './src/my-plugin.ts'
|
||||
name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'
|
||||
```
|
||||
|
||||
插件路径必须是绝对路径。patch 文件只贡献配置,不会改变 loader 解析模块路径时使用的 profile 目录。
|
||||
|
||||
使用该覆盖层启动 Web UI:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/basic/publish.md
|
||||
publish.md: 588531a28020ebe620643cd1aaaa43de000e658a
|
||||
publish.zh.md: b86bd43369c027972705394fded43ae053248c0f
|
||||
publish.md: 8283f9e7ff0c28580343975d67c5715d17c53074
|
||||
publish.zh.md: 5a87901fe39aa00e94db81dc840e39a52e0cc88c
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
English | [中文](publish.zh.md)
|
||||
|
||||
The previous tutorials loaded a local plugin through a `--patch` overlay. This tutorial packages it as an installable **bundle**, installs it into a **profile** with `dsh plugin add`, and explains the layer order that determines the composed configuration. Complete [plugin configuration](./config.md) first.
|
||||
The previous tutorials loaded a local plugin through a `--patch` overlay. This tutorial packages it as an installable **bundle**, installs it into a **profile** with `dsh plugin add`, and explains the layer order that determines the composed configuration. It assumes the `dsh` CLI is installed. Complete [plugin configuration](./config.md) first.
|
||||
|
||||
## Two concepts, two manifests
|
||||
|
||||
@@ -15,6 +15,12 @@ A bundle is what you author and distribute; a profile is what a user boots with
|
||||
|
||||
### The bundle manifest
|
||||
|
||||
Create the package directory:
|
||||
|
||||
```sh
|
||||
mkdir -p hello-plugin
|
||||
```
|
||||
|
||||
```
|
||||
hello-plugin/
|
||||
├── package.json # declares dsh.bundle
|
||||
@@ -22,6 +28,8 @@ hello-plugin/
|
||||
└── index.js # plugin modules the patch rows reference
|
||||
```
|
||||
|
||||
Create `hello-plugin/package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "dsh-hello-plugin",
|
||||
@@ -33,7 +41,17 @@ hello-plugin/
|
||||
}
|
||||
```
|
||||
|
||||
The patch file is a YAML array of patch entries, like the `--patch` overlays you have been writing, except plugin rows reference the package by name instead of a relative source path so Node resolution finds the installed code:
|
||||
Create `hello-plugin/index.js` with the plugin entry point:
|
||||
|
||||
```js
|
||||
export const name = 'hello-plugin'
|
||||
|
||||
export function apply() {
|
||||
console.log('[hello-plugin] plugin loaded!')
|
||||
}
|
||||
```
|
||||
|
||||
Create `hello-plugin/cordis.patch.yml`. The patch is a YAML array like the `--patch` overlays you have been writing, except plugin rows reference the package by name instead of a relative source path so Node resolution finds the installed code:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
@@ -54,11 +72,10 @@ You never write a profile manifest by hand: `dsh plugin` creates and maintains i
|
||||
|
||||
## Install into a profile
|
||||
|
||||
`dsh plugin --profile <name> <args...>` forwards to pnpm in the profile directory, so every pnpm verb works. Install your package from its checkout:
|
||||
`dsh plugin --profile <name> <args...>` forwards to pnpm in the profile directory, so every pnpm verb works. From the directory that contains `hello-plugin`, install the package checkout:
|
||||
|
||||
```sh
|
||||
cd hello-plugin
|
||||
dsh plugin --profile demo add .
|
||||
dsh plugin --profile demo add ./hello-plugin
|
||||
```
|
||||
|
||||
The first use initializes the profile (with `@deepseek-ai/dsh-base` as its first bundle), pnpm links the checkout, and `dsh` appends the bundle to `dsh.profile.bundles` because the package declares `dsh.bundle`:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](publish.md) | 中文
|
||||
|
||||
前几篇教程通过 `--patch` overlay 加载本地插件。本教程把它打包成可安装的**组合包**(bundle),用 `dsh plugin add` 安装进一个 **profile**,并解释决定组合后配置的层顺序。请先完成[插件配置](./config.md)。
|
||||
前几篇教程通过 `--patch` overlay 加载本地插件。本教程把它打包成可安装的**组合包**(bundle),用 `dsh plugin add` 安装进一个 **profile**,并解释决定组合后配置的层顺序。本文假设 `dsh` CLI 已安装。请先完成[插件配置](./config.md)。
|
||||
|
||||
## 两个概念,两种 manifest
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
|
||||
### 组合包 manifest
|
||||
|
||||
创建包目录:
|
||||
|
||||
```sh
|
||||
mkdir -p hello-plugin
|
||||
```
|
||||
|
||||
```
|
||||
hello-plugin/
|
||||
├── package.json # declares dsh.bundle
|
||||
@@ -22,6 +28,8 @@ hello-plugin/
|
||||
└── index.js # plugin modules the patch rows reference
|
||||
```
|
||||
|
||||
创建 `hello-plugin/package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "dsh-hello-plugin",
|
||||
@@ -33,7 +41,17 @@ hello-plugin/
|
||||
}
|
||||
```
|
||||
|
||||
patch 文件与一直在写的 `--patch` overlay 一样,是一个 patch 条目的 YAML 数组;区别是插件行按包名而不是相对源码路径引用这个包,这样 Node 的模块解析才能找到已安装的代码:
|
||||
创建 `hello-plugin/index.js`,写入插件入口:
|
||||
|
||||
```js
|
||||
export const name = 'hello-plugin'
|
||||
|
||||
export function apply() {
|
||||
console.log('[hello-plugin] plugin loaded!')
|
||||
}
|
||||
```
|
||||
|
||||
创建 `hello-plugin/cordis.patch.yml`。这个 patch 与一直在写的 `--patch` overlay 一样,是一个 patch 条目的 YAML 数组;区别是插件行按包名而不是相对源码路径引用这个包,这样 Node 的模块解析才能找到已安装的代码:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
@@ -54,11 +72,10 @@ profile manifest 从不需要手写:`dsh plugin` 负责创建和维护它。
|
||||
|
||||
## 安装进 profile
|
||||
|
||||
`dsh plugin --profile <name> <args...>` 在 profile 目录内转发给 pnpm,因此所有 pnpm 子命令都可用。从 checkout 安装你的包:
|
||||
`dsh plugin --profile <name> <args...>` 在 profile 目录内转发给 pnpm,因此所有 pnpm 子命令都可用。在包含 `hello-plugin` 的目录中安装该包的 checkout:
|
||||
|
||||
```sh
|
||||
cd hello-plugin
|
||||
dsh plugin --profile demo add .
|
||||
dsh plugin --profile demo add ./hello-plugin
|
||||
```
|
||||
|
||||
首次使用会初始化 profile(`@deepseek-ai/dsh-base` 作为它的第一个组合包),pnpm 链接该 checkout,而 `dsh` 因为这个包声明了 `dsh.bundle`,把它追加进 `dsh.profile.bundles`:
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/framework/events.md
|
||||
events.md: 4a6ecbad614cf2debccaee9ace1086273d8fb95b
|
||||
events.zh.md: c77747bf6ac767c69e4f2d9cfe7375b71bd388e6
|
||||
events.md: 1d9fe5c8f5068de6ad8b2abaa85cf67be35c8459
|
||||
events.zh.md: 8bb9447a270cc2db966b1e01298a831a60a1b9c1
|
||||
@@ -40,7 +40,7 @@ ctx.on('my-plugin/ready', ({ id }) => {
|
||||
|
||||
### bail — short circuit
|
||||
|
||||
Listeners run in order; the first non-`undefined` result becomes the final result:
|
||||
Listeners run in order; the first result other than `null`, `false`, or `undefined` becomes the final result:
|
||||
|
||||
```ts ignore-check
|
||||
// Dispatch
|
||||
@@ -49,13 +49,13 @@ const result = ctx.bail('some-check', input)
|
||||
// Listen: a returned value stops later listeners.
|
||||
ctx.on('some-check', (input) => {
|
||||
if (shouldBlock(input)) return 'blocked'
|
||||
// Return undefined to continue to the next listener.
|
||||
// Return null, false, or undefined to continue to the next listener.
|
||||
})
|
||||
```
|
||||
|
||||
### serial — ordered execution
|
||||
|
||||
Listeners run in registration order and asynchronous results are awaited. The first listener to return a non-empty value stops further execution:
|
||||
Listeners run in registration order and asynchronous results are awaited. The first result other than `null`, `false`, or `undefined` stops further execution:
|
||||
|
||||
```ts ignore-check
|
||||
await ctx.serial('setup-phase', context)
|
||||
|
||||
@@ -40,7 +40,7 @@ ctx.on('my-plugin/ready', ({ id }) => {
|
||||
|
||||
### bail — 短路
|
||||
|
||||
依次调用监听器,第一个非 `undefined` 的返回值将作为最终结果:
|
||||
监听器按顺序运行,第一个不是 `null`、`false` 或 `undefined` 的返回值会成为最终结果:
|
||||
|
||||
```ts ignore-check
|
||||
// Dispatch
|
||||
@@ -49,13 +49,13 @@ const result = ctx.bail('some-check', input)
|
||||
// Listen: a returned value stops later listeners.
|
||||
ctx.on('some-check', (input) => {
|
||||
if (shouldBlock(input)) return 'blocked'
|
||||
// Return undefined to continue to the next listener.
|
||||
// Return null, false, or undefined to continue to the next listener.
|
||||
})
|
||||
```
|
||||
|
||||
### serial — 顺序执行
|
||||
|
||||
监听器按注册顺序依次执行,并等待异步结果;第一个返回非空值的监听器会终止后续执行:
|
||||
监听器按注册顺序依次执行,并等待异步结果;第一个不是 `null`、`false` 或 `undefined` 的返回值会终止后续执行:
|
||||
|
||||
```ts ignore-check
|
||||
await ctx.serial('setup-phase', context)
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/user/develop/framework/service.md
|
||||
service.md: a9e873f1ba969b1f2d22266f8ec03207f84eeddc
|
||||
service.zh.md: a201280bc38176f57f5354ab205ae700c7b04a89
|
||||
service.md: 03f4e7dc4df934495a4b203066183753b621339e
|
||||
service.zh.md: 2f4c01e0ea6a87a87ca694b265b07e07098f3e59
|
||||
@@ -117,7 +117,7 @@ This prevents a plugin from calling a service that no longer exists.
|
||||
name: '@deepseek-ai/cordis-plugin-group'
|
||||
group: true
|
||||
isolate:
|
||||
bash: true
|
||||
shell: true
|
||||
config:
|
||||
- name: '@deepseek-ai/dsh-bash-local'
|
||||
config:
|
||||
@@ -128,7 +128,7 @@ This prevents a plugin from calling a service that no longer exists.
|
||||
name: '@deepseek-ai/cordis-plugin-group'
|
||||
group: true
|
||||
isolate:
|
||||
bash: true
|
||||
shell: true
|
||||
config:
|
||||
- name: '@deepseek-ai/dsh-bash-local'
|
||||
config:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user