@thincoder/core 0.10.13 → 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 (164) hide show
  1. package/CHANGELOG.md +29 -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 +69 -48
  14. package/agent/run-start.mjs +8 -8
  15. package/agent/setup.mjs +3 -11
  16. package/agent/suspension.mjs +1 -1
  17. package/agent/turn-loop.mjs +32 -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 -367
  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 +275 -80
  32. package/agent-tools/batch.mjs +243 -50
  33. package/agent-tools/context.mjs +6 -3
  34. package/agent-tools/design-slots.mjs +24 -24
  35. package/agent-tools/design-token.mjs +96 -15
  36. package/agent-tools/doc-check.mjs +18 -2
  37. package/agent-tools/eng.mjs +1 -1
  38. package/agent-tools/escalate-async.mjs +3 -3
  39. package/agent-tools/manifest.mjs +8 -5
  40. package/agent-tools/read-history.mjs +5 -5
  41. package/agent-tools/review-facts.mjs +31 -13
  42. package/agent-tools/spawn-gates.mjs +10 -14
  43. package/agent-tools/ssh-session.mjs +120 -111
  44. package/agent-tools/ssh-transfer.mjs +210 -0
  45. package/agent-tools/ssh-transport.mjs +277 -46
  46. package/agent-tools/subagent-actions-query.mjs +1 -1
  47. package/agent-tools/subagent-actions.mjs +1 -1
  48. package/agent-tools/subagent-async.mjs +3 -2
  49. package/agent-tools/subagent-scheduler.mjs +43 -9
  50. package/agent-tools/subagent-spawn.mjs +68 -9
  51. package/agent-tools/subagent.mjs +16 -14
  52. package/client-identity.mjs +22 -6
  53. package/config-presets.mjs +5 -3
  54. package/context.mjs +34 -3
  55. package/declaration.mjs +2 -2
  56. package/doc-check/anchors.mjs +128 -28
  57. package/doc-check/index.mjs +68 -15
  58. package/doc-check/line-refs.mjs +112 -0
  59. package/doc-check/paragraph.mjs +18 -5
  60. package/explore-distill.mjs +1 -1
  61. package/i18n.mjs +1 -1
  62. package/index-discover.mjs +4 -1
  63. package/ledger-close-proof.mjs +19 -37
  64. package/ledger-cmd.mjs +71 -195
  65. package/ledger-db.mjs +29 -28
  66. package/ledger-migrate.mjs +4 -4
  67. package/ledger-read.mjs +10 -8
  68. package/ledger-surface.mjs +1 -1
  69. package/ledger-tools.mjs +6 -6
  70. package/ledger-variant-notice.mjs +1 -1
  71. package/ledger-write-ops.mjs +373 -0
  72. package/ledger.mjs +2 -2
  73. package/manifest-discovery.mjs +2 -2
  74. package/manifest-schema.mjs +4 -0
  75. package/memory/memory-tool.mjs +5 -2
  76. package/memory/schema.mjs +5 -26
  77. package/package.json +1 -1
  78. package/path-resolve.mjs +217 -0
  79. package/permission.mjs +4 -0
  80. package/prompt-overlays.mjs +5 -0
  81. package/prompts/advisor-design.md +9 -6
  82. package/prompts/advisor-round1.md +4 -3
  83. package/prompts/advisor-round2.md +6 -5
  84. package/prompts/advisor-round3.md +6 -5
  85. package/prompts/common.md +23 -10
  86. package/prompts/consult-base.md +2 -1
  87. package/prompts/discipline-engineering.md +29 -48
  88. package/prompts/discipline-normal.md +10 -5
  89. package/prompts/persona-eng-coder.md +8 -0
  90. package/prompts/persona-eng-designer.md +22 -12
  91. package/prompts/persona-engineering.md +81 -68
  92. package/prompts/persona-plan.md +2 -1
  93. package/prompts/persona-tester.md +55 -0
  94. package/provider/core.mjs +2 -2
  95. package/provider/google.mjs +15 -5
  96. package/provider/rate.mjs +11 -3
  97. package/provider/sse.mjs +15 -4
  98. package/session-identity.mjs +21 -0
  99. package/session-lifecycle.mjs +9 -4
  100. package/session-slots.mjs +9 -14
  101. package/session.mjs +5 -0
  102. package/skip-dirs.mjs +48 -0
  103. package/team-ledger.mjs +4 -4
  104. package/text-budget.mjs +4 -0
  105. package/token-window.mjs +90 -14
  106. package/tool-docs/advisor.md +2 -2
  107. package/tool-docs/apply_patch.md +2 -0
  108. package/tool-docs/bash.md +4 -0
  109. package/tool-docs/batch.md +85 -1
  110. package/tool-docs/browser.md +3 -1
  111. package/tool-docs/code_search.md +3 -1
  112. package/tool-docs/consult_start.md +6 -2
  113. package/tool-docs/consult_stop.md +3 -1
  114. package/tool-docs/delete.md +3 -0
  115. package/tool-docs/doc_check.md +43 -8
  116. package/tool-docs/doc_search.md +5 -1
  117. package/tool-docs/edit.md +22 -1
  118. package/tool-docs/execute.md +7 -1
  119. package/tool-docs/fetch.md +3 -1
  120. package/tool-docs/file_ops.md +3 -1
  121. package/tool-docs/git.md +9 -1
  122. package/tool-docs/goal.md +2 -0
  123. package/tool-docs/grep.md +1 -1
  124. package/tool-docs/hashline_edit.md +2 -0
  125. package/tool-docs/insert_after.md +3 -1
  126. package/tool-docs/ledger.md +5 -5
  127. package/tool-docs/lint.md +1 -0
  128. package/tool-docs/manifest-read.md +2 -1
  129. package/tool-docs/manifest.md +9 -2
  130. package/tool-docs/memory.md +11 -1
  131. package/tool-docs/notify_parent.md +1 -1
  132. package/tool-docs/plan.md +2 -0
  133. package/tool-docs/question.md +1 -1
  134. package/tool-docs/read_history.md +15 -3
  135. package/tool-docs/read_image.md +3 -1
  136. package/tool-docs/recent_changes.md +3 -1
  137. package/tool-docs/repo_outline.md +3 -1
  138. package/tool-docs/settings.md +10 -2
  139. package/tool-docs/skill.md +2 -0
  140. package/tool-docs/ssh.md +30 -17
  141. package/tool-docs/subagent.md +50 -13
  142. package/tool-docs/task.md +2 -0
  143. package/tool-docs/team_ledger.md +1 -1
  144. package/tool-docs/timer.md +7 -0
  145. package/tool-docs/verify.md +13 -1
  146. package/tool-docs/websearch.md +3 -1
  147. package/tool-docs/write.md +2 -0
  148. package/tools/bash.mjs +12 -2
  149. package/tools/edit-batch.mjs +40 -33
  150. package/tools/edit-diff.mjs +69 -1
  151. package/tools/execute.mjs +10 -4
  152. package/tools/file.mjs +17 -27
  153. package/tools/git.mjs +27 -1
  154. package/tools/ops.mjs +2 -1
  155. package/tools/patch.mjs +12 -3
  156. package/tools/process-doc-mark.mjs +139 -0
  157. package/tools/search.mjs +15 -6
  158. package/tools/shared.mjs +24 -1
  159. package/tools/ssh.mjs +48 -7
  160. package/tools/tree.mjs +4 -1
  161. package/tools/write-path.mjs +64 -3
  162. package/traces/trace-store.mjs +4 -3
  163. package/agent/light-round.mjs +0 -63
  164. package/agent/unbooked-pen.mjs +0 -62
