@thincoder/core 0.10.12 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/advisor/messages.mjs +4 -2
  3. package/advisor/notice.mjs +1 -1
  4. package/advisor/project-context.mjs +121 -11
  5. package/agent/completion.mjs +13 -1
  6. package/agent/digest-account.mjs +73 -46
  7. package/agent/dispatch-run.mjs +1 -1
  8. package/agent/dispatch.mjs +29 -21
  9. package/agent/family-tools.mjs +9 -5
  10. package/agent/helpers.mjs +1 -94
  11. package/agent/offload.mjs +88 -0
  12. package/agent/record-results.mjs +1 -6
  13. package/agent/run-stages.mjs +74 -49
  14. package/agent/run-start.mjs +8 -8
  15. package/agent/setup.mjs +6 -11
  16. package/agent/suspension.mjs +1 -1
  17. package/agent/turn-loop.mjs +35 -3
  18. package/agent/write-face.mjs +99 -0
  19. package/agent/write-gate.mjs +354 -5
  20. package/agent-tools/advisor.mjs +127 -11
  21. package/agent-tools/async-settle.mjs +2 -2
  22. package/agent-tools/bash-async.mjs +8 -2
  23. package/agent-tools/batch-closeout.mjs +206 -0
  24. package/agent-tools/batch-gate.mjs +287 -73
  25. package/agent-tools/batch-ledger-bind.mjs +183 -0
  26. package/agent-tools/batch-ledger-link.mjs +73 -0
  27. package/agent-tools/batch-lifecycle.mjs +113 -354
  28. package/agent-tools/batch-paths.mjs +45 -40
  29. package/agent-tools/batch-read.mjs +1 -1
  30. package/agent-tools/batch-reopen.mjs +142 -0
  31. package/agent-tools/batch-skeleton.mjs +283 -80
  32. package/agent-tools/batch-unit-test-gate.mjs +107 -0
  33. package/agent-tools/batch.mjs +243 -50
  34. package/agent-tools/context.mjs +6 -3
  35. package/agent-tools/design-slots.mjs +24 -24
  36. package/agent-tools/design-token.mjs +96 -15
  37. package/agent-tools/doc-check.mjs +18 -2
  38. package/agent-tools/eng.mjs +1 -1
  39. package/agent-tools/escalate-async.mjs +3 -3
  40. package/agent-tools/manifest.mjs +8 -5
  41. package/agent-tools/read-history.mjs +5 -5
  42. package/agent-tools/review-facts.mjs +31 -13
  43. package/agent-tools/spawn-gates.mjs +10 -14
  44. package/agent-tools/ssh-session.mjs +120 -111
  45. package/agent-tools/ssh-transfer.mjs +210 -0
  46. package/agent-tools/ssh-transport.mjs +277 -46
  47. package/agent-tools/subagent-actions-query.mjs +1 -1
  48. package/agent-tools/subagent-actions.mjs +1 -1
  49. package/agent-tools/subagent-async.mjs +3 -2
  50. package/agent-tools/subagent-scheduler.mjs +43 -9
  51. package/agent-tools/subagent-spawn.mjs +68 -9
  52. package/agent-tools/subagent.mjs +16 -14
  53. package/agent.mjs +1 -0
  54. package/client-identity.mjs +70 -0
  55. package/config-presets.mjs +5 -3
  56. package/config.mjs +19 -13
  57. package/context.mjs +39 -8
  58. package/declaration.mjs +2 -2
  59. package/doc-check/anchors.mjs +128 -28
  60. package/doc-check/index.mjs +93 -27
  61. package/doc-check/line-refs.mjs +112 -0
  62. package/doc-check/paragraph.mjs +24 -8
  63. package/embedding.mjs +2 -0
  64. package/explore-distill.mjs +1 -1
  65. package/generate-title.mjs +3 -2
  66. package/i18n.mjs +1 -1
  67. package/index-discover.mjs +4 -1
  68. package/ledger-close-proof.mjs +62 -0
  69. package/ledger-cmd.mjs +79 -194
  70. package/ledger-db.mjs +29 -28
  71. package/ledger-migrate.mjs +4 -4
  72. package/ledger-read.mjs +10 -8
  73. package/ledger-surface.mjs +1 -1
  74. package/ledger-tools.mjs +10 -10
  75. package/ledger-variant-notice.mjs +1 -1
  76. package/ledger-write-ops.mjs +373 -0
  77. package/ledger.mjs +2 -2
  78. package/manifest-discovery.mjs +2 -2
  79. package/manifest-schema.mjs +4 -0
  80. package/memory/memory-tool.mjs +5 -2
  81. package/memory/schema.mjs +5 -26
  82. package/model-specs.mjs +6 -5
  83. package/package.json +1 -1
  84. package/path-resolve.mjs +217 -0
  85. package/permission.mjs +4 -0
  86. package/prompt-overlays.mjs +5 -0
  87. package/prompts/advisor-design.md +9 -6
  88. package/prompts/advisor-round1.md +4 -3
  89. package/prompts/advisor-round2.md +6 -5
  90. package/prompts/advisor-round3.md +6 -5
  91. package/prompts/common.md +23 -10
  92. package/prompts/consult-base.md +2 -1
  93. package/prompts/discipline-engineering.md +29 -48
  94. package/prompts/discipline-normal.md +10 -5
  95. package/prompts/persona-eng-coder.md +8 -0
  96. package/prompts/persona-eng-designer.md +22 -12
  97. package/prompts/persona-engineering.md +81 -66
  98. package/prompts/persona-plan.md +2 -1
  99. package/prompts/persona-tester.md +55 -0
  100. package/provider/anthropic.mjs +12 -7
  101. package/provider/core.mjs +21 -5
  102. package/provider/errors.mjs +41 -0
  103. package/provider/google.mjs +25 -9
  104. package/provider/list-models.mjs +4 -3
  105. package/provider/rate.mjs +11 -3
  106. package/provider/responses.mjs +17 -7
  107. package/provider/sse.mjs +15 -4
  108. package/session-identity.mjs +21 -0
  109. package/session-lifecycle.mjs +12 -4
  110. package/session-slots.mjs +9 -14
  111. package/session.mjs +5 -0
  112. package/skip-dirs.mjs +48 -0
  113. package/team-ledger.mjs +4 -4
  114. package/text-budget.mjs +4 -0
  115. package/token-window.mjs +107 -10
  116. package/tool-docs/advisor.md +2 -2
  117. package/tool-docs/apply_patch.md +2 -0
  118. package/tool-docs/bash.md +4 -0
  119. package/tool-docs/batch.md +85 -1
  120. package/tool-docs/browser.md +3 -1
  121. package/tool-docs/code_search.md +3 -1
  122. package/tool-docs/consult_start.md +6 -2
  123. package/tool-docs/consult_stop.md +3 -1
  124. package/tool-docs/delete.md +3 -0
  125. package/tool-docs/doc_check.md +43 -8
  126. package/tool-docs/doc_search.md +5 -1
  127. package/tool-docs/edit.md +22 -1
  128. package/tool-docs/execute.md +7 -1
  129. package/tool-docs/fetch.md +3 -1
  130. package/tool-docs/file_ops.md +3 -1
  131. package/tool-docs/git.md +9 -1
  132. package/tool-docs/goal.md +2 -0
  133. package/tool-docs/grep.md +1 -1
  134. package/tool-docs/hashline_edit.md +2 -0
  135. package/tool-docs/insert_after.md +3 -1
  136. package/tool-docs/ledger.md +5 -5
  137. package/tool-docs/lint.md +1 -0
  138. package/tool-docs/manifest-read.md +2 -1
  139. package/tool-docs/manifest.md +9 -2
  140. package/tool-docs/memory.md +11 -1
  141. package/tool-docs/notify_parent.md +1 -1
  142. package/tool-docs/plan.md +2 -0
  143. package/tool-docs/question.md +1 -1
  144. package/tool-docs/read_history.md +15 -3
  145. package/tool-docs/read_image.md +3 -1
  146. package/tool-docs/recent_changes.md +3 -1
  147. package/tool-docs/repo_outline.md +3 -1
  148. package/tool-docs/settings.md +10 -2
  149. package/tool-docs/skill.md +2 -0
  150. package/tool-docs/ssh.md +30 -17
  151. package/tool-docs/subagent.md +50 -13
  152. package/tool-docs/task.md +2 -0
  153. package/tool-docs/team_ledger.md +1 -1
  154. package/tool-docs/timer.md +7 -0
  155. package/tool-docs/verify.md +13 -1
  156. package/tool-docs/websearch.md +3 -1
  157. package/tool-docs/write.md +2 -0
  158. package/tools/bash.mjs +12 -2
  159. package/tools/edit-batch.mjs +40 -33
  160. package/tools/edit-diff.mjs +69 -1
  161. package/tools/execute.mjs +10 -4
  162. package/tools/file.mjs +17 -27
  163. package/tools/git.mjs +27 -1
  164. package/tools/ops.mjs +2 -1
  165. package/tools/patch.mjs +12 -3
  166. package/tools/process-doc-mark.mjs +139 -0
  167. package/tools/search.mjs +15 -6
  168. package/tools/shared.mjs +24 -1
  169. package/tools/ssh.mjs +48 -7
  170. package/tools/tree.mjs +4 -1
  171. package/tools/write-path.mjs +64 -3
  172. package/traces/trace-store.mjs +4 -3
  173. package/agent/light-round.mjs +0 -63
  174. package/agent/unbooked-pen.mjs +0 -62
