@thincoder/core 0.9.4 → 0.10.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 (221) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +1 -1
  3. package/abort-provenance.mjs +10 -10
  4. package/advisor/citations.mjs +5 -5
  5. package/advisor/compaction.mjs +16 -15
  6. package/advisor/loop.mjs +14 -14
  7. package/advisor/messages.mjs +6 -6
  8. package/advisor/project-context.mjs +5 -5
  9. package/advisor/repos.mjs +3 -3
  10. package/advisor/run.mjs +23 -13
  11. package/advisor.mjs +4 -4
  12. package/agent/assemble.mjs +111 -0
  13. package/agent/chat-call.mjs +68 -0
  14. package/agent/child-marks.mjs +2 -2
  15. package/agent/completion.mjs +9 -2
  16. package/agent/continue-decision.mjs +25 -0
  17. package/agent/dispatch-gates.mjs +140 -0
  18. package/agent/dispatch-run.mjs +167 -0
  19. package/agent/dispatch.mjs +55 -294
  20. package/agent/family-tools.mjs +11 -11
  21. package/agent/helpers.mjs +63 -3
  22. package/agent/live-beat.mjs +49 -0
  23. package/agent/post-turn.mjs +4 -8
  24. package/agent/record-results.mjs +23 -20
  25. package/agent/relay-prefix.mjs +2 -2
  26. package/agent/run-stages.mjs +19 -15
  27. package/agent/run-start.mjs +111 -0
  28. package/agent/setup-reminders.mjs +9 -9
  29. package/agent/setup.mjs +32 -4
  30. package/agent/spawn-child.mjs +9 -9
  31. package/agent/suspension.mjs +90 -30
  32. package/agent/timers.mjs +113 -0
  33. package/agent/turn-loop.mjs +244 -0
  34. package/agent/write-gate.mjs +103 -6
  35. package/agent-tools/advisor-async.mjs +11 -11
  36. package/agent-tools/advisor-settle.mjs +17 -17
  37. package/agent-tools/advisor.mjs +38 -43
  38. package/agent-tools/async-discard.mjs +44 -1
  39. package/agent-tools/async-settle.mjs +23 -20
  40. package/agent-tools/audit-block.mjs +7 -7
  41. package/agent-tools/bash-async.mjs +281 -0
  42. package/agent-tools/batch-lifecycle.mjs +65 -34
  43. package/agent-tools/batch-paths.mjs +186 -0
  44. package/agent-tools/batch-skeleton.mjs +19 -1
  45. package/agent-tools/batch.mjs +22 -119
  46. package/agent-tools/checkpoint.mjs +121 -0
  47. package/agent-tools/child-permission.mjs +5 -3
  48. package/agent-tools/consult.mjs +58 -58
  49. package/agent-tools/context.mjs +4 -20
  50. package/agent-tools/design-token.mjs +3 -3
  51. package/agent-tools/digest-budget.mjs +1 -1
  52. package/agent-tools/eng.mjs +5 -5
  53. package/agent-tools/escalate-async.mjs +18 -13
  54. package/agent-tools/goal.mjs +3 -10
  55. package/agent-tools/panel-blocks.mjs +3 -3
  56. package/agent-tools/parent-channel.mjs +3 -13
  57. package/agent-tools/plan.mjs +3 -4
  58. package/agent-tools/read-history.mjs +12 -28
  59. package/agent-tools/recent-changes.mjs +4 -5
  60. package/agent-tools/review-facts.mjs +1 -1
  61. package/agent-tools/settings.mjs +47 -20
  62. package/agent-tools/skill.mjs +3 -5
  63. package/agent-tools/spawn-gates.mjs +3 -3
  64. package/agent-tools/subagent-actions-query.mjs +270 -0
  65. package/agent-tools/subagent-actions.mjs +29 -273
  66. package/agent-tools/subagent-async.mjs +36 -31
  67. package/agent-tools/subagent-panel.mjs +38 -9
  68. package/agent-tools/subagent-run.mjs +44 -29
  69. package/agent-tools/subagent-scheduler.mjs +29 -28
  70. package/agent-tools/subagent-spawn.mjs +57 -25
  71. package/agent-tools/subagent.mjs +46 -66
  72. package/agent-tools/task.mjs +3 -9
  73. package/agent-tools/timer.mjs +12 -12
  74. package/agent-tools/verify.mjs +14 -13
  75. package/agent-tools.mjs +0 -1
  76. package/agent.mjs +20 -351
  77. package/attachments.mjs +125 -0
  78. package/auto-think.mjs +1 -1
  79. package/config-presets.mjs +12 -7
  80. package/config-watch.mjs +83 -0
  81. package/config.mjs +17 -4
  82. package/context-degrade.mjs +81 -0
  83. package/context-echo.mjs +88 -0
  84. package/context-push.mjs +51 -0
  85. package/context.mjs +8 -187
  86. package/conventions.mjs +110 -161
  87. package/declaration.mjs +194 -0
  88. package/embedding.mjs +3 -1
  89. package/env-ref.mjs +81 -0
  90. package/explore-distill.mjs +2 -3
  91. package/file-links.mjs +53 -0
  92. package/file-refs.mjs +103 -0
  93. package/generate-title.mjs +28 -4
  94. package/git/checkpoint.mjs +4 -8
  95. package/history-window.mjs +17 -2
  96. package/i18n.mjs +2 -0
  97. package/index-discover.mjs +7 -7
  98. package/ledger-cmd.mjs +34 -126
  99. package/ledger-db.mjs +35 -7
  100. package/ledger-migrate.mjs +299 -0
  101. package/ledger-tools.mjs +188 -0
  102. package/ledger.mjs +11 -5
  103. package/log.mjs +12 -7
  104. package/manifest-discovery.mjs +131 -0
  105. package/manifest-schema.mjs +166 -0
  106. package/manifest.mjs +18 -217
  107. package/mcp.mjs +4 -1
  108. package/memory/code-search.mjs +149 -0
  109. package/memory/code-sync.mjs +89 -230
  110. package/memory/core.mjs +47 -32
  111. package/memory/docs.mjs +63 -262
  112. package/memory/file-list.mjs +89 -0
  113. package/memory/file-walk.mjs +7 -4
  114. package/memory/memory-tool.mjs +229 -0
  115. package/memory/schema.mjs +18 -3
  116. package/memory/sweep.mjs +289 -0
  117. package/memory/sync-tail.mjs +81 -0
  118. package/memory-status.mjs +69 -0
  119. package/memory.mjs +3 -0
  120. package/model-specs.mjs +131 -66
  121. package/notify-policy.mjs +51 -0
  122. package/package.json +1 -1
  123. package/peer-claims.mjs +263 -0
  124. package/peer-domains.mjs +100 -71
  125. package/peer-instances.mjs +9 -10
  126. package/process-probe-exec.mjs +187 -0
  127. package/process-probe.mjs +27 -175
  128. package/prompt-overlays.mjs +11 -10
  129. package/prompts/advisor-design.md +2 -2
  130. package/prompts/advisor-round2.md +1 -1
  131. package/prompts/advisor-round3.md +1 -1
  132. package/prompts/common.md +19 -7
  133. package/prompts/discipline-engineering.md +57 -16
  134. package/prompts/discipline-normal.md +6 -3
  135. package/prompts/persona-coder.md +0 -1
  136. package/prompts/persona-eng-coder.md +1 -5
  137. package/prompts/persona-eng-designer.md +1 -2
  138. package/prompts/persona-engineering.md +41 -11
  139. package/prompts/persona-explore.md +0 -1
  140. package/prompts/persona-normal.md +10 -1
  141. package/prompts/persona-plan.md +3 -4
  142. package/prompts/subagent-base.md +14 -0
  143. package/provider/core.mjs +11 -48
  144. package/provider/list-models.mjs +3 -0
  145. package/provider/responses-request.mjs +237 -0
  146. package/provider/responses.mjs +6 -228
  147. package/provider-flows.mjs +248 -0
  148. package/queued.mjs +90 -0
  149. package/rules.mjs +209 -2
  150. package/session-gc.mjs +67 -6
  151. package/session-guard.mjs +27 -7
  152. package/session-lifecycle.mjs +90 -18
  153. package/session-rename.mjs +5 -1
  154. package/session-slot-claims.mjs +230 -0
  155. package/session-slot-scan.mjs +299 -0
  156. package/session-slot-verify.mjs +304 -0
  157. package/session-slot-write.mjs +74 -8
  158. package/session-slots-manifest.mjs +163 -236
  159. package/session-slots.mjs +99 -71
  160. package/session.mjs +30 -10
  161. package/shell-candidates.mjs +78 -0
  162. package/text-budget.mjs +2 -2
  163. package/think-off.mjs +49 -0
  164. package/token-ttl.mjs +15 -4
  165. package/tool-args.mjs +73 -0
  166. package/tool-docs/advisor.md +9 -0
  167. package/tool-docs/batch.md +1 -0
  168. package/tool-docs/code_search.md +1 -0
  169. package/tool-docs/consult_start.md +5 -0
  170. package/tool-docs/consult_stop.md +3 -0
  171. package/tool-docs/context.md +7 -0
  172. package/tool-docs/doc_search.md +1 -0
  173. package/tool-docs/edit.md +2 -13
  174. package/tool-docs/eng.md +1 -0
  175. package/tool-docs/execute.md +1 -9
  176. package/tool-docs/git.md +25 -51
  177. package/tool-docs/goal.md +6 -0
  178. package/tool-docs/ledger_add.md +1 -0
  179. package/tool-docs/ledger_close.md +1 -0
  180. package/tool-docs/ledger_count.md +1 -0
  181. package/tool-docs/ledger_query.md +1 -0
  182. package/tool-docs/ledger_update.md +1 -0
  183. package/tool-docs/main_history.md +1 -0
  184. package/tool-docs/memory.md +10 -0
  185. package/tool-docs/notify_parent.md +9 -0
  186. package/tool-docs/peer_instances.md +1 -0
  187. package/tool-docs/plan.md +5 -0
  188. package/tool-docs/process.md +7 -3
  189. package/tool-docs/question.md +1 -0
  190. package/tool-docs/read_history.md +7 -0
  191. package/tool-docs/recent_changes.md +1 -0
  192. package/tool-docs/repo_outline.md +1 -0
  193. package/tool-docs/settings.md +6 -0
  194. package/tool-docs/skill.md +5 -0
  195. package/tool-docs/subagent.md +31 -0
  196. package/tool-docs/task.md +7 -0
  197. package/tool-docs/timer.md +6 -0
  198. package/tool-docs/verify.md +1 -0
  199. package/tool-docs/wait_for.md +2 -1
  200. package/tools/bash.mjs +28 -4
  201. package/tools/edit-batch.mjs +10 -11
  202. package/tools/edit-diff.mjs +33 -25
  203. package/tools/exec-run.mjs +102 -4
  204. package/tools/execute.mjs +5 -2
  205. package/tools/file.mjs +11 -12
  206. package/tools/git-run.mjs +1 -1
  207. package/tools/git.mjs +0 -24
  208. package/tools/glob-dialect.mjs +3 -3
  209. package/tools/index.mjs +2 -1
  210. package/tools/linter.mjs +2 -1
  211. package/tools/node-child.mjs +21 -0
  212. package/tools/ops.mjs +50 -13
  213. package/tools/patch.mjs +4 -2
  214. package/tools/repomap.mjs +20 -9
  215. package/tools/search.mjs +2 -2
  216. package/tools/shared.mjs +9 -7
  217. package/tools/web.mjs +5 -2
  218. package/tools/write-path.mjs +1 -1
  219. package/traces/trace-store.mjs +17 -14
  220. package/vision-reader.mjs +76 -0
  221. package/agent-tools/batch-segment.mjs +0 -18