@@ -2,12 +2,20 @@ Run a built-in documentation-discipline check on a project and report its findin
2
2
  Read-only. In the default `report` mode it is non-gating: it reports, it never blocks, never sets an exit code, and its output is never a reason to refuse a task or a user instruction.
3
3
 
4
4
  What it checks — exactly two criteria, both built into the engine:
5
- - Anchors — every documentation pointer (a `*.md` token, optionally carrying directory segments, optionally followed by a section
5
+ - Anchors — a documentation pointer (a `*.md` token, optionally carrying directory segments, optionally followed by a section
6
6
  indicator `§N` / `§N.M` / `§N.M.K`) must resolve: the file must exist on disk (`档缺` when it does not), and when a section
7
7
  indicator is given the target file must carry a heading numbered with it (`节缺` when it does not). Line-number coordinates
8
8
 
9
9
  (`<doc>:12`) are not section references and are not judged as such. Files inside fenced code blocks and executable lines
10
10
  (command / pattern code spans) are skipped whole.
11
+ - **The reach is what survives extraction, not every `.md` token.** Three name families are never extracted, so they are never
12
+ judged: **conventional file names** used to say which files get read (`AGENTS.md`, `SKILL.md`, `project_rules.md`, `todo.md`
13
+ and the rest of that closed set),
14
+
15
+ **placeholder stems** (single letters plus the usual sample words — `x.md`, `file.md`, `foo.md`, `example.md`), and — on the
16
+ prompt face only — the seven operand names the `Operand names` block below lists.
17
+
18
+ A `.md` token outside those families is judged even when misspelled: a wrong name reports `档缺`, never a pass.
11
19
 
12
20
  ~~~text
13
21
  **Operand names.** Seven names count as operands rather than documents: the model writes them, or reads a file by that name. On
@@ -21,15 +29,41 @@ What it checks — exactly two criteria, both built into the engine:
21
29
  ```
22
30
  ~~~
23
31
 
24
- - Paragraph length — on a document face, adjacent non-blank body lines merge into one paragraph whose total character
32
+ - Citation check — the same criterion, one more hit class `引缺` (a line that claims its own basis).
33
+
34
+ A claim line writes `依据 <document path>「<verbatim quotation>」`, and the quoted text must appear as a contiguous substring
35
+ of the file that path resolves to; when it does not, the hit is `引缺` and the report names the path plus the first 40 characters.
36
+
37
+ The path is judged for existence first: a path that does not resolve reports `档缺`, never `引缺` — the fix differs
38
+ (check the path ∥ check the words). Both classes count into the one `锚` total: no third criterion, no new verdict word.
39
+
40
+ Between the path token and `「` only the optional separator (`:` ∥ `:` ∥ `=`) and an optional backtick may sit. Anything else
41
+ (a space, a prose word, a punctuation mark) means the line is not a basis marker and nothing is judged; an empty `「」` is not a marker either.
42
+
43
+ A path whose name falls in the exempt families above is not a marker path either — the same exemption decides both faces.
44
+
45
+ Existence only: no whitespace folding, no case or width folding. A verbatim quotation taken from the wrong place still passes —
46
+ whether it is the *right* basis (a contract rather than a comment) belongs to review, and this tool does not claim to judge it.
47
+
48
+
49
+ - Paragraph length — on every non-prompt face, adjacent non-blank body lines merge into one paragraph whose total character
25
50
  count (CJK counts as 1) is judged against the built-in threshold; blank lines, table rows, headings, list items,
26
51
  quote-block lines and fenced code blocks do not count into a paragraph and break it, and lines inside an exempt zone
27
52
 
28
- are excluded. Breaking a paragraph into more lines changes nothing — only splitting it into more paragraphs or
29
- writing it shorter passes.
53
+ are excluded. No face is exempt: a tool-description file (`thincoder-core/tool-docs/**`, this file included) is judged on
54
+ this criterion too — a long paragraph hides its later points from every reader, the model included.
55
+
56
+ Breaking a paragraph into more lines changes nothing, and clearing the length check is not the same as fixing it: splitting a
57
+ paragraph into more paragraphs, or writing it shorter, clears the count while the reader still faces the same packed paragraph.
58
+
59
+ What fixes it is fewer and shorter sentences, a list of named items where the paragraph holds parallel assertions, or a table
60
+ where it holds enumerated readings.
30
61
  - Line length — a prompt-face file (`thincoder-core/prompts/**`) is judged line by line: the model reads raw text, so
31
62
  one line is one block, and any single line over the threshold counts with no structural exemption.
32
63
 
64
+ `report` mode also prints one extra block: an inventory of the line-number coordinates found in the documents you pass
65
+ (`<doc>:12` shape). That block is a reading, not a criterion — `gate` never produces it, and it cannot change a verdict or a hit count.
66
+
33
67
  It cannot — in `report` mode — write anything, gate anything, or turn a finding into a refusal.
34
68
 
35
69
  Arguments — `target` (optional): the project root to check; defaults to the session anchor, relative paths resolve against it.
@@ -46,10 +80,11 @@ is judged; in `gate` mode such paths are listed as skipped instead. A pointer re
46
80
 
47
81
  against the pointing document's own directory — bare names are not resolved across other directories.
48
82
 
49
- Delivery gate — `mode: "gate"`, for the end of a design or development round. Every listed doc is judged **whole**: a
50
- pre-existing dangling pointer or overlong paragraph / line anywhere in it counts, not only this round's edited lines. The first line is the
83
+ Delivery gate — `mode: "gate"`, for the end of a design or development round. Every listed doc is judged **whole**:
84
+ a pre-existing dangling pointer or overlong paragraph / line anywhere in it counts, not only this round's edited lines.
85
+
86
+ The first line is the machine-readable verdict — `DOC-CHECK GATE: PASS` / `DOC-CHECK GATE: REFUSED(命中 K 条)` / `DOC-CHECK GATE: ERROR(reason)` —
51
87
 
52
- machine-readable verdict — `DOC-CHECK GATE: PASS` / `DOC-CHECK GATE: REFUSED(命中 K 条)` / `DOC-CHECK GATE: ERROR(reason)` —
53
88
  and consumers judge by that prefix; the hits are fixed in the same round and are never booked to the ledger. The gate refuses
54
89
 
55
90
  **one delivery**, not a user instruction: an explicit user go-ahead is followed, with the hits written into the delivery.
@@ -64,7 +99,7 @@ a reader: use `doc_search` / `read` to read documents and `grep` to search them;
64
99
  Side effects and permissions — none. The tool is read-only: no writes, no approval prompt, safe to run in parallel with other calls.
65
100
 
66
101
  Parameters and scope — both criteria run on built-in constants (`DOC_CHECK_BUILTINS`: threshold 300 characters, no exempt zones,
67
- no exemptions), and the judged set is the document list the caller passes — the judged set and the resolution set are the same
102
+ no registration-based exemption list), and the judged set is the document list the caller passes — the judged set and the resolution set are the same
68
103
 
69
104
  documents, so there is no scan-dir / domain / root / exclude surface and no whole-repository scan. Changing a criterion or a
70
105
  threshold is a code change and goes through review; no project declaration changes these readings.
@@ -1 +1,5 @@
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.
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.
2
+
3
+ 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.
4
+
5
+ For what was said in sessions (conversation/chat history — decisions, rulings), use read_history.
package/tool-docs/edit.md CHANGED
@@ -1,4 +1,20 @@
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.
1
+ Edit a file as a patch — targeted by content or by line number.
2
+
3
+ Two targeting forms (mutually exclusive — use one):
4
+
5
+ ① 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;
6
+
7
+ ② 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.
8
+
9
+ 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,
10
+
11
+ tab→space indent and quote normalization — ASCII single, curly single/double and backtick quotes all unify to straight double quotes).
12
+
13
+ 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).
14
+
15
+ 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.
16
+
17
+ replace_all applies to content-based edits only: literal replacement of every occurrence — the diff rules do not apply.
2
18
 
3
19
  **Routing — pick the right edit tool:**
4
20
  - Delete a line/range by number → omit new_string: edit with `line: N` / `startLine: N, endLine: M`
@@ -11,9 +27,14 @@ Edit a file as a patch — targeted by content or by line number. Two targeting
11
27
 
12
28
  **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.
13
29
 
30
+ Line-number entries in one `edits` array apply first, in descending `startLine` order, so each is anchored on the numbers you read; their ranges must not overlap (overlap ⇒ the whole batch is refused, nothing written). Content entries then apply in array order. The receipt stays in call order.
31
+
14
32
  Notes:
15
33
  - Prefer this over write for targeted edits — it's safer and keeps changes targeted
16
34
  - 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
17
35
  - 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..).
18
36
  - Never fabricate the old_string — copy it verbatim from the actual file using read first
37
+ - **Line-number anchoring**: `line` / `startLine`+`endLine` are judged against the last write to that file: inside or below that write's affected range, or when the file was written after it without updating that anchor, the call is refused — naming the path, the drift (`L<startLine>`, `±shift`) and two ways on (re-read, or address the region without line numbers).
19
38
  - use the most recent read of the file as the source of old_string / line numbers / hashes — re-read after the file changed
39
+
40
+ **`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.
@@ -1,4 +1,6 @@
1
- Execute JavaScript — either inline `code` or a `scriptFile`. Runs in a real child `node` process — a pure node ESM environment: top-level `await` and dynamic `import()` are available, no globals are injected. File reads/writes/searches belong to the dedicated read/ls/glob/grep/write/edit tools — not to execute. If a script genuinely needs fs/path, `import` the `node:` module inside the code (one explicit import line).
1
+ Execute JavaScript — either inline `code` or a `scriptFile`. Runs in a real child `node` process — a pure node ESM environment: top-level `await` and dynamic `import()` are available, no globals are injected.
2
+
3
+ File reads/writes/searches belong to the dedicated read/ls/glob/grep/write/edit tools — not to execute. If a script genuinely needs fs/path, `import` the `node:` module inside the code (one explicit import line).
2
4
 
3
5
  **Route to execute instead of bash:**
4
6
  - `node -e "…"` → execute (inline code; top-level await + import() + console all work)
@@ -11,3 +13,7 @@ Notes:
11
13
  - Output is capped at ~50KB; when a script overruns it, an explicit `[output truncated]` marker is appended — print large results in chunks, or have the script write them to a file (node:fs) and read that file back with the `read` tool.
12
14
  - Use `write`/`edit`/`apply_patch` for source edits. Still use `bash` for package-manager/CLI subprocesses (`npm test`/`npm publish`/`vsce`), servers, and interactive/TTY programs — execute covers in-process JS and `node <script>`/`node --test`/`node --check`, not arbitrary CLI or long-running programs.
13
15
  - Irreversibility: it runs with full filesystem access and no automatic undo — script side effects are permanent; checkpoint (git) before risky bulk operations.
16
+
17
+ **`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, and read-only scripts are judged the same way (no command-line classification).
18
+
19
+ **`project`** — the project this call belongs to (absolute path of the project root). Read only when `workdir` is absent — `workdir` wins when both are given. Pure declaration: it does not change the execution directory (`workdir` does).
@@ -1,4 +1,6 @@
1
- Fetch a URL and return its content. With a DeepSeek provider configured the URL is fetched through DeepSeek's servers and returned as Markdown ([deepseek] title + content); otherwise it is fetched locally and HTML is stripped to readable text. Private/metadata URLs are never sent. Use after websearch to read full documents.
1
+ Fetch a URL and return its content. With a DeepSeek provider configured the URL is fetched through DeepSeek's servers and returned as Markdown ([deepseek] title + content); otherwise it is fetched locally and HTML is stripped to readable text.
2
+
3
+ Private/metadata URLs are never sent. Use after websearch to read full documents.
2
4
 
3
5
  Parameters:
4
6
  - url (required): http/https URL
@@ -14,4 +14,6 @@ Notes:
14
14
  - Paths resolve relative to cwd — no directory restriction (same boundary as bash; the approval gate is the guard).
15
15
  - `dest` is overwritten if it already exists. `copy` is recursive for directories.
16
16
  - To create a directory, use `write` (creates parent dirs) or `bash mkdir`.
17
- - Returns `Moved|Copied|Renamed <source> -> <dest>` or `Error: ...` (same-path and missing-path errors).
17
+ - Returns `Moved|Copied|Renamed <source> -> <dest>` or `Error: ...` (same-path and missing-path errors).
18
+
19
+ **`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/tool-docs/git.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Run a git command. Only works inside a git repository.
2
2
 
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.
3
+ **Route to git instead of bash** — every sub-command maps to the same-named action:
4
+
5
+ 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
6
 
5
7
  - diff: unified diff since last commit (`staged` — staged only; `ref` — compare a commit/branch; `path` — scope).
6
8
  - status: working tree state — staged / unstaged / untracked / conflicts.
@@ -26,3 +28,9 @@ Run a git command. Only works inside a git repository.
26
28
  - Destructive ops (checkout -- path / restore / reset --hard / stash pop / branch|tag delete / clean / rebase) auto-snapshot first; restore a snapshot via `checkpointAction=rewind`.
27
29
  - Failures come back as errors — `git <action> failed: <reason>` — nothing is silently swallowed.
28
30
  - `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.
31
+
32
+ **`ledger`** — the in-flight ledger row this call serves: `"#N"` or `"N"`. In engineering mode the parent agent must pass it for a write action; omitted = refused.
33
+
34
+ **`project`** — the project this call belongs to (absolute path of the project root). Read only when neither `path` nor `workdir` is given — those win when present. Pure declaration: it does not change where git runs (`workdir` does).
35
+
36
+ Read-only actions do not need it: `diff` / `status` / `log` / `show` / `ls-remote` / `blame`, and each `*Action: "list"` (`checkpoint` `list` / `cat` included).
package/tool-docs/goal.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Manage a long-running autonomous goal.
2
2
  action='set': create or replace the goal — must have a verifiable completion criterion (a machine-checkable proof, not vague effort).
3
+
3
4
  action='complete': mark achieved — only after the criterion's check has actually passed.
4
5
  action='blocked': report an impasse (requires 'reason') — only after 3 genuine attempts.
5
6
  action='cancel': abandon the goal.
7
+
6
8
  Returns a status line — the goal set/updated/completed/blocked/cancelled confirmation, or Error: ... with the reason.
package/tool-docs/grep.md CHANGED
@@ -1,4 +1,4 @@
1
- Search file contents with a regex. Returns matching lines as path:line: content.
1
+ Search file contents with a regex. Returns matching lines, each preceded by its file path and line number.
2
2
 
3
3
  **Route to grep instead of bash:** `findstr /c:"pat" file` / `grep -rn pat .` → grep. Searching file contents is a read — never shell out for it.
4
4
 
@@ -12,3 +12,5 @@ Notes:
12
12
  - Prefer this over edit when: 1) the file may have mixed whitespace/encoding, 2) you want to edit a block of lines with a single call
13
13
  - Replacement text replaces the lines identified by the hashes — content not present in new_content is deleted. For a new line after a known line, use insert_after. For a single simple string swap, use edit.
14
14
  - use the most recent read of the file as the source of old_string / line numbers / hashes — re-read after the file changed
15
+
16
+ **`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.
@@ -11,5 +11,7 @@ Notes:
11
11
  - Use this instead of edit when you're adding a new line — a checklist item, a doc heading, a line of prose, a function, an import, or a block — no need to fabricate surrounding context for exact matching.
12
12
  - The inserted content becomes its own line; it's equivalent to `lines.splice(targetLine, 0, content)`.
13
13
  - Returns a diff of the change.
14
- - **Read-before-insert guard**: if the file was modified by any write tool (write/edit/insert_after/hashline_edit/apply_patch/delete) since your last `read`, this tool REFUSES with an error — line numbers may be stale. Read the file again, then retry. This prevents after_line from silently landing at a drifted position.
14
+ - **Read-before-insert guard**: `after_line` is judged against the last write to that file — a line at or above that write's write point is allowed; inside or below it, or when the file was written after it without updating that anchor, the call is refused with the path, the drift and two ways on (re-read, or address the region without line numbers).
15
15
  - use the most recent read of the file as the source of old_string / line numbers / hashes — re-read after the file changed
16
+
17
+ **`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.
@@ -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.