@@ -1,8 +1,8 @@
1
1
  台账统一入口——action = add / update / close / query / count。query / count 只读全角色;add / update / close 写仅主 agent。
2
2
  - add:新增条目入待讨论。kind = requirement(需求池)/ tech_todo(技术待办);trigger = 归批 / 条件 / 认账不排期(可空);resume_when = 复启条件句(可空;值非空——空串 / 全空白拒;句内可带锚 `@YYYY-MM-DD`(机判到期)或 `@事件件名`(机器不判))。task_book 写门(add ∥ update 同判,判本笔写入面):结果行 在途 / 待核销 ∥ trigger = 归批 ⇒ task_book 必填(缺 / 空串 / 全空白拒);本笔新写 task_book(非空值)∥ 本笔新写 trigger = 归批 ⇒ 该指针的文件部分(首个 `§` 前子串)须可解析且指出的档在盘,否则拒。本笔不动指针 ⇒ 零判零阻——旧指针所指档已被清理不阻 status / evidence / 其它字段更新(「档在不在盘」是读数 taskBookOnDisk,不是门)。
3
- - update:按六态允许表迁移:待讨论→待设计 / 待设计→在途 / 在途→待核销 / 待核销→已核销 / 任意态→已废弃;表外拒;迁移入 已核销 时结果行标题携「收尾链待跑」同拒(同笔携清标记 title 放行)。id ∥ batch 恰携其一。status 缺省 = 仅更新字段;executor 缺省 = 进入待设计 / 在途自动写本会话,出在途 / 撤回清空;resume_when 同 update 可空字段(缺省 = 不变)。evidence 传入 = 追加(旧值非空 ⇒ 拼接 `旧|新`——「|」零空格;旧空直写);`evidenceReplace: true` 与 evidence 同传 = 整段替换;旗独传(无新文)∥ 新值全空白 ⇒ 拒。
3
+ - update:按六态允许表迁移(逐边枚举,表外拒):待讨论→待设计 / 待讨论→在途 / 待设计→在途 / 在途→待核销 / 待核销→已核销 / 待核销→在途 / 任意非 已废弃 态→已废弃(已废弃 无出边)。`待讨论→在途` 是点火与建档的正路——批档一开就把覆盖行直接落到 在途,不过 待设计(待设计 = 已排设计,不是点火发生的事);`待核销→在途` 是重开回收——批档重开 ⇒ 行回工作位,六态唯一的回退边。id ∥ batch 恰携其一。status 缺省 = 仅更新字段;executor 缺省 = 进入待设计 / 在途自动写本会话,出在途 / 撤回清空;resume_when 同 update 可空字段(缺省 = 不变)。evidence 传入 = 追加(旧值非空 ⇒ 拼接 `旧|新`——「|」零空格;旧空直写);`evidenceReplace: true` 与 evidence 同传 = 整段替换;旗独传(无新文)∥ 新值全空白 ⇒ 拒。
4
4
  - update --batch:批级批量迁移(batch = 批档指针,与该档 task_book 同址的行一次处理)——携 status ⇒ 逐行按迁移表重判;不携 status ⇒ 纯字段补丁(status 零写)。回执 { batch, status, applied, skipped };被跳过的行逐行点名 { id, from, why }(why = 逐行拒因原文),其余行照落;事务级失败整批回滚。batch 值须可解析且批档在盘,否则拒。
5
- - close:勾销(待核销 → 已核销);追认核销(待讨论 / 待设计 → 已核销,须有 evidence——可随本调用传入(一跳核销),判结果值:缺 / 全空白拒);在途 → 已核销 不可跳;核销标记门:结果行标题携「收尾链待跑」⇒ 拒(收尾链未跑完,不许核销——先跑收尾全链,再由父侧清标记);撤回(任意态 → 已废弃)不拦。软删除(写 closed_at,行保留)。id ∥ batch 恰携其一。evidence 传入 = 追加(旧值非空 ⇒ 拼接 `旧|新`;旧空直写);`evidenceReplace: true` 同传 = 整段替换;旗独传 / 新值全空白 ⇒ 拒;缺省 = 判行值。
6
- - close --batch:批级批量结算——只销已到 待核销 的行(勾销);待讨论 / 待设计 逐行点名跳过(追认核销不入批量面,转单行 close),在途 逐行点名跳过(不可跳);已核销 / 已废弃 行静默不计。status 可不给(缺省 = 已核销),给了只能是 已核销。
7
- - query:SQLite 行集,等值过滤(status / kind / board / trigger / task_book)缺省 = 全部行;行集逐行携 aged(未决四态 ∧ 行龄 > 30 天)/ evidenceOversize(evidence 超软上限 300 字——读数非拒写)/ taskBookOnDisk(task_book 文件部分解析成立 ∧ 该档在盘 ⇒ true;缺指针 / 不可解析 / 不在盘 ⇒ false——读数非门,不拦任何写入)/ overdue(出口态字串 ∥ null:resume_due / dangling / unlabeled / aged,首中优先)。六态 = 待讨论 / 待设计 / 在途 / 待核销 / 已核销 / 已废弃。
8
- - count:回报 { count, overdue, evidenceOversize }——count = 未决四态(待讨论 / 待设计 / 在途 / 待核销)行数;overdue = 其中命中出口态的行数;evidenceOversize = 其中 evidence 超限行数。task_book 等值过滤。
5
+ - close:勾销(待核销 → 已核销)——**只有这一条核销边**:待讨论 / 待设计 / 在途 一律拒(拒文点名现态 + 该现态的出路句);撤回(任意态 → 已废弃)不拦。软删除(写 closed_at,行保留)。id ∥ batch 恰携其一。evidence 传入 = 追加(旧值非空 ⇒ 拼接 `旧|新`;旧空直写);`evidenceReplace: true` 同传 = 整段替换;旗独传 / 新值全空白 ⇒ 拒;缺省 = 判行值。
6
+ - close --batch:批级批量结算——只销已到 待核销 的行(勾销);待讨论 / 待设计 逐行点名跳过(须先 update 到 在途 认领);在途 逐行点名跳过(不可跳);已核销 / 已废弃 行静默不计。status 可不给(缺省 = 已核销),给了只能是 已核销。
7
+ - query:SQLite 行集,等值过滤(status / kind / board / trigger / task_book)缺省 = 全部行;行集逐行携 aged(未决四态 ∧ 行龄 > 30 天)/ evidenceTooLong(evidence 文字太长,难于阅读——读数非拒写;超 300 字即算命中)/ taskBookOnDisk(task_book 文件部分解析成立 ∧ 该档在盘 ⇒ true;缺指针 / 不可解析 / 不在盘 ⇒ false——读数非门,不拦任何写入)/ overdue(出口态字串 ∥ null:resume_due / dangling / unlabeled / aged,首中优先)。六态 = 待讨论 / 待设计 / 在途 / 待核销 / 已核销 / 已废弃。
8
+ - count:回报 { count, overdue, evidenceTooLong }——count = 未决四态(待讨论 / 待设计 / 在途 / 待核销)行数;overdue = 其中命中出口态的行数;evidenceTooLong = 其中文字太长、难于阅读的行数。task_book 等值过滤。
package/tool-docs/lint.md CHANGED
@@ -1,5 +1,6 @@
1
1
  Run the appropriate linter/checker for a file. Auto-detects based on file extension and project config.