package/tool-args.mjs ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * tool-args.mjs — 工具调用参数的可读展示**单源**(B7 1a 上提:体 = CLI
3
+ * `thincoder-cli/src/tui/tool-args.mjs` `describeToolArgs` 现体——覆盖 15+ 工具族,最全)。
4
+ *
5
+ * 消费面:CLI 标题行 ∕ 恢复面(核件同名转口——`toolArgsLines` 留端)· desk
6
+ * `agent-bridge.mjs` 保名转口(`describeToolArgs as summarizeArgs`——回调桥 ∕ 待决门 payload 共用一份口径)·
7
+ * advisor 进度行(端装配层经 `seams.describeArgs` 注入——`advisor/loop.mjs`)。
8
+ * 单源一句话:按工具挑关键参数的可读单行摘要;未知工具回退单行紧凑 JSON。
9
+ *
10
+ * 已登记差额(B7 §2 修正轮 1 ⑨——展示面、非语义差):默认分支截断 = 本档简版切片(`slice`
11
+ * 码元截断)替代 CLI `render.mjs` `sliceByWidth`(宽度感知 ∕ 全角计宽)⇒ 全角字符截断
12
+ * 续接点可异于 CLI 现端(160 ∕ 80 两档触发)。
13
+ */
14
+
15
+ /** 单行参数摘要:按工具挑关键字段(卡片头口径),未知工具回退 JSON。 */
16
+ export function describeToolArgs(name, args) {
17
+ if (!args || typeof args !== "object") return ""
18
+ const a = args
19
+ switch (name) {
20
+ case "bash": case "cmd-shell": {
21
+ const cmd = String(a.command ?? "").replace(/\s+/g, " ").trim()
22
+ return cmd ? cmd + (a.workdir ? ` (in ${a.workdir})` : "") : ""
23
+ }
24
+ case "read": case "write": case "edit": case "hashline_edit": {
25
+ const p = a.path ? String(a.path) : ""
26
+ const extras = [
27
+ a.offset ? `offset ${a.offset}` : "",
28
+ a.limit ? `limit ${a.limit}` : "",
29
+ name === "edit" && a.old_string ? `old: ${String(a.old_string).replace(/\s+/g, " ").trim().slice(0, 30)}` : "",
30
+ ].filter(Boolean).join(", ")
31
+ return p ? `"${p}"${extras ? " · " + extras : ""}` : extras
32
+ }
33
+ case "grep": case "glob": case "code_search": case "doc_search": case "search": {
34
+ const pat = a.pattern ?? a.query ?? ""
35
+ const p = a.path ? ` in "${a.path}"` : ""
36
+ return `/${String(pat)}/${p}`
37
+ }
38
+ case "ls": {
39
+ const p = a.path ? String(a.path) : "."
40
+ return a.filter ? `${p} (filter: ${String(a.filter)})` : p
41
+ }
42
+ case "websearch": return String(a.query ?? "")
43
+ case "subagent": case "coder": case "explore": case "plan": case "eng-coder": case "eng-designer": {
44
+ const task = String(a.task ?? "").replace(/\s+/g, " ").trim()
45
+ if (task) return task.slice(0, 60) + (task.length > 60 ? "…" : "")
46
+ // action-only 调用(status ∕ observe ∕ send ∕ cancel ∕ escalate ∕ consume-design…)无 task——action 兜底(2.4 批)
47
+ return a.action ? `(${String(a.action)})` : ""
48
+ }
49
+ case "advisor": return String(a.type ?? "review")
50
+ case "read_image": return String(a.path ?? "")
51
+ case "question": return String(a.question ?? "").replace(/\s+/g, " ").trim().slice(0, 60)
52
+ case "memory": {
53
+ // §6 action-routed summary (D-M5): one readable line per action
54
+ const action = String(a.action ?? "")
55
+ if (action === "put") return String(a.title ?? "")
56
+ if (action === "search") return String(a.query ?? "")
57
+ if (action === "list") return [a.layer && `layer ${a.layer}`, a.type && `type ${a.type}`, a.keyword && `kw ${a.keyword}`].filter(Boolean).join(" ")
58
+ if (action === "delete") return a.id ? `id ${a.id}${a.layer ? ` (layer ${a.layer})` : ""}` : `batch ${a.layer ?? ""} ${a.type ? `type ${a.type} ` : ""}${a.keyword ? `kw ${a.keyword}` : ""}`.trim()
59
+ if (action === "clear") return `clear ${a.layer ?? ""}`
60
+ return action || JSON.stringify(a)
61
+ }
62
+ case "lsp": return [a.subcommand, a.uri].filter(Boolean).map(String).join(" ")
63
+ case "repo_outline": return a.path ? String(a.path) : ""
64
+ case "checkpoint": return [a.checkpointAction ?? a.action, a.checkpointId, a.path].filter(Boolean).map(String).join(" ")
65
+ case "git": return [a.action, a.ref, a.name, a.message].filter(Boolean).map(String).join(" ").slice(0, 60)
66
+ default: {
67
+ // MCP 工具 ∕ 未知工具:单行紧凑 JSON(与卡片头原始 JSON 截断口径同族)。硬上限 160:
68
+ // 超大 arguments(如 execute 的千字符 code)绝不进单行头。截断 = 简版切片(见档头差额)。
69
+ const s = JSON.stringify(a)
70
+ return s.length > 160 ? s.slice(0, 156) + "…" : s.length > 80 ? s.slice(0, 78) + "…" : s
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,9 @@
1
+ Run an independent review of your work. `type` is REQUIRED — one of exactly two values: 'design' reviews design / requirement documents BEFORE implementation (documents=[...] with the explicit doc paths; plus batchDoc when a batch record is in flight); 'code' reviews the code you changed AFTER implementation (paths=[...] to scope files/directories; documents=[...] adds acceptance-criteria context). A call without a type (or with a conflicting object.type) is refused — no default, no silent fallback.
2
+
3
+ The advisor is an independent read-only sub-agent (explores the codebase, reads files, traces callers via grep/lsp). Code review converges: round 1 full review → round 2 verifies the agent's fix claims → round 3+ re-checks only the fix claims. Design review is a single pass against methodology and requirements. Criteria come from .thincoder/advisor.md (if present) or sensible defaults. After the review you MUST produce a response table (format = discipline rules); on all-clear, call verify.
4
+
5
+ object={type,target,status,reason,exclude} optionally anchors the review target — mechanically injected at the start of the review message; absent = no injection.
6
+
7
+ ASYNC (depth 0 only): the review runs in the BACKGROUND by default — ack immediately, the report arrives automatically in a digest turn. One shared pool (agent.poolLimits.advisor, default 4 — configurable via /config 并发池 or config.json; pool-full and same-scope launches are refused stating the current limit) — launch reviews one at a time. Inside a child (depth>0) reviews are always synchronous (async:true rejected).
8
+
9
+ Returns the verdict: all-clear (call verify) or a findings list to fix.
@@ -0,0 +1 @@
1
+ Batch-record lifecycle tool (一段一作者 — six append-only sections, one author each). actions: create (depth-0 only — write a new six-section skeleton record; pass path + topic + source) · append (add text to the END of YOUR section — existing lines are never rewritten or deleted) · status (update YOUR section's `**状态行**:` line — the value must carry exactly ONE legal keyword of your section's STATUS_WORDS entry, decorated only by surrounding symbols / a trailing ISO date / whitespace; prose goes to the separate `note` field, which lands as a parenthetical) · close (depth-0 only — freeze the record: §1 → 「已收口 <date>」, every further write is refused). Identity fixes what you may write (段白名单): main agent (depth 0) — append §1/§4/§6, status §1 only, create/close; eng-designer — §2; eng-coder — §5; design review (review binding) — §3. A write outside your own section is refused. Skeleton placeholders (dead literals — `#<编号>` / `<板块>` and the older `<BATCH-ID>` / `<讨论来源>`) in the record header or in your target section block append/status: fill them first (the main agent fills the header right after create); `<§N 模板占位:…>` template lines are legal and never blocked. Target record: sub-agents and design reviews have NO path parameter in practice — the record arrives via the spawn binding / the review instance key (passing path is refused); depth-0 MAY pass path (若传则须可读), omitting it picks the unique in-flight record (0 or ≥2 in flight ⇒ refuse — pass path). A design review's append is stamped by the tool with a `### 轮次 N(评审子代理)` heading — N is tool-counted; do not write your own heading (it would be dropped). Credential values are stripped mechanically before writing (never write a token or designId value). Failures are hard and visible (no silent fallback): if a write is refused or fails, say so in your report — “§× 未写入”.
@@ -0,0 +1 @@
1
+ Search the project's source code for relevant code. Use this to find functions, classes, or code patterns across the codebase. Returns matching code chunks with file paths and line numbers. Prefer doc_search for the intended design (design docs, conventions); code_search for the implementation as written. For what was said in a session (conversation/chat history), use read_history.
@@ -0,0 +1,5 @@
1
+ Start a parallel multi-model consultation (会诊) for a hard problem you are stuck on (repeated failures, no headway). Call it directly when the user asks for 会诊 / consult — an explicit user request applies even if you are not 'stuck'.
2
+
3
+ Several configured models (agent.consultModels — at most 5; an unconfigured pool is an explicit error) analyze the same problem INDEPENDENTLY and in parallel. Non-blocking: returns immediately with a consult id; the consultants keep running in the background across turns. When EVERY model has replied (or failed), the full verdict text is delivered to you automatically — as a system reminder at the next run start, or digested on its own while the session is idle — judge and adopt each opinion yourself with your own tools (opinions are suggestions, not gates). To stop a session early (user changed their mind / wants the tokens back), call consult_stop(id) — a stopped session delivers no digest.
4
+
5
+ The brief should carry the symptom, what you already tried (the failure trail), and entry-point files; do NOT paste raw error logs — consultants pull the main session history themselves via their main_history tool.
@@ -0,0 +1,3 @@
1
+ Cancel a still-running consultation session (会诊) — the user changed their mind, the problem resolved, or you want the tokens back. Aborts every consultant that is still running; a stopped session delivers NO digest (its already-collected partial replies are dropped). Sessions that finished on their own are no longer cancellable — their verdict text is delivered automatically.
2
+
3
+ Returns JSON {abandoned: <pending count>, cancelled: true} — or {error: "unknown consult id"} (already finished/cancelled).
@@ -0,0 +1,7 @@
1
+ Manage your own context window — see how full it is, drop stale tool output, or compact the earlier conversation into a summary at a moment of your own choosing.
2
+
3
+ - action='stats': current usage — total vs the compaction threshold, per-segment shares, and how much is prunable / reclaimable.
4
+ - action='prune': drop the CONTENT of stale tool results (older than the protected tail) and replace it with a short stub — tool pairing stays intact, the session record keeps the full text, and the tool can simply be re-run.
5
+ - action='compact': compact the earlier conversation now, with 'focus' — write what the UPCOMING work needs (1–3 sentences: goal, files, constraints that must survive); the summary is weighted toward that focus and the current task list + goal are attached automatically. It runs at the next safe point (before the next request — never mid-exchange) on the same chain as automatic compaction: same summary chain, same panel, same failure chain (3 consecutive failures → deterministic truncation). The receipt carries this session's record path.
6
+
7
+ Nothing here runs on its own — the automatic threshold compaction stays in place as a fallback; whether to compact is your call. Errors come back as 'Error: ...' and change nothing.
@@ -0,0 +1 @@
1
+ Search the project's documentation (README, design docs, guides, markdown files) for relevant information. Use this to find design decisions, coding conventions, architecture docs, or project rules. Prefer this over code_search when you need to understand the project's intended design rather than existing implementation. Returns matching doc chunks: path, heading, line range, relevance score, content excerpt. For what was said in sessions (conversation/chat history — decisions, rulings), use read_history.
package/tool-docs/edit.md CHANGED
@@ -1,4 +1,4 @@
1
- Edit a file as a patch — targeted by content or by line number. Two targeting forms (mutually exclusive — use one): ① line-based: `line: N` replaces that single line, `startLine: N, endLine: M` replaces the inclusive 1-based line range — no old_string needed when you know the line number; give new_string to replace, or OMIT new_string to delete the line/range; ② content-based: old_string is the current content of the region to change (must match exactly once); new_string is the desired result of that region. old_string matching is tolerant: exact match first, then a unique whitespace-only variant, then fuzzy match (unique window with ≥90% of lines identical after trimming, tab→space indent and quote normalization — ASCII single, curly single/double and backtick quotes all unify to straight double quotes). Lines shared by old/new are kept; lines only in new_string take their position relative to the shared lines (LCS order); lines only in old_string are deleted — a replacement never leaves old lines behind (zero overlap → old lines are replaced by new_string, not kept). A unique single-line old_string paired with a single-line new_string replaces that exact line in place (line count unchanged). To add a new line without removing anything use insert_after. replace_all keeps literal replacement of every occurrence — the diff rules do not apply.
1
+ Edit a file as a patch — targeted by content or by line number. Two targeting forms (mutually exclusive — use one): ① line-based: `line: N` replaces that single line, `startLine: N, endLine: M` replaces the inclusive 1-based line range — no old_string needed when you know the line number; give new_string to replace, or OMIT new_string to delete the line/range; ② content-based: old_string is the current content of the region to change (must match exactly once); new_string is the desired result of that region. old_string matching is tolerant: exact match first, then a unique whitespace-only variant, then fuzzy match (unique window with ≥90% of lines identical after trimming, tab→space indent and quote normalization — ASCII single, curly single/double and backtick quotes all unify to straight double quotes). Lines shared by old/new are kept; lines only in new_string take their position relative to the shared lines (LCS order); lines only in old_string are deleted — a replacement never leaves old lines behind (zero overlap → old lines are replaced by new_string, not kept). A unique single-line old_string paired with a single-line new_string replaces that exact line in place (line count unchanged). To add a new line without removing anything use insert_after. replace_all applies to content-based edits only: literal replacement of every occurrence — the diff rules do not apply.
2
2
 
3
3
  **Routing — pick the right edit tool:**
4
4
  - Delete a line/range by number → omit new_string: edit with `line: N` / `startLine: N, endLine: M`
@@ -9,22 +9,11 @@ Edit a file as a patch — targeted by content or by line number. Two targeting
9
9
  - Rewrite an entire file → write
10
10
  - Rename a symbol project-wide → `lsp` or `grep` first to map every caller
11
11
 
12
- **Batch multiple edits into ONE call via the `edits` array** (preferred over N single edit calls): multiple changes to the SAME file go into one `edits` array (entries are applied serially, each based on the previous one's result); independent changes across MULTIPLE files also go into the same `edits` array — one call, atomic (any failure writes nothing). A batched call is one permission ask, one undo unit, and one turn instead of N. A top-level path may accompany the array — entries without their own path inherit it (entry paths override).
13
-
14
- Parameters:
15
- - path: File path (single form: required; with the edits array: optional — the default for entries without their own path)
16
- - old_string: Current content of the region to change (must match exactly once — tolerant matching: exact → whitespace-only variant → fuzzy ≥90% line-equal). Mutually exclusive with line/startLine/endLine — required unless line targeting is used
17
- - new_string: Desired result of the region — diffed against old_string (shared lines kept; old-only lines deleted — a replacement never leaves old lines behind). Content-based edits: required — an explicit empty string is an error (protects against forgetting it). Line-based edits (line/startLine/endLine): give it to replace the line/range, or OMIT it to delete — an explicit empty string is NOT deletion (error — omit instead)
18
- - line: 1-based line number — replace that single line with new_string, or OMIT new_string to DELETE it (mutually exclusive with old_string and startLine/endLine)
19
- - startLine / endLine: 1-based inclusive line range to replace with new_string (given together; mutually exclusive with old_string) — OMIT new_string to DELETE the range
20
- - replace_all: Replace all occurrences instead of just one (default false; content-based targeting only)
21
- - edits: Array of {path?, old_string?, new_string?, line?, startLine?, endLine?, replace_all?} entries — batch form; mutually exclusive with top-level old_string/new_string/line/startLine/endLine — a top-level path is allowed and applies to entries without their own path
12
+ **Batch multiple changes into ONE call via the `edits` array** (preferred over N single edit calls) — same file or across files; atomic: any failure writes nothing. One permission ask, one undo unit, and one turn instead of N. Per-entry shape and targeting are in the schema.
22
13
 
23
14
  Notes:
24
15
  - Prefer this over write for targeted edits — it's safer and keeps changes targeted
25
16
  - If old_string matches zero times (even fuzzy): error. If it matches multiple times without replace_all: error — add more surrounding context to make it unique
26
- - Content-based edits: new_string empty is an explicit error (protects against forgetting it).
27
- - Line-based edits: OMIT new_string to delete the line/range — deleting by number is an explicit, bounded intent.
28
17
  - Returns `Edited <path>: replaced N occurrence(s)` (delete-mode: `Deleted line N of <path>` / `Deleted lines N-M of <path>`) + git diff + syntax-check note + context block (L..-L..).
29
18
  - Never fabricate the old_string — copy it verbatim from the actual file using read first
30
19
  - use the most recent read of the file as the source of old_string / line numbers / hashes — re-read after the file changed
@@ -0,0 +1 @@
1
+ Enter or exit engineering mode. In engineering mode, follow design-before-code: write a design document, run advisor design review, get user approval, then implement via eng-coder subagents. Returns the mode state — 'Engineering mode activated/exited' (an already-active state is acknowledged).
@@ -3,15 +3,7 @@ Execute JavaScript — either inline `code` or a `scriptFile`. Runs in a real ch
3
3
  **Route to execute instead of bash:**
4
4
  - `node -e "…"` → execute (inline code; top-level await + import() + console all work)
5
5
  - `node <script.mjs>` → execute with scriptFile (runs the file in a child node process)
6
- - `node --test <file>` / `node --check <file>` → execute with scriptFile + nodeArgs
7
-
8
- Parameters:
9
- - code: JavaScript to run inline. Top-level `await` and `import('./x.mjs')` are supported. Pure node ESM — no preloaded helpers; import `node:fs`/`node:path` etc. yourself when needed. File reads/writes go through the dedicated read/ls/glob/grep/write/edit tools. Use this OR scriptFile.
10
- - scriptFile: run a .mjs/.js file with node (self-contained — the file imports what it needs). Path relative to workdir — no directory restriction. Use this OR code.
11
- - nodeArgs: (scriptFile) extra node flags before the script, e.g. ["--test"], ["--check"]. Eval-like flags (--eval/--input-type/--inspect) are rejected.
12
- - workdir: run in this directory (relative to cwd — no directory restriction; default cwd)
13
- - filter: optional — only return output lines matching this regex (case-insensitive)
14
- - timeoutMs: Timeout in milliseconds (default 30000, max 600000 — covers `node --test` suites and package scripts)
6
+ - `node --test <file>` / `node --check <file>` → execute with scriptFile + nodeArgs (timeoutMs up to 600000 — long suites fit)
15
7
 
16
8
  Notes:
17
9
  - `console.log(...)` prints to the result; objects are JSON-stringified where needed.
package/tool-docs/git.md CHANGED
@@ -1,54 +1,28 @@
1
1
  Run a git command. Only works inside a git repository.
2
2
 
3
- **Route to git instead of bash:** `git status`→status, `git log`→log, `git diff`→diff, `git show`→show, `git add`→add, `git rm`→rm, `git commit -m`→commit, `git push <remote> <branch> <tag>`→push, `git tag`→tag, `git branch`→branch, `git checkout`→checkout, `git restore`→restore, `git stash`→stash, `git fetch/pull`→fetch/pull, `git reset`→reset, `git revert`→revert, `git merge`→merge, `git cherry-pick`→cherry-pick, `git ls-remote`→ls-remote, `git clone`→clone, `git init`→init, `git rebase`→rebase, `git remote`→remote, `git clean`→clean, `git switch`→switch, `git apply`→apply, `git worktree`→worktree, `git archive`→archive, `git blame`→blame, `git mv`→mv.
3
+ **Route to git instead of bash** — every sub-command maps to the same-named action: status / log / diff / show / add / rm / commit / push / tag / branch / checkout / restore / stash / fetch / pull / reset / revert / merge / cherry-pick / ls-remote / clone / init / rebase / remote / clean / switch / apply / worktree / archive / blame / mv.
4
4
 
5
- - action='diff': unified diff — what changed since last commit. staged=true for staged-only; ref=<ref> to compare a commit/branch; path=<dir> to scope.
6
- - action='status': working tree state — staged / unstaged / untracked / conflicts, categorized.
7
- - action='log': recent commits. count (default 10), oneline=true compact, path=<file> for one file's history.
8
- - action='show': a commit's details (--stat). ref=<ref> (default HEAD).
9
- - action='add': stage files — path=<file> (granular) or all changes when path omitted.
10
- - action='commit': commit. message required; path=<file> → `git commit --only <paths>` — commits those files' working-tree content only (other staged batches are NOT mixed in — atomic); without path → add -A + full commit. New (untracked) files aren't committable by path alone — `git add` them first (staging extra is safe: --only still commits only the listed files).
11
- - action='rm': untrack a file/dir (git rm --cached, kept on disk). path required.
12
- - action='push'/'fetch'/'pull': sync with remote. remote=<origin>, ref=<branch or tag> (space-separated for multiple), tags=true for --tags.
13
- - action='tag': manage tags. tagAction=list (optional filter) / create (name, optional ref) / delete (name; snapshots first).
14
- - action='branch': manage branches. branchAction=list / create (name, optional ref) / switch (name) / delete (name; snapshots first).
15
- - action='checkout': switch to ref=<branch/commit>, or restore a file path=<file> (discards its working-tree changes; snapshots first).
16
- - action='restore': restore a file from index/HEAD. path required; staged=true restores the staged copy; snapshots first.
17
- - action='stash': manage the stash. stashAction=list / push (message) / pop (snapshots first).
18
- - action='reset': reset to ref (default HEAD). mode=soft/mixed/hard; hard snapshots the tree first (drops working-tree changes).
19
- - action='revert': revert a commit (safe). ref=<commit> (default HEAD).
20
- - action='merge': merge ref=<branch/commit>; conflicts reported for you to resolve.
21
- - action='cherry-pick': cherry-pick ref=<commit>.
22
- - action='ls-remote': light remote-ref check — which refs a remote has (read-only, network). remote=<origin>, ref=<branch/tag> optional, config for proxy.
23
- - action='clone': clone a repo. remote required (URL or local path); path optional (target dir).
24
- - action='init': init a repo in the current (work)dir.
25
- - action='rebase': rebase onto ref. rebaseAction=start (ref required) / abort / continue(操作前自动快照,checkpointAction=rewind 恢复).
26
- - action='remote': manage remotes. remoteAction=list / add / remove / set-url; remoteUrl for add/set-url.
27
- - action='clean': remove untracked files/dirs. dryRun for -n preview(真删除操作前自动快照,checkpointAction=rewind 恢复).
28
- - action='switch': switch branch. name required; create for -c (new branch).
29
- - action='apply': apply a patch. path required (patch file).
30
- - action='worktree': manage worktrees. worktreeAction=list / add (path, ref) / remove (path).
31
- - action='archive': write a tar of ref (default HEAD). path required (output file).
32
- - action='blame': file blame. path required.
33
- - action='mv': rename/move. path (source) + dest required.
34
- - action='checkpoint': git snapshots. checkpointAction=list/create/rewind/cat/versions; checkpointId required for rewind/cat.
35
- - Destructive ops (checkout -- path / restore / reset --hard / stash pop / branch|tag delete / clean / rebase) auto-snapshot first — restore via checkpointAction=rewind.
36
-
37
- Parameters:
38
- - action (required): diff / status / log / show / checkpoint / add / rm / commit / push / tag / branch / checkout / restore / stash / fetch / pull / reset / revert / merge / cherry-pick / ls-remote / clone / init / rebase / remote / clean / switch / apply / worktree / archive / blame / mv
39
- - workdir: run git in this subdirectory (monorepo / multi-repo). Path relative to cwd — no directory restriction. Default: the discovered project repo root(缺省 = 发现的项目仓根;显式 workdir 优先)
40
- - config: (network actions push/fetch/pull/ls-remote/clone) git -c overrides, e.g. ["http.proxy=http://10.2.2.112:3128"] for blocked remotes
41
- - path: (diff/log/add/commit/checkout/restore/rm/apply/archive/blame/mv/worktree) file or directory to scope / stage / restore
42
- - ref: (show/diff/checkout/reset/revert/merge/cherry-pick/tag:create/branch:create/rebase/worktree:add/archive) commit/branch/ref; (push/pull/fetch) the branch or tag (space-separated for multiple)
43
- - name: (branch/tag/switch) the branch or tag name
44
- - remote: (push/fetch/pull/remote/clone) remote name (e.g. origin) or URL; default: current upstream
45
- - tags: (push) also push all tags (--tags)
46
- - staged: (diff) staged changes; (restore) the staged copy
47
- - count: (log) number of commits (default 10)
48
- - oneline: (log) one-line-per-commit
49
- - message: (commit) commit message — required; (stash:push) stash message
50
- - mode: (reset) soft / mixed / hard — hard snapshots the tree first + needs confirmation
51
- - tagAction: (tag) list / create / delete — branchAction: (branch) list / create / delete / switch — stashAction: (stash) push / pop / list
52
- - filter: (read-only actions) keep only output lines matching this regex (case-insensitive)
53
- - checkpointAction: (checkpoint) list / create / rewind / cat / versions — checkpointId: snapshot id (rewind/cat)
54
- - remoteAction: (remote) list / add / remove / set-url — remoteUrl: (remote add/set-url) URL — rebaseAction: (rebase) start / abort / continue — dryRun: (clean) -n preview — create: (switch) -c — dest: (mv) destination — worktreeAction: (worktree) list / add / remove
5
+ - diff: unified diff since last commit (`staged` — staged only; `ref` — compare a commit/branch; `path` — scope).
6
+ - status: working tree state — staged / unstaged / untracked / conflicts.
7
+ - log: recent commits (`count`, `oneline`, `path` — one file's history).
8
+ - show: one commit with --stat (`ref`, default HEAD).
9
+ - add: stage files — `path` (granular) or all changes.
10
+ - rm: untrack a file/dir (`git rm --cached` — kept on disk; `path` required).
11
+ - commit: `message` required. With `path` → `git commit --only <paths>`: commits those files' working-tree content only, atomic — other staged batches are NOT mixed in; without → add -A + full commit. New (untracked) files: `git add` them first (staging extra is safe — `--only` commits only the listed files).
12
+ - push / fetch / pull: sync with remote — `remote`, `ref` (space-separated for multiple); `tags` for --tags.
13
+ - tag / branch: manage via `tagAction` / `branchAction` — list / create (name, optional ref) / delete (snapshots first); branch also switch (name).
14
+ - checkout: switch to `ref`; with `path`, restore a file from the index (discards its working-tree changes — snapshots first).
15
+ - restore: restore a file from index/HEAD (`path` required; `staged` restores the staged copy — snapshots first).
16
+ - stash: `stashAction` push (message) / pop / list (pop snapshots first).
17
+ - reset: `ref` (default HEAD), `mode` soft / mixed / hard — hard drops working-tree changes (snapshots first).
18
+ - revert: revert a commit (safe, `ref` default HEAD); merge: `ref` — conflicts come back for you to resolve; cherry-pick: `ref`.
19
+ - rebase: `rebaseAction` start / abort / continue (snapshots first).
20
+ - ls-remote: light remote-ref check — read-only, network (`remote`, optional `ref`).
21
+ - clone: `remote` required (URL or local path), optional `path` (target dir); init: create a repo in the current workdir.
22
+ - remote: manage remotes — `remoteAction` list / add / remove / set-url (`remoteUrl` for add / set-url).
23
+ - clean: remove untracked files/dirs — `dryRun` previews (-n; the real clean snapshots first).
24
+ - switch: switch branch (`name` required; `create` = -c); apply: apply a patch (`path` required); archive: tar of a `ref` (`path` required, output file); blame: file blame (`path` required); mv: rename/move (`path` + `dest` required); worktree: `worktreeAction` list / add / remove.
25
+ - checkpoint: local snapshots — `checkpointAction` list / create / rewind / cat / versions (`checkpointId` for rewind / cat).
26
+ - Destructive ops (checkout -- path / restore / reset --hard / stash pop / branch|tag delete / clean / rebase) auto-snapshot first; restore a snapshot via `checkpointAction=rewind`.
27
+ - Failures come back as errors — `git <action> failed: <reason>` — nothing is silently swallowed.
28
+ - `filter` narrows any read-only action's output (case-insensitive regex); `config` (git -c overrides, e.g. a proxy) applies to the network actions (push / fetch / pull / ls-remote / clone). Other parameter defaults and applicability live in the schema.
@@ -0,0 +1,6 @@
1
+ Manage a long-running autonomous goal.
2
+ action='set': create or replace the goal — must have a verifiable completion criterion (a machine-checkable proof, not vague effort).
3
+ action='complete': mark achieved — only after the criterion's check has actually passed.
4
+ action='blocked': report an impasse (requires 'reason') — only after 3 genuine attempts.
5
+ action='cancel': abandon the goal.
6
+ Returns a status line — the goal set/updated/completed/blocked/cancelled confirmation, or Error: ... with the reason.
@@ -0,0 +1 @@
1
+ 台账新增条目(写命令,仅主 agent)——入待讨论(六态状态机入口)。kind = requirement(需求池)/ tech_todo(技术待办);trigger = 归批 / 条件 / 认账不排期(可空)。
@@ -0,0 +1 @@
1
+ 台账收口(写命令,仅主 agent)——勾销:待核销 → 已核销;追认核销:待讨论 / 待设计 → 已核销(须已有 evidence,缺则拒);在途 → 已核销 不可跳(仍经 待核销);撤回:任意态 → 已废弃。归档 = 软删除(写 closed_at,行保留)。
@@ -0,0 +1 @@
1
+ 台账计数单源:未决四态(待讨论 / 待设计 / 在途 / 待核销)COUNT(*),只读、全角色可用。
@@ -0,0 +1 @@
1
+ 台账查询(需求池 / 技术待办)——SQLite 行集,只读、全角色可用。未决四态 = 待讨论 / 待设计 / 在途 / 待核销;已核销 / 已废弃 = 归档态(软删除,行保留)。过滤参数缺省 = 全部行。
@@ -0,0 +1 @@
1
+ 台账更新条目(写命令,仅主 agent)——状态迁移按六态允许迁移表:待讨论→待设计 / 待设计→在途 / 在途→待核销 / 待核销→已核销 / 任意态→已废弃;表外迁移被拒。status 缺省 = 仅更新字段。
@@ -0,0 +1 @@
1
+ Read the main agent's conversation history — what has been tried, the exact errors, recent context. Ground your analysis in the actual failure trail instead of guessing. Output is capped (~60k chars — older messages are trimmed with a note).
@@ -0,0 +1,10 @@
1
+ Manage long-term memory in ONE tool — the action parameter picks the operation:
2
+ - search — find knowledge saved in previous sessions; each result row carries [layer] + entry id (the id's prefix = the layer)
3
+ - put — save knowledge for future sessions; type = rule (coding standards) / knowledge (project facts) / decision (architecture decisions) / pattern (debugging/workflow patterns)
4
+ - list — inventory what memory holds; one row per entry: [layer] id [type] title (date); a truncated list notes the full count
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
+ - 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
+ 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.
8
+ 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.
9
+ Save bugs, conventions, and preferences here — they persist across sessions.
10
+ Session message history (what was said in this or past sessions) is NOT in memory — search session messages with read_history.
@@ -0,0 +1,9 @@
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
+
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
+ - kind:'note' — an FYI that needs no answer (a premise you found broken, a conflict you resolved and want visible early).
5
+ - NON-BLOCKING: returns immediately — keep working on the unaffected parts, keep the affected part pending. No fetch, no polling; finish first = report the unanswered part as not done.
6
+ - SYNCHRONOUS SPAWN: if the parent is blocked on your run, nothing can be sent back — `send` reaches only a RUNNING ASYNC child; the message is read when the parent's call returns (it may re-spawn you with an answer). Do not idle-wait.
7
+ - Out of scope: naming / implementation / wording details, anything a read or a command would answer, trade-offs the task book already states — use the stop-and-report discipline, not this channel.
8
+ - Availability: subagents only (depth > 0). At depth 0 you talk to the user through your normal reply or the question tool.
9
+ - Limits: message ≤1,500 chars; the parent's in-flight queue holds ≤20 messages — exceeding either is an explicit error (nothing is silently dropped).
@@ -0,0 +1 @@
1
+ peer_instances — read-only: list other live ThinCoder instances sharing this workspace cwd. Returns [{ pid, end, sessionId, slots }]; never includes self; pure read — writes nothing.
@@ -0,0 +1,5 @@
1
+ Enter or exit plan mode.
2
+ In plan mode you are restricted to READ-ONLY tools: read files, search code, run read-only shell commands.
3
+ Use plan mode before complex multi-step tasks — explore the codebase, design the architecture, present a plan to the user.
4
+ Exit plan mode to present the plan for the user's approval; implement only after they approve.
5
+ For simple single-file edits, skip plan mode and just make the change.
@@ -1,10 +1,14 @@
1
- List running processes, optionally filtered by name. Returns process name / PID / memory.
1
+ List running processes, optionally filtered by name — or kill a process tree / a background bash task. List returns process name / PID / memory; kill returns a one-line confirmation.
2
2
 
3
3
  **Route to process instead of bash:**
4
4
  - `tasklist` (Windows) / `ps aux` (POSIX) → process
5
5
 
6
6
  Parameters:
7
- - name (optional): substring filter (case-insensitive), e.g. "node", "python"
7
+ - action (optional, default 'list'): list — show running processes; kill — terminate a process tree (target: pid) or a background bash task (target: id)
8
+ - name: (list) substring filter (case-insensitive), e.g. "node", "python"
9
+ - pid: (kill) process id — the whole tree is terminated (taskkill /T /F on win32; POSIX group kill)
10
+ - id: (kill) background bash task id — the `bash#N` from the bash async ack; its process tree is terminated, the entry leaves the pool, and no digest will arrive (the log so far stays readable)
8
11
 
9
12
  Notes:
10
- - List-only. To kill a process, use `bash taskkill /PID <pid> /F` (Windows) or `bash kill <pid>` — and confirm with the user first.
13
+ - kill is destructive: pass exactly one target (pid or id — never both), and it goes through the same approval gate as other destructive actions — confirm before killing.
14
+ - Repeating a kill is idempotent (same confirmation, no double kill); an unknown or already-finished bash task id comes back as `Error: ...`.
@@ -13,4 +13,5 @@ Notes:
13
13
  - Ask ONE question per call — never bundle multiple sub-questions into one question string; ask the next one after the answer arrives.
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
+ - 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.
16
17
  - 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.
@@ -0,0 +1,7 @@
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
+
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.
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`).
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——互相不替代。
@@ -0,0 +1 @@
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.
@@ -0,0 +1 @@
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.
@@ -0,0 +1,6 @@
1
+ Adjust ThinCoder runtime configuration — persisted to config.json AND hot-applied to the live agent config.
2
+ Actions: list (all keys + values, flattened) | get <key> | set <key> <value> — dot paths into config.json, any nesting.
3
+ 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
+ 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.
@@ -0,0 +1,5 @@
1
+ Load a project skill from .thincoder/skills/.
2
+ Skills contain reusable instructions, workflows, or reference material.
3
+ Use this when the user references a skill by name, or when a task matches a known skill's description.
4
+ Call with action='list' to see available skills; call with action='load' and name=<skill> to activate one.
5
+ Returns the skill list ('list'), the load confirmation ('load' — instructions arrive in the next message), or Error: ... with the available skills.
@@ -0,0 +1,31 @@
1
+ ONE tool, EIGHT actions — pick by what you need:
2
+
3
+ - action:'spawn' (DEFAULT): run a sub-agent in its own isolated context — its reads, searches and tool calls never reach your history; only the final report comes back. Spawn MULTIPLE subagents in the SAME response for parallel work — they run concurrently.
4
+ - action:'status': NON-BLOCKING progress query — returns immediately, consumes nothing, never fetches. Pass the spawn id for one child (role, state: running|queued|done, model, elapsed, turn, position, plus a touched-files summary — first 5 + a count) or omit it for a pool overview — see what a running child has changed BEFORE cancelling it. Background advisor reviews share this surface (pass the review id — role:'advisor', reviewType/round/elapsedSec, same shape).
5
+ - action:'observe': SEE what a running async subagent is DOING right now (progress vs stuck) — pass the id; returns state, turn, the tool(s) executing right now (omitted when none), and the last N one-line turn summaries, newest first (default 5, via recent). Readonly; running/queued/done all answer — queued returns a placeholder, done gives the activity summary only, NOT the report (it rides the auto channel). Judge stuck vs progressing BEFORE cancelling or steering.
6
+ - 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, 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.
7
+ - 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 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 your bookkeeping (pooled with the other role-domain spawns).
8
+ - 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 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 the same way (pass the review id — no token is issued for a cancelled review).
9
+ - 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 (designId; optional for a single-design session). A consumed slot mechanically rejects further spawns for the same designId — new work (deviation fixes included) needs a fresh design review and token. Idempotent (unknown/already-consumed = a no-op notice). Do NOT call while the chain is still open — fix rounds reuse the same slot.
10
+ - 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. 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).
11
+
12
+ Why delegate? The child's noise never reaches your window — delegation keeps your context lean and the child focused; parallel children save wall-clock time, and coder/eng-coder children self-review (verify + advisor) before their reports arrive.
13
+
14
+ Available roles (exposed per mode; the role is REQUIRED for action:'spawn' — a missing or misspelled role is refused):
15
+ - explore — read-only search & analysis (read/search family); no git context — evidence comes from reads and the task book; its report must list what it searched and what it did NOT find. Say quick / medium / thorough (default medium).
16
+ - plan — read-only planning; NEVER edits; returns a step-by-step plan.
17
+ - 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).
18
+ - 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 advisor(type='design') review (its reply also echoes a designId — pass it: 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).
19
+ - eng-designer — engineering mode only: the SOLE author of the requirements/design documents and of the batch record's design section. Writes no implementation code, does not edit prompts, does not fire reviews, needs NO designToken. Surveys on its own; may only spawn read-only explore children (sync, ≤6 per batch). REQUIRES a batchDoc (same gate as eng-coder).
20
+
21
+ 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).
22
+
23
+ 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 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 while the other keeps starting.
24
+
25
+ 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 (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 immediate spawn (no scheduler involvement).
26
+
27
+ Writing the prompt:
28
+ - The child starts with zero context — brief it like a colleague who just walked in: goal, what you already know, the specifics.
29
+ - Put exact paths and commands in — do not make it search for what you already know.
30
+ - Do not delegate understanding: resolve the paths/line numbers the task hinges on first.
31
+ - Once it runs, leave that scope to it — don't redo its searches in parallel or finish manually midway.
@@ -0,0 +1,7 @@
1
+ Plan and track a task list for complex multi-step work.
2
+ Each call replaces the entire list.
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
+ Statuses: pending | in_progress | done — synonyms (completed/finished/complete, todo/open/waiting, active/running/working, …) are accepted and normalized with a warning.
5
+ IMPORTANT: title is required and must be a non-empty string — items with empty titles are silently dropped.
6
+ For cross-session / project-level tracking, use `/ledger`.
7
+ Returns the updated task list (or the new item's ID on add).
@@ -0,0 +1,6 @@
1
+ Set a timer before you start analyzing code.
2
+ When the timer fires, a system reminder will be injected suggesting you try running code or adding debug logs.
3
+ Use this to enforce a thinking budget: you get N seconds to reason, then the timer reminds you to act.
4
+ Returns the set confirmation — the reminder fires at the deadline.
5
+ Delivery: while a turn is running it lands at the next step boundary; 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); other paths keep the step-boundary behavior.
6
+ A pending timer survives across runs; at most 8 timers may be pending at once, and further timer calls are rejected until some expire.
@@ -0,0 +1 @@
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? } — 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). 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.
@@ -5,9 +5,10 @@ Parameters:
5
5
  - `advisor settled` — an in-flight advisor review session has finished (async advisor-role children settled)
6
6
  - `subagent id:N done` — async subagent N (the id your async spawn ack returned) has settled
7
7
  - `consult done` — every consult_start session has drained
8
+ - `bash id:N done` — background bash task N (the id from the bash async ack, `bash#N`) has finished — settled, or already left the pool (nothing left to wait on)
8
9
  - `file exists:path` — the file at path exists (path relative to cwd)
9
10
  - `port open:N` — something is listening on 127.0.0.1 port N
10
- - The agent-internal conditions (advisor / subagent / consult) apply to ASYNC sessions only — a synchronous call already completed before it returned and has nothing to wait for. An unknown condition is an explicit error (`wait_for: unsupported condition "..."` — the supported forms are listed above), never a silent wait.
11
+ - The agent-internal conditions (advisor / subagent / consult / bash) apply to ASYNC sessions only — a synchronous call already completed before it returned and has nothing to wait for. An unknown condition is an explicit error (`wait_for: unsupported condition "..."` — the supported forms are listed above), never a silent wait.
11
12
  - interval_ms: poll interval (default 1000, floor 100 — polling never busy-spins)
12
13
  - timeout_ms: overall ceiling (default 30000; config.json `agent.waitForTimeoutMs` overrides the default; hard cap 600000 like the execute tool)
13
14
 
package/tools/bash.mjs CHANGED
@@ -41,13 +41,16 @@ function posixSyntaxHint(command) {
41
41
  // ====================================================================
42
42
  // bash — command execution with safety gates
43
43
  // ====================================================================
44
+ // #9:异步 ∥ 后台执行(`async: true`——池/起跑/结算/杀单点 = `agent-tools/bash-async.mjs`;
45
+ // 本档 = 薄接线:参数面 + depth 第二道 + 起跑 ack)。同步径(缺省)**逐字零变**。
44
46
 
45
47
  /**
46
48
  * Build environment for child process.
47
49
  * Passes through all parent env vars, with non-interactive overrides (EDITOR/PAGER/TERM).
48
50
  * Sets PYTHONIOENCODING on Windows to override GBK default for Python scripts.
51
+ * #9:导出面 = 后台径(`agent-tools/bash-async.mjs`)同源复用(env 单源——勿另建副本)。
49
52
  */
50
- function buildBashEnv() {
53
+ export function buildBashEnv() {
51
54
  const isWindows = process.platform === "win32"
52
55
  return {
53
56
  ...process.env,
@@ -238,8 +241,9 @@ export const bashTool = {
238
241
  type: "object",
239
242
  properties: {
240
243
  command: { type: "string", description: "Shell command to execute" },
241
- timeout: { type: "number", description: `Timeout in ms (default ${BASH_TIMEOUT_MS})` },
242
- filter: { type: "string", description: "Optional: only return output lines matching this regex (case-insensitive)" },
244
+ timeout: { type: "number", description: `Timeout in ms (default ${BASH_TIMEOUT_MS} for synchronous runs; background runs have no default — an explicit timeout still applies)` },
245
+ 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." },
246
+ filter: { type: "string", description: "Optional: only return output lines matching this regex (case-insensitive; synchronous runs only)" },
243
247
  },
244
248
  required: ["command"],
245
249
  },
@@ -250,7 +254,28 @@ export const bashTool = {
250
254
  // guard anyway. Instead: snapshot every uncommitted file first, then ALLOW
251
255
  // the command. The snapshot makes the rollback reversible (defense in depth:
252
256
  // the wide matcher also covers variants like `git checkout HEAD -- .`).
257
+ // 前置两件(guard ∥ hint)同步 ∥ 后台两径同保留(#9)。
253
258
  const guard = await gitGuardSnapshot(args.command, ctx.cwd)
259
+ const hint = posixSyntaxHint(args.command)
260
+ if (args.async === true) {
261
+ // depth 第二道(schema 主门 = agent/helpers.mjs excludeSubagentTools 删参——异步面只到
262
+ // 子代理实装亦拒:留一条显式文案,不静默转同步)。
263
+ if ((ctx.depth ?? 0) > 0) {
264
+ return "Error: bash async is depth-0 only — a child agent has no background task pool (run the command synchronously)"
265
+ }
266
+ // 动态 import(W8 契约②:agent-tools 静态链达 node:sqlite——端壳静态闭包须保持零命中)。
267
+ const { launchBgTask } = await import("../agent-tools/bash-async.mjs")
268
+ const launched = await launchBgTask(ctx.agent, ctx, {
269
+ command: args.command,
270
+ timeout: args.timeout ?? null,
271
+ shell: ctx.agent?.config?.shell ?? null,
272
+ })
273
+ if (launched?.error) return `Error: ${launched.error}`
274
+ // filter 对后台径不适用(无同步结果可滤)——显式注记,不静默丢参。
275
+ const filterNote = args.filter ? "\n[note: filter applies to synchronous runs only — for this background task read the log and grep it instead]" : ""
276
+ const body = `${hint ? `${hint}\n` : ""}${launched.ack}${filterNote}`
277
+ return guard ? `${guard.notice}\n\n${body}` : body
278
+ }
254
279
  const result = await runBash(args.command, ctx.cwd, {
255
280
  timeout: args.timeout ?? BASH_TIMEOUT_MS,
256
281
  signal: ctx.signal,
@@ -258,7 +283,6 @@ export const bashTool = {
258
283
  shell: ctx.agent?.config?.shell ?? null,
259
284
  })
260
285
  const filtered = args.filter ? applyLineFilter(result, args.filter) : result
261
- const hint = posixSyntaxHint(args.command)
262
286
  const body = guard ? `${guard.notice}\n\n${filtered}` : filtered
263
287
  return hint ? `${hint}\n${body}` : body
264
288
  },