2
2
  Without 'full', runs a fast node --check (JS/TS syntax only, catches parse errors in milliseconds).
3
+
3
4
  With 'full', runs the language-aware cascade: tsc –noEmit (TS); ruff (Python); cargo check (Rust); go vet (Go). JS/JSX files fall back to node --check; TS uses tsc --noEmit (requires tsconfig.json).
4
5
  Use the fast default after every write/edit; use 'full' before declaring a task complete.
5
6
 
@@ -1,4 +1,5 @@
1
- Read the project manifest (PROJECT-MANIFEST.json) — the project-level state file: version / phase / docRoot (the root of each document layer: requirements / specs / design / modules / batches) / codePaths / index.
1
+ Read the project manifest (PROJECT-MANIFEST.json) — the project-level state file: version / phase / docRoot (the root of each document layer: requirements / specs / design / modules / batches, plus `standards` = the project's standards document, by file path) / codePaths / index.
2
+
2
3
  Read-only: the only action is `read`. Creating or editing a manifest belongs to the main agent — this subagent variant has no init / write action.
3
4
 
4
5
  read [target] — report the manifest state with a stable anchor `state=ok|missing|invalid|workspace|no-project`. The ok state prints the manifest JSON plus missingKeys / unknownKeys / errors rows (only when non-empty). Never throws — a missing manifest is reported, not refused.
@@ -7,7 +7,9 @@ Actions:
7
7
  The resulting manifest must pass validation (a fault is refused with the disk byte-for-byte unchanged); a missing manifest is
8
8
  refused — run init first (write never creates one).
9
9
 
10
- target — explicit target directory; defaults to the session anchor, relative paths resolve against it. A workspace target
10
+ target — explicit target directory; defaults to the session anchor, relative paths resolve against it.
11
+
12
+ A workspace target
11
13
  (several projects below it) is reported by `read` and refused by `init` / `write` — with the facts, the full candidate list and
12
14
  a next step: name the project root you mean and pass it as target.
13
15
 
@@ -19,11 +21,16 @@ Refusals throw `manifest <action>: refused — …` and leave the disk unchanged
19
21
 
20
22
  read is read-only (planMode passes, no approval); init / write are side effects (approval gate). Writes go through writeManifest / initManifest with writer "main" — the fail-closed subagent default is never used.
21
23
 
22
- Key catalog — the 12 writable nodes (3 whole keys + docRoot's 5 sub-keys + index's 4 sub-keys): what each is; when to change it; wrong ⇒ consequence.
24
+ Key catalog — the 13 writable nodes (3 whole keys + docRoot's 6 sub-keys + index's 4 sub-keys): what each is; when to change it; wrong ⇒ consequence.
23
25
  - `version` — schema version (a number); change on file migration; wrong ⇒ validation refuses (disk unchanged).
24
26
  - `phase` — project stage, `initial-dev` / `production`; change when the stage is crossed; wrong ⇒ validation refuses.
25
27
  - `codePaths` — path segment names (replaces the default `["src"]`); change when the layout moves; wrong ⇒ no segment is classified (the fallback still runs).
26
28
  - `docRoot.requirements` · `docRoot.specs` · `docRoot.design` · `docRoot.modules` · `docRoot.batches` — each doc-layer root path (a string | a multi-root array | `null` = absent); change when a layer moves root; wrong ⇒ validation refuses, or checks / batch landing / review roots point elsewhere.
29
+ - `docRoot.standards` — the project's standards document, by FILE path (a string | a multi-file array | `null` = undeclared); the reviewer judges methodology compliance against it; change when that document moves; wrong ⇒ the review says the declaration is unreadable and names the path (never a guessed default — there is none).
27
30
  - `index.codeExtensions` · `index.docExtensions` — extra code / doc extensions (unioned, add-only); change when a file type is missing from the index; wrong ⇒ that type stays out of the index (extras harmless; a missing entry = a miss).
28
31
  - `index.excludePaths` — project-root-relative path prefixes (for the index); change to keep a directory out of the index; wrong ⇒ that directory is still indexed, or another is wrongly excluded.
29
32
  - `index.publicRepos` — public-repo paths (resolvable from this repo root); change when wiring a public repo into the index or cross-repo refs; wrong ⇒ that repo is unreachable for retrieval (empty origin set / wrong path).
33
+
34
+ - **`ledger`** — the in-flight ledger row this call serves: `"#N"` or `"N"`. In engineering mode the parent agent must pass it for `write`; for `init`, only when the target sits inside an existing project (a `PROJECT-MANIFEST.json` exists on its ancestor chain) — a bootstrap outside any project needs none; omitted when required = refused. `read` does not need it.
35
+
36
+ **`project`** — the project this call belongs to (absolute path of the project root). Read only when `target` is absent — `target` wins when present. Pure declaration: it does not change the target directory (`target` does).
@@ -5,7 +5,17 @@ Manage long-term memory in ONE tool — the action parameter picks the operation
5
5
  - delete — SINGLE: {id, layer} removes the entry shown in put/search/list output — layer is optional: passed, it is validated against the id prefix (a mismatch is refused — guards against deleting the wrong entry); omitted, the id prefix routes the delete (any id from put/search/list is directly deletable). BATCH (no id): {layer, type and/or keyword} removes every matching entry in that layer — layer + at least one of type/keyword required; without confirm:true it returns the count + preview instead; layer-wide wipes without filters are refused on every layer
6
6
  - clear — {layer: "personal", confirm: true} wipes ALL personal memory entries. clear is personal-only: a missing layer or a project/team layer is refused (use delete batch filters on shared layers)
7
7
  - maintain — index self-maintenance (dry-run by default in tool calls): ghost-row GC (rows whose files are gone from disk — ENOENT-only; live rows untouched; ghost-row deletions take a backup first and read back after), compaction (VACUUM past the freelist thresholds), backup rotation (keeps the newest N maintenance backups). The automatic startup pass runs the same engine and executes directly; every run reports its readings. confirm:true executes — without it you get the plan + readings only
8
+
8
9
  Layer = the memory tier: personal (private) / project (shared via this repo's .thincoder/memory/) / team (CLI only, git-synced); the [layer] tag, the id prefix, and the layer parameter are the same concept — pass a result row's [layer] as layer.
10
+
9
11
  Deleting project/team entries removes the local markdown file and its index row — team deletion is local only; a later team sync may resurrect the file while the remote still has it.
12
+
10
13
  Save bugs, conventions, and preferences here — they persist across sessions.
11
- Session message history (what was said in this or past sessions) is NOT in memory — search session messages with read_history.
14
+ Session message history (what was said in this or past sessions) is NOT in memory — search session messages with read_history.
15
+
16
+ **`ledger`** — the in-flight ledger row this call serves: `"#N"` or `"N"`.
17
+
18
+ In engineering mode the parent agent must pass it for any write that lands in the project layer: either `layer: "project"`, or a single delete whose id starts with `project:` while `layer` is omitted (`personal` / `team` entries live in the user data directory, so they need no number).
19
+
20
+ **`project`** — the project this call belongs to (absolute path of the project root). Needed for exactly those project-layer writes: they also refuse without it. `personal` / `team` entries need neither. Pure declaration: it changes no execution directory.
21
+
@@ -1,7 +1,7 @@
1
1
  A one-way channel to your PARENT (the agent that spawned you) — you are a subagent, so there is no user to ask. Queue a message on the parent's side; your turn is not interrupted and nothing is consumed from it.
2
2
 
3
3
  - kind:'ask' — a question whose answer changes your next step and that you cannot answer from the materials you can read (task book / design doc / repo). The parent replies with subagent action:'send'; you receive it as an ordinary instruction at your next turn boundary. One ask at a time while a previous one still waits in the parent's queue.
4
- Read the materials first and carry the evidence you already checked (`file:line` + the key text) — the parent should not have to re-read for you.
4
+ Read the materials first and carry the evidence you already checked (the file path + the exact words you read) — the parent should not have to re-read for you.
5
5
  - kind:'note' — an FYI that needs no answer (a premise you found broken, a conflict you resolved and want visible early).
6
6
  - Delivery markers: the message your parent receives is headed `[上抛·待裁]` (ask — awaiting the
7
7
  parent's decision) or `[上抛·知会]` (note — FYI) — added for you, so do not write these markers
package/tool-docs/plan.md CHANGED
@@ -1,5 +1,7 @@
1
1
  Enter or exit plan mode.
2
+
2
3
  In plan mode you are restricted to READ-ONLY tools: read files, search code, run read-only shell commands.
3
4
  Use plan mode before complex multi-step tasks — explore the codebase, design the architecture, present a plan to the user.
5
+
4
6
  Exit plan mode to present the plan for the user's approval; implement only after they approve.
5
7
  For simple single-file edits, skip plan mode and just make the change.
@@ -14,5 +14,5 @@ Notes:
14
14
  - Keep the question text short — one or two sentences. Background, context, and analysis belong in your normal reply text, NOT in the question.
15
15
  - Routine confirmations (confirm gates) belong in your plain reply text — the user answers in their next message. Use this tool ONLY when you need the user's decision or input to proceed.
16
16
  - Ask here when no default can carry the work forward (new scope, a ruling on a criterion) — this blocks; when a reasonable default exists, ask in your ordinary reply text and keep going — a reply arriving while you work steers the work from there.
17
- Read the materials first and carry the evidence you already checked (`file:line` + the key text) — the user should not have to re-read for you.
17
+ Read the materials first and carry the evidence you already checked (the file path + the exact words you read) — the user should not have to re-read for you.
18
18
  - After receiving an answer about a design convention, tool preference, or recurring pattern: save it with the memory tool (action: put). This prevents asking the same question in future sessions — the user shouldn't have to repeat their preferences.
@@ -1,7 +1,19 @@
1
1
  Query message history — THIS session by default, any session on disk with `path`. Recall what was said or done earlier: design decisions, tool-call timing, past rulings.
2
2
 
3
- Default (no path): this session's full record (never compacted, audit-complete). Filters combine with AND (role / keyword / tool / since-until / limit / direction — semantics per parameter; keyword with path="all" matches FTS words / phrases). Returns a JSON array in chronological order: [{ts, role, name?, tool_call_id?, content (≈500 chars, truncated marker), tool_calls ([{name, arguments}] — arguments capped at 300 chars)}]. Messages without ts return ts:null; content is truncated — the full text is in the session file.
3
+ Default (no path): this session's full record (never compacted, audit-complete).
4
4
 
5
- Cross-session (`path`, optional): a session file path deep-queries THAT session with the same filters (relative paths resolve against the project cwd) — from the derived session index when it covers that session, otherwise from the session file itself (a file over 50,000 messages or 200,000 lines is refused as "session too large"). "cwd:<dir>" lists that directory's session slots (slot + file path + title + count + updatedAt; copy one into path= to deep-query it). "all" searches every INDEXED session (cross-project; rows carry session.file) — sessions never indexed yet are invisible (query them with path=<file>, or index first with the CLI `thincoder session index --rebuild`).
5
+ Filters combine with AND (role / keyword / tool / since-until / limit / direction — semantics per parameter; keyword with path="all" matches FTS words / phrases).
6
6
 
7
- 检索/记忆族选哪个:查**本会话**说过/裁定过 → read_history(默认);查**别的会话/项目**旧对话 → read_history 带 path/cwd 参数;查**本 run 改过哪些文件** → recent_changes;查**跨会话已存知识/约定**(memory)→ memory search;查**项目设计文档** → doc_search;查**代码实现** → code_search;查 git 历史快照 → checkpoint cat/versions。read_history 只查会话消息——文件级改动用 recent_changes——知识与约定用 memory——互相不替代。
7
+ Returns a JSON array in chronological order: [{ts, role, name?, tool_call_id?, content (≈500 chars, truncated marker), tool_calls ([{name, arguments}] — arguments capped at 300 chars)}]. Messages without ts return ts:null; content is truncated — the full text is in the session file.
8
+
9
+ Cross-session (`path`, optional): a session file path deep-queries THAT session with the same filters (relative paths resolve against the project cwd) — from the derived session index when it covers that session,
10
+
11
+ otherwise from the session file itself (a file over 50,000 messages or 200,000 lines is refused as "session too large").
12
+
13
+ "cwd:<dir>" lists that directory's session slots (slot + file path + title + count + updatedAt; copy one into path= to deep-query it).
14
+
15
+ "all" searches every INDEXED session (cross-project; rows carry session.file) — sessions never indexed yet are invisible (query them with path=<file>, or index first with the CLI `thincoder session index --rebuild`).
16
+
17
+ 检索/记忆族选哪个:查**本会话**说过/裁定过 → read_history(默认);查**别的会话/项目**旧对话 → read_history 带 path/cwd 参数;查**本 run 改过哪些文件** → recent_changes;
18
+
19
+ 查**跨会话已存知识/约定**(memory)→ memory search;查**项目设计文档** → doc_search;查**代码实现** → code_search;查 git 历史快照 → checkpoint cat/versions。read_history 只查会话消息——文件级改动用 recent_changes——知识与约定用 memory——互相不替代。
@@ -1,4 +1,6 @@
1
- Read an image file and return it as multimodal content visible to the model. Use this to view screenshots, UI mockups, diagrams, or any visual content. The model only sees images through this tool — it cannot "see" files directly. Supports png, jpg, gif, webp. The image is base64-encoded and included in the response. Large images (>15MB) are rejected.
1
+ Read an image file and return it as multimodal content visible to the model. Use this to view screenshots, UI mockups, diagrams, or any visual content. The model only sees images through this tool — it cannot "see" files directly.
2
+
3
+ Supports png, jpg, gif, webp. The image is base64-encoded and included in the response. Large images (>15MB) are rejected.
2
4
 
3
5
  Parameters:
4
6
  - path (required): Path to image file (relative to cwd or absolute). Supports png, jpg, gif, webp; svg is returned as text source.
@@ -1 +1,3 @@
1
- Show files modified in this agent run (write/edit/insert_after/delete). Use when you need to remember which files you've already touched — during long multi-file tasks, it's easy to lose track. This is scoped to the current run, unlike git status which shows all uncommitted changes. For session-level history (what was said in a session), use read_history.
1
+ Show files modified in this agent run (write/edit/insert_after/delete). Use when you need to remember which files you've already touched — during long multi-file tasks, it's easy to lose track. This is scoped to the current run, unlike git status which shows all uncommitted changes.
2
+
3
+ For session-level history (what was said in a session), use read_history.
@@ -1 +1,3 @@
1
- Show the project's file dependency outline: which files import/export from which, and what symbols they export. Use when you need to understand the project structure, find where a function is defined, or see what files depend on a module. Pass a path to focus on a single file's relationships. Find code by keyword or snippet with code_search.
1
+ Show the project's file dependency outline: which files import/export from which, and what symbols they export. Use when you need to understand the project structure, find where a function is defined, or see what files depend on a module.
2
+
3
+ Pass a path to focus on a single file's relationships. Find code by keyword or snippet with code_search.
@@ -1,6 +1,14 @@
1
1
  Adjust ThinCoder runtime configuration — persisted to config.json AND hot-applied to the live agent config.
2
2
  Actions: list (all keys + values, flattened) | get <key> | set <key> <value> — dot paths into config.json, any nesting.
3
+
3
4
  set persists to disk (only the set key is written — defaults are never baked in) and takes effect in the running session immediately (turn-boundary keys apply next turn); the value survives restarts.
4
- Known keys are type-checked: scalar keys against the built-in defaults (agent.maxTurns a number, traces.enabled a boolean); keys whose default is null against their real consumption shape — defaultModel "provider:model", agent.subagentModel / shell non-empty string, memory.team object with a repo — so a value the app would silently drop is refused (null clears the key: the entry is removed from config.json and the built-in default applies; string-typed keys refuse null — no "unset" state to fall back to). Unknown keys under a known section are stored as given.
5
+
6
+ Known keys are type-checked: scalar keys against the built-in defaults (agent.maxTurns a number, traces.enabled a boolean);
7
+
8
+ keys whose default is null against their real consumption shape — defaultModel "provider:model", agent.subagentModel / shell non-empty string, memory.team object with a repo — so a value the app would silently drop is refused
9
+
10
+ (null clears the key: the entry is removed from config.json and the built-in default applies; string-typed keys refuse null — no "unset" state to fall back to). Unknown keys under a known section are stored as given.
11
+
5
12
  SENSITIVE keys (path segment matching apiKey/key/token/secret/password/authorization/auth/cookie/credential, or any key under a headers/env segment) are NEVER echoed in plaintext — list/get/set replies show ••••(masked); setting a sensitive key is allowed and stored, but never echoed back.
6
- list/get are read-only (planMode ok, no approval); set is a side effect (approval gate). The /config TUI command is the human equivalent.
13
+
14
+ list/get are read-only (planMode ok, no approval); set is a side effect (approval gate). The /config TUI command is the human equivalent.
@@ -1,5 +1,7 @@
1
1
  Load a project skill from .thincoder/skills/.
2
+
2
3
  Skills contain reusable instructions, workflows, or reference material.
3
4
  Use this when the user references a skill by name, or when a task matches a known skill's description.
5
+
4
6
  Call with action='list' to see available skills; call with action='load' and name=<skill> to activate one.
5
7
  Returns the skill list ('list'), the load confirmation ('load' — instructions arrive in the next message), or Error: ... with the available skills.
package/tool-docs/ssh.md CHANGED
@@ -1,26 +1,36 @@
1
- Open and drive a persistent interactive SSH session (remote login shell) on a host. The session survives across tool calls; password hosts get a credential window — the value never appears in tool args or results (an explicit opt-in can store it as ciphertext on this machine).
1
+ Open and drive a persistent interactive SSH session (remote login shell) on a host, and move single files to or from that host (`put` / `get`).
2
+
3
+ A session survives across tool calls. Password hosts get a credential window — the value never appears in tool args or results (an explicit opt-in can store it as ciphertext on this machine).
2
4
 
3
5
  **Route to ssh instead of bash:**
4
6
  - a one-shot non-interactive command over ssh → `bash` with `ssh host <command>` (cheaper, no session)
5
7
  - an interactive shell that must survive several calls (network device CLI, interactive prompts) → ssh
8
+ - one file to or from a host you already have a session on → `put` / `get` (they reuse the session's host and credential chain; `bash scp` cannot reach that chain, so a password host would ask again or fail)
9
+ - a whole directory tree, a resumable transfer or a progress bar → not this tool (single file only)
6
10
 
7
11
  Parameters:
8
- - action (required): connect | send | read | secret_input | close | list | credentials | forget
12
+ - action (required): connect | send | read | secret_input | close | list | credentials | forget | put | get
9
13
  - host: connect / forget — target host (IP or name)
10
14
  - user: connect — login user (optional: your local ssh config decides, else the user recorded for this host locally)
11
15
  - port: connect / forget — TCP port (optional, default 22)
12
16
  - label: connect — short human label for this session (optional); secret_input — label for the value being sent
13
- - promptPattern: connect — regex that marks the shell prompt as ready (optional): send/read then settle the moment the prompt appears instead of waiting out the silence window
17
+ - promptPattern: connect — regex that marks the shell prompt as ready (optional; the default recognises lines ending in `#` `>` `$` `%`)
14
18
  - identityFile: connect — private-key path to offer as `-i` (`~` expands); remembered for this host and reused when omitted (optional)
15
- - id: send / read / secret_input / close — session id from connect (`ssh#N`)
19
+ - id: send / read / secret_input / close / put / get — session id from connect (`ssh#N`)
16
20
  - data: send — text to type into the session (a trailing newline is passed as-is; otherwise Enter is sent as `\r`)
17
21
  - settle: send — wait for the ready verdict before returning (default true); false returns right after the bytes are written
18
- - timeoutMs: send / read — wait budget override (default 10000; the wait then returns partial output with a readable line)
19
- - maxChars: read — return cap override (default 8000; the full output stays in the session log)
22
+ - timeoutMs: send / read — wait budget override (default 60000; the wait ends as soon as the device is waiting for input — a prompt, `--More--`, a y/n or password prompt); put / get — transfer budget override (default 600000; on expiry the process tree is killed)
23
+ - maxChars: read — return-window override (default 8000): head 60% + a note + tail 40%, and the omitted middle stays in the session for the next read
24
+ - localPath: put / get — local file path (`~` expands; a file, never a directory)
25
+ - remotePath: put / get — path of that file on the session host (e.g. `/flash/img.bin`)
26
+ - overwrite: get — replace an existing local file (default false: an existing target is refused, never overwritten silently). put follows scp's own semantics: a same-named remote file is replaced
27
+ - protocol: put / get — `scp` (classic SCP protocol, the default, what network devices speak) | `sftp` (the SFTP subsystem, for hosts that only offer that). There is no automatic fallback between them
28
+ - ledger: the in-flight ledger row this call serves (`"#N"` or `"N"`) — required for `get` in engineering mode (the same write gate `write` goes through; `put` writes the remote host and needs no number)
20
29
 
21
30
  Output:
22
- - every result starts with the session status line: `[ssh (ssh#3) 10.0.0.5 — ready · idle 3s]`
23
- - connect returns the first screen; send returns the round's output plus the ready verdict (silence | prompt matched | timeout); read returns what arrived since the last read
31
+ - connect / send / read / secret_input / close / list / put / get results start with the session status line: `[ssh (ssh#3) 10.0.0.5 — ready · idle 3s]`
32
+ - connect returns the first screen; send returns the round's output plus the ready verdict (answer prompt such as `--More--` | prompt matched | timeout); read returns what arrived since the last read
33
+ - put / get return the status line, then exactly one more line — `put <localPath> → <remotePath> · N bytes · exit 0` (and the mirrored form for get). The file's content never enters the context: the bytes travel over the disk only, never through a result, a log or a message. On failure you get an `Error:` line plus the tail of scp's stderr (≤ 600 characters), with the exit code named
24
34
 
25
35
  Notes:
26
36
  - Key-first: keys, your ssh config and ssh-agent are always tried before any saved credential — a connect succeeds without a window
@@ -30,22 +40,25 @@ Notes:
30
40
  - Credential discipline: the password is asked for in a window and reaches ssh only through its child-process environment — never in tool
31
41
  args, never echoed in a result, never stored in plaintext. Any captured output containing that value (or a value given to secret_input)
32
42
  is scrubbed from the returned text and from the session log.
33
- - Saving a credential is opt-in: the credential window carries a `save` checkbox (off by default). When checked and authentication succeeds,
34
- the password is stored encrypted with your OS user account (Windows DPAPI) in a per-user file outside the repository; the store holds only
35
- ciphertext. A saved credential is reused silently — the next connect skips the window, and only after key
36
- authentication fails. The residual risk is honest: another process running as the same logged-in user can decrypt it; this protects the
37
- file at rest, not a compromised account. Saving is Windows-only for now; on other platforms the checkbox does not appear and the window
38
- keeps asking.
43
+ - Saving a credential is opt-in and belongs to `connect`: that credential window carries a `save` checkbox (off by default). When checked and authentication succeeds,
44
+ the password is stored encrypted with your OS user account (Windows DPAPI) in a per-user file outside the repository; the store holds only ciphertext. A saved credential is reused silently — the next connect skips the window, and only after key authentication fails.
45
+
46
+ The residual risk is honest: another process running as the same logged-in user can decrypt it; this protects the file at rest, not a compromised account. Saving is Windows-only for now; on other platforms the checkbox does not appear and the window keeps asking.
39
47
  - Fail-soft: an unreadable/undecryptable entry, a damaged store or a missing backend falls back to the credential window (the connection is
40
48
  not broken; undecryptable entries are kept). If the server rejects a saved credential it is deleted and the window is shown. A failed save
41
49
  never affects the connection.
42
50
  - secret_input is for device prompts (enable password, sudo, key passphrases): it opens the same kind of window, writes the value plus Enter, and returns only the output — the value is never shown.
43
51
  - Sessions: at most 4 live at once (a connect beyond the cap is refused — close one first). A session idle for 600s with no send/read is closed automatically. `close` ends it (stdin EOF → 1.5s grace → the process tree is killed). Ctrl+I (interrupt) does not kill sessions; a user Stop does.
44
- - Output is capped per return (8000 chars, tail kept); the full stream is always in the session log whose path connect returns.
52
+ - Output is a cleaned text stream: terminal escape sequences and CRLF noise are stripped, and the session log holds the same cleaned text as the result. Each return is a window (8000 chars: head + a note + tail); the omitted middle stays in the session, so another read collects it and a large configuration comes back in full.
45
53
  - Not for full-screen terminal UIs (vim/top/screen): output is read as a text stream — paged output such as `--More--` is shown as-is, not driven for you.
54
+ - Transfers are binary safe and single-file: no recursive directory sync, no resume, no progress bar, and the parameters take files only (a directory is not a valid `localPath` / `remotePath`). That status line under the header is the whole receipt — do not expect a byte-by-byte progress.
55
+ - `get` never overwrites silently and never creates directories: an existing local file is refused unless you pass `overwrite:true`, and the local parent directory must already exist (create it first — a mistyped `get` would otherwise land somewhere you cannot see).
56
+ - `put` on a password host re-runs the same credential decision as connect: keys first, then the saved credential (no window), then the credential window. That transfer window only asks for user / password — it carries no save checkbox (storing a credential belongs to `connect`); a session built by typing a password into the window without saving it has no password kept, so the next transfer asks again.
57
+ - If a transfer is killed at `timeoutMs`, a `get` removes the partial local file only when it was actually written by that transfer (an existing file scp never touched is kept — the receipt then says the target was left as it stands); after a `put` the remote host may keep a partial file — this tool does not clean it (resend the whole file with `overwrite:true`, or delete it on the host).
58
+ - Ready means the device is waiting for you, not that output stopped: a prompt or an answer prompt (`--More--`, y/n, password) ends the wait, and a slow operation that goes quiet keeps waiting instead of returning half of its output. If a device's prompt does not look like a shell prompt, pass `promptPattern` on connect — otherwise each command waits out the full timeout.
46
59
  - Host keys follow your local ssh config — the tool never rewrites known_hosts. A changed or untrusted key stops the connect with a readable error before any credential is asked for.
47
- - read / list / credentials are read-only (no approval prompt); connect / send / secret_input / close / forget pass the approval gate like any side-effecting tool, and secret_input shows a masked placeholder — the value itself is never in the approval text.
60
+ - read / list / credentials are read-only (no approval prompt); connect / send / secret_input / close / forget / put / get pass the approval gate like any side-effecting tool, and secret_input shows a masked placeholder — the value itself is never in the approval text. A transfer's approval text names both ends (`localPath` → `remotePath`) and never the file's content.
48
61
  - credentials lists saved entries (host / user / saved / last used — never a value); forget deletes the entry for a host (and optional port) and is idempotent — the next connect asks in the window again.
49
- - Not for file transfer or port forwarding — run `scp` / `sftp` / `ssh -L` through bash.
62
+ - Not for port forwarding (`ssh -L` / `-R`) — run that through `bash`.
50
63
 
51
64
  Availability: where the end has no UI to collect a credential (headless / ACP), connecting to a password host fails with a readable error — use keys or an ssh-agent there.
@@ -8,17 +8,27 @@ ONE tool, NINE actions — pick by what you need:
8
8
  - action:'send': STEER a running async subagent mid-flight — id + message (a direction, e.g. "check X, don't fixate on Y"). The child consumes it at its next turn boundary as an ORDINARY user instruction (non-interrupting; its discipline is unchanged — guidance, not a deviation waiver); returns {id,
9
9
  status:'delivered', queued}. Only RUNNING async children are targetable — sync/queued/settled/unknown error clearly; if the child settles first, its report carries an 'undelivered' note.
10
10
  - action:'escalate' (飞刀): hand an implementation task to a STRONGER model from your consult models; it gets WRITE access and does the work itself, then returns a post-op report (what changed, why, verification). Escalate EARLY, when the task calls for stronger hands (complex refactors, intractable
11
- bugs, intricate algorithms — or beyond your comfortable ability). Not available in engineering mode (implementation goes through eng-coder). Default-async at depth 0: ack {id, role:'escalate', status:'running'} returns immediately; the report arrives automatically with its mutations merged into
11
+ bugs, intricate algorithms — or beyond your comfortable ability). Not available in engineering mode (implementation goes through eng-coder).
12
+
13
+ Default-async at depth 0: ack {id, role:'escalate', status:'running'} returns immediately; the report arrives automatically with its mutations merged into
12
14
  your bookkeeping (pooled with the other role-domain spawns).
13
15
  - action:'cancel': STOP ONE background subagent — the id from the spawn return is REQUIRED (a blanket cancel is unsupported; Ctrl+C stops everything). Running aborts immediately ({id, status:'cancelled'}); queued is removed ({id, status:'cancelled', was:'queued'}; later positions shift). Other
14
- children and the session keep running. Cancel is a last resort: verify alarming signals with reliable checks (git/node — not guesses) first, and prefer scoped recovery — a running child's in-flight work dies with it, partial changes stay unmerged and unaudited. Background advisor reviews cancel
16
+ children and the session keep running. Cancel is a last resort: verify alarming signals with reliable checks (git/node — not guesses) first, and prefer scoped recovery — a running child's in-flight work dies with it, partial changes stay unmerged and unaudited.
17
+
18
+ Background advisor reviews cancel
15
19
  the same way (pass the review id — no token is issued for a cancelled review).
16
20
  - action:'consume-design' (engineering mode, parent side): chain-terminal token consumption — after the delivery is verified and the chain closes out, consume this design's token slot. Selectors — pass exactly ONE: designId (a single slot; optional for a single-design session), designIds (an
17
- explicit non-empty list), expired:true (every expired slot), or olderThanDays:N (every slot older than N days). A consumed slot mechanically rejects further spawns for the same designId — new work (deviation fixes included) needs a fresh design review and token. Idempotent
21
+ explicit non-empty list), expired:true (every expired slot), or olderThanDays:N (every slot older than N days). A consumed slot mechanically rejects further spawns for the same designId — new work (deviation fixes included) needs a fresh design review and token.
22
+
23
+ Idempotent
18
24
  (unknown/already-consumed = a no-op notice); batch calls report per-slot lines + a `consumed N` count line. Do NOT call while the chain is still open — fix rounds reuse the same slot.
19
25
  - action:'design-slots' (engineering mode, parent side): READ-ONLY inventory of this session's approved design token slots — one line per slot (designId, live|expired, ageDays, expiresAt, batch, designToken), oldest first, ending with a total/live/expired count line. Nothing is written. Use it to
20
26
  see what still holds a slot before consuming; the expired / olderThanDays selectors act on the same set.
21
- Every row carries its designToken value (expired ones included — status marks them; a malformed record shows designToken=—). Pass designId to filter to a single slot (trimmed exact match; unknown = refused with the held id list; empty string = no filter). Take designId + designToken verbatim onto
27
+ Every row carries its designToken value (expired ones included — status marks them; a malformed record shows designToken=—).
28
+
29
+ Pass designId to filter to a single slot (trimmed exact match; unknown = refused with the held id list; empty string = no filter).
30
+
31
+ Take designId + designToken verbatim onto
22
32
  the eng-coder spawn — the gate checks exact equality.
23
33
  - action:'panel': DIAGNOSE + fix the subagent panel (the collapsible blocks the user sees; headless/VS Code degrade to a 'no panel' pool view). view (default): the live blocks (key, role, status: running|done|awaitingDigest) exactly as the user sees them — digested-stuck entries carry digested:true.
24
34
  freeze: pass a digested-stuck block key (e.g. 'eng-coder#9' — {action:'panel', freeze:'role#N'}) to reclaim it into the conversation — passes ONLY for awaitingDigest blocks with no live pool entry and no pending report (a still-pending report would break the digestion order — refused).
@@ -31,34 +41,61 @@ Available roles (exposed per mode; the role is REQUIRED for action:'spawn' — a
31
41
  - coder — full implementation; the parent's complete read/write/execute toolset plus verify and advisor self-review. Its report carries a delivery table, one row per requirement (Done / Simplified / Not done — no deferred column). Normal mode: may optionally carry `batchDoc` — binds this spawn's §5
32
42
  record-write channel (unbound ⇒ the main agent records §5 on its behalf); when provided the path must resolve to a readable file.
33
43
  - eng-coder — engineering mode only (replaces coder): same toolset plus the design-driven methodology overlay; its delivery protocol (implementation → audit → self-fix → advisor re-review → converged delivery) runs fully inside the child. REQUIRES a valid designToken from a passed
34
- advisor(type='design') review — pass the exact value from that review, or copy it verbatim from the action:'design-slots' row (the text after designToken=): missing or mismatched = the spawn is refused, and an expired token is refused with expired named (its reply also echoes a designId — pass it:
35
- required to pick between concurrent designs, optional for one; echo it back in the delivery report). REQUIRES a batchDoc — the batch record path, the task book this spawn implements (refused without it or when it does not resolve to a readable file).
44
+ advisor(type='design') review — pass the exact value from that review, or copy it verbatim from the action:'design-slots' row (the text after designToken=): missing or mismatched = the spawn is refused,
45
+
46
+ and an expired token is refused with expired named (its reply also echoes a designId — pass it:
47
+ required to pick between concurrent designs, optional for one;
48
+
49
+ echo it back in the delivery report). REQUIRES a batchDoc — the batch record path, the task book this spawn implements (refused without it, when it does not resolve to a readable file, or when that record already has an in-flight spawn).
50
+
51
+ One batch record serves one concurrent spawn: wait for the occupant to settle, or cancel it.
36
52
  - eng-designer — engineering mode only: the SOLE author of the design documents and of the batch record's design section (requirement docs stay with the main agent). Writes no implementation code, does not edit prompts, does not fire reviews, needs NO designToken. Surveys on its own; may only spawn
37
53
  read-only explore children (sync, ≤6 per batch). REQUIRES a batchDoc (same gate as eng-coder).
54
+ - tester — BOTH modes: the readings seat. It runs the verification commands the task book puts in `goal` and hands the readings back as they stand —
55
+ no verdict, no fix, no document of any kind.
56
+
57
+ Tool face = the read-only tools plus `execute` / `bash` (dependency installs, compiles and fixtures included), minus `verify` (a verdict tool).
58
+
59
+ Run only, never change is a role contract, not a sandbox — `bash` can write, so a tester that edits anything is treated by the parent as a defect.
60
+
61
+ Task book (non-engineering roles: explore / plan / coder / tester): four core structured parameters — goal (goal & why), knownFacts (the facts you already verified), acceptance (machine-verifiable criteria), reportFormat (delivery-report format)
38
62
 
39
- Task book (normal-mode roles: explore / plan / coder): four core structured parameters — goal (goal & why), knownFacts (the facts you already verified), acceptance (machine-verifiable criteria), reportFormat (delivery-report format)
40
63
  — plus scope (scope & forbidden scope — what to read / what not to touch).
41
64
  All five are required: a missing, blank or non-string value is refused with the parameter named.
42
65
  A free-text task is an optional supplement, never the whole brief.
66
+
43
67
  Engineering roles (eng-coder / eng-designer) take their task book from the batch record: batchDoc (the record path) and round (initial|fix), plus files / dependsOn for scheduling; the child reads §2 of that record itself — no other task text is passed.
68
+
44
69
  An eng-coder spawn also carries designToken — the write credential (the exact value from the review, or copied verbatim from the action:'design-slots' row, the text after designToken=), and designId when several designs are open: missing or mismatched = the spawn is refused.
45
70
 
71
+ A record carries one concurrent spawn at a time: a second spawn on a record still in flight is refused, naming the occupant — sequential hand-offs (design → implementation → fix round) pass, because the previous spawn has settled first.
72
+
46
73
  Pass one parameter per field — contents only (the runtime adds the labels):
47
74
  subagent(role="eng-coder", round="initial", batchDoc="<batch record>", designToken="…", files=[…])
48
75
  subagent(role="explore", goal="…", knownFacts="…", scope="…", acceptance="…", reportFormat="…")
49
76
 
50
- Mode filtering: normal mode exposes explore/plan/coder; engineering mode exposes explore/eng-designer/eng-coder — off-mode roles are refused mechanically (enums filtered at assembly; the spawn gate re-checks).
77
+ Mode filtering: normal mode exposes explore/plan/coder/tester (eng-coder and eng-designer are refused); engineering mode exposes explore/eng-designer/eng-coder/tester (plan and coder are refused — plan is a normal-mode role, coder is replaced by eng-coder; tester is dispatchable in both modes).
78
+
79
+ The role enum is filtered per mode at assembly, and the spawn gate refuses out-of-mode roles mechanically.
51
80
 
52
- Async spawn: top-level spawns are async by default — never pass async:false at depth 0 (the spawn returns {id, status:"running"} immediately; the report arrives automatically; if your next step needs it, end the turn and let the digest deliver it — do not poll; the explicit async:false is a
53
- mechanism parameter, not for model use). Inside subagents (depth>0) spawns are always synchronous. Async spawns are pooled per role domain — 4 concurrent eng-coders plus 4 concurrent other-role spawns by default (agent.poolLimits overrides both); a full domain queues further spawns with a position
81
+ Async spawn: top-level spawns are async by default — never pass async:false at depth 0 (the spawn returns {id, status:"running"} immediately; the report arrives automatically; if your next step needs it, end the turn and let the digest deliver it — do not poll;
82
+
83
+ the explicit async:false is a
84
+ mechanism parameter, not for model use). Inside subagents (depth>0) spawns are always synchronous.
85
+
86
+ Async spawns are pooled per role domain — 4 concurrent eng-coders plus 4 concurrent other-role spawns by default (agent.poolLimits overrides both); a full domain queues further spawns with a position
54
87
  while the other keeps starting.
55
88
 
56
- Task scheduling: declare files (the file paths this task will modify) and dependsOn (ids from prior async returns whose outcome this task needs) to let the scheduler order your spawns. Overlapping-file tasks serialize and dependents start in order: a conflicting/dependent spawn queues
57
- (position/reason) and auto-starts when the conflict clears / the dependency settles (cancel to drop). A cancelled/failed dependency leaves it queued marked "dependency cancelled" until you decide (AUTO sessions auto-start). Unknown ids error; a consumed id counts as satisfied. Omit both for a plain
89
+ Task scheduling: declare files (the file paths this task will modify) and dependsOn (ids from prior async returns whose outcome this task needs) to let the scheduler order your spawns.
90
+
91
+ Overlapping-file tasks serialize and dependents start in order: a conflicting/dependent spawn queues
92
+ (position/reason) and auto-starts when the conflict clears / the dependency settles (cancel to drop).
93
+
94
+ A cancelled/failed dependency leaves it queued marked "dependency cancelled" until you decide (AUTO sessions auto-start). Unknown ids error; a consumed id counts as satisfied. Omit both for a plain
58
95
  immediate spawn (no scheduler involvement).
59
96
 
60
97
  Writing the prompt:
61
98
  - The child starts with zero context — brief it like a colleague who just walked in: goal, what you already know, the specifics.
62
99
  - Put exact paths and commands in — do not make it search for what you already know.
63
- - Do not delegate understanding: resolve the paths/line numbers the task hinges on first.
100
+ - Do not delegate understanding: resolve the paths and the symbols the task hinges on first.
64
101
  - Once it runs, leave that scope to it — don't redo its searches in parallel or finish manually midway.
package/tool-docs/task.md CHANGED
@@ -1,7 +1,9 @@
1
1
  Plan and track a task list for complex multi-step work.
2
2
  Each call replaces the entire list.
3
3
  Keep exactly one item in_progress at a time; mark items done as you complete them; never mark done if tests fail or work is partial.
4
+
4
5
  Statuses: pending | in_progress | done — synonyms (completed/finished/complete, todo/open/waiting, active/running/working, …) are accepted and normalized with a warning.
5
6
  IMPORTANT: title is required and must be a non-empty string — items with empty titles are silently dropped.
7
+
6
8
  For cross-session / project-level tracking, use `/ledger`.
7
9
  Returns the updated task list (or the new item's ID on add).
@@ -5,5 +5,5 @@
5
5
  - count:同 query 参数,出 total。
6
6
  - add:title 必填(≤200)∥ detail(≤4000)∥ owner(缺省 = 自己)——status 恒 待讨论。
7
7
  - update:id 必填;title / detail / owner / status 至少一件;status = 迁移表合法后继(待讨论→待设计 ∥ 待设计→在途 ∥ 在途→待核销 ∥ 待核销→已核销 ∥ 未归档→已废弃);已归档(已核销 / 已废弃)⇒ 拒;仓不可改。
8
- - close:id + status(已核销 ∥ 已废弃)——已核销:勾销(待核销)/ 追认核销(待讨论 ∥ 待设计,须正文非空);已废弃 = 撤回(任意未归档态)。
8
+ - close:id + status(已核销 ∥ 已废弃)——已核销:勾销(只自 待核销;其余现态 400,出路 = 先 PATCH 推进到 待核销);已废弃 = 撤回(任意未归档态)。
9
9
  - 登录态门:未登录 ⇒ 明示「未登录」且零请求;401(token 失效)⇒ 「登录已失效——请重新登录」;不可达 ⇒ 「服务器不可达」(零离线缓存,重试不落旧值)。
@@ -1,13 +1,20 @@
1
1
  Set a timer before you start analyzing code.
2
2
  When the timer fires, a system reminder will be injected suggesting you try running code or adding debug logs.
3
3
  Use this to enforce a thinking budget: you get N seconds to reason, then the timer reminds you to act.
4
+
4
5
  Beyond a one-shot countdown, three schedule forms are available, one per call (`seconds`, `at`, `every` and `daily` are mutually exclusive — passing more than one is a validation error):
6
+
5
7
  `at` takes a local clock time such as "2026-10-13T09:00" and fires once at that moment — a time already past fires immediately.
6
8
  `every` takes a fixed interval in seconds (minimum 60): the first reminder comes N seconds after setting, then every N seconds, until cancelled.
9
+
7
10
  `daily` takes a local "HH:MM" and repeats every day at that time (a time already past today fires tomorrow), until cancelled.
8
11
  All times are local to the host.
12
+
9
13
  `cancel` takes the id from the set confirmation and stops that timer; `list` shows every pending timer with its next due time. Repeating timers occupy one pending slot each until cancelled.
10
14
  Returns the set confirmation — the reminder fires at the deadline.
15
+
11
16
  Delivery: when the session is idle it is delivered on the spot and starts a turn — the idle wake is available on the CLI / VSC / desktop foregrounds and suspension windows (headless is structurally unsupported).
17
+
12
18
  A user turn gets no delivery: while a session turn is running, an expired timer waits for the next delivery round (suspension window / idle latch); other paths keep the step-boundary behavior.
19
+
13
20
  A pending timer survives across runs; at most 8 timers may be pending at once, and further timer calls are rejected until some expire.
@@ -1 +1,13 @@
1
- Generic pre-completion verification gate — language/framework/project agnostic. verify does NOT run any test/verification command for you and does NOT require a test per change. You DECLARE your verification status via the verification argument ({ status: 'passed' | 'failed' | 'skipped', command?, summary?, basis? } — effects per parameter): the declaration is self-reported evidence — verify only mechanically gates on it ('passed' → allowed; 'failed' → blocked; 'skipped' → allowed but needs a reason). 'basis' (optional) is the 'what it stands on' dimension of the declaration — a judgment source, a read file:line coordinate, or an explicit 'unverified' (declaration-only: no format is enforced or machine-checked); a passed / skipped declaration with no basis gets one advisory hint line in the report — never blocking and never changing the gate — while the failed face gets no basis hint (already blocked). Whether/how to verify is described in natural language in the project's AGENTS.md and is decided + executed by you. The report also carries the changed files (git diff), an advisory node --check hint on changed .js/.mjs (not gating), the task list, and a self-review checklist. Call this BEFORE declaring a coding task complete — do not say 'done' until verify passes.
1
+ Generic pre-completion verification gate — language/framework/project agnostic. verify does NOT run any test/verification command for you and does NOT require a test per change.
2
+
3
+ You DECLARE your verification status via the verification argument ({ status: 'passed' | 'failed' | 'skipped', command?, summary?, basis? } — effects per parameter): the declaration is self-reported evidence —
4
+
5
+ verify only mechanically gates on it ('passed' → allowed; 'failed' → blocked; 'skipped' → allowed but needs a reason).
6
+
7
+ 'basis' (optional) is the 'what it stands on' dimension of the declaration — a judgment source, the exact words you read at their path, or an explicit 'unverified' (declaration-only: no format is enforced or machine-checked);
8
+
9
+ a passed / skipped declaration with no basis gets one advisory hint line in the report — never blocking and never changing the gate — while the failed face gets no basis hint (already blocked).
10
+
11
+ Whether/how to verify is described in natural language in the project's AGENTS.md and is decided + executed by you. The report also carries the changed files (git diff), an advisory node --check hint on changed .js/.mjs (not gating), the task list, and a self-review checklist.
12
+
13
+ Call this BEFORE declaring a coding task complete — do not say 'done' until verify passes.
@@ -1,4 +1,6 @@
1
- Search the web (DeepSeek Search when a DeepSeek provider is configured; otherwise Tavily with a key, else Bing). Returns result titles, URLs, and snippets — DeepSeek results also carry a date · authority (0–4) · rerank (0–3) line and a long summary. Use for looking up current information, docs, error messages.
1
+ Search the web (DeepSeek Search when a DeepSeek provider is configured; otherwise Tavily with a key, else Bing). Returns result titles, URLs, and snippets — DeepSeek results also carry a date · authority (0–4) · rerank (0–3) line and a long summary.
2
+
3
+ Use for looking up current information, docs, error messages.
2
4
 
3
5
  Parameters:
4
6
  - query (required): Search query
@@ -9,3 +9,5 @@ Notes:
9
9
  - Returns `Wrote N chars to <path>` + git diff + syntax-check note.
10
10
  - This overwrites the entire file — use `edit` for targeted changes
11
11
  - The file is atomic: it either writes completely or fails
12
+
13
+ **`ledger`** — the in-flight ledger row this call serves: `"#N"` or `"N"`. In engineering mode the parent agent must pass it — a call that does not say which row it serves is refused.
package/tools/bash.mjs CHANGED
@@ -3,12 +3,16 @@ import {
3
3
  sanitizeOutput,
4
4
  truncate,
5
5
  makeDecoder,
6
- BASH_TIMEOUT_MS,
6
+ BASH_TIMEOUT_MS,
7
+ LEDGER_PARAM_DESC,
8
+ PROJECT_PARAM_DESC,
7
9
  } from "./shared.mjs";
8
10
  import { spawn } from "node:child_process";
9
11
  // 树杀单源(台账 #208② · TOOLS.md §6.14 落位表行 2):本地副本删除——改用 `./process-tree.mjs`
10
12
  // (行为逐字同:win32 `taskkill /T /F` · POSIX 组杀 + 直杀兜底)。
11
13
  import { killProcessTree } from "./process-tree.mjs";
14
+ // 过程档标记(TOOLS.md §6.28):输出里行首路径 token 真解析到盘上的过程档行 ⇒ 行首前缀 + 末尾汇总行。
15
+ import { markProcessDocLines } from "./process-doc-mark.mjs";
12
16
  import { resolveShellIdentity } from "../shell-identity.mjs";
13
17
 
14
18
  /** Maximum buffer size per stream (stdout / stderr) before truncation */
@@ -247,6 +251,9 @@ export const bashTool = {
247
251
  timeout: { type: "number", description: `Timeout in ms (default ${BASH_TIMEOUT_MS} for synchronous runs; background runs have no default — an explicit timeout still applies)` },
248
252
  async: { type: "boolean", description: "Run in the background (default false): returns an ack at once (bash#<id>, log path) and the result arrives as a digest when the process exits. Depth-0 only." },
249
253
  filter: { type: "string", description: "Optional: only return output lines matching this regex (case-insensitive; synchronous runs only)" },
254
+ ledger: { type: "string", description: LEDGER_PARAM_DESC },
255
+ // 项目声明面(决策 40):`bash` 没有定位参数 ⇒ 判据点只能靠声明;纯声明,命令仍在会话 cwd 执行。
256
+ project: { type: "string", description: PROJECT_PARAM_DESC },
250
257
  },
251
258
  required: ["command"],
252
259
  },
@@ -288,7 +295,10 @@ export const bashTool = {
288
295
  shell: ctx.agent?.config?.shell ?? null,
289
296
  })
290
297
  const filtered = args.filter ? applyLineFilter(result, args.filter) : result
291
- const body = guard ? `${guard.notice}\n\n${filtered}` : filtered
298
+ // §6.28:顺序写死 = **过滤 → 打标 → 汇总 → 外包装**(filter 才照旧匹配原始行,前缀不吃
299
+ // 过滤命中;`guard.notice` ∥ `hint` 包在标之外)。解析基准 = 子进程 cwd(同步径 = `ctx.cwd`)。
300
+ const marked = markProcessDocLines(filtered, ctx.cwd)
301
+ const body = guard ? `${guard.notice}\n\n${marked}` : marked
292
302
  return hint ? `${hint}\n${body}` : body
293
303
  },
294
304
  }