@te-river/opencode-team-mode 1.5.15 → 1.6.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.
- package/README.md +853 -690
- package/README.zh-CN.md +761 -631
- package/dist/agents.d.ts +5 -3
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +19 -8
- package/dist/agents.js.map +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/capabilities.js +2 -2
- package/dist/capabilities.js.map +1 -1
- package/dist/host/note.d.ts +7 -0
- package/dist/host/note.d.ts.map +1 -0
- package/dist/host/note.js +28 -0
- package/dist/host/note.js.map +1 -0
- package/dist/host/v1.d.ts +14 -0
- package/dist/host/v1.d.ts.map +1 -0
- package/dist/host/v1.js +340 -0
- package/dist/host/v1.js.map +1 -0
- package/dist/host/v2-browser-gate.d.ts +45 -0
- package/dist/host/v2-browser-gate.d.ts.map +1 -0
- package/dist/host/v2-browser-gate.js +319 -0
- package/dist/host/v2-browser-gate.js.map +1 -0
- package/dist/host/v2-capabilities.d.ts +68 -0
- package/dist/host/v2-capabilities.d.ts.map +1 -0
- package/dist/host/v2-capabilities.js +146 -0
- package/dist/host/v2-capabilities.js.map +1 -0
- package/dist/host/v2-client.d.ts +53 -0
- package/dist/host/v2-client.d.ts.map +1 -0
- package/dist/host/v2-client.js +193 -0
- package/dist/host/v2-client.js.map +1 -0
- package/dist/host/v2-events.d.ts +56 -0
- package/dist/host/v2-events.d.ts.map +1 -0
- package/dist/host/v2-events.js +158 -0
- package/dist/host/v2-events.js.map +1 -0
- package/dist/host/v2-guard.d.ts +101 -0
- package/dist/host/v2-guard.d.ts.map +1 -0
- package/dist/host/v2-guard.js +199 -0
- package/dist/host/v2-guard.js.map +1 -0
- package/dist/host/v2-offload.d.ts +148 -0
- package/dist/host/v2-offload.d.ts.map +1 -0
- package/dist/host/v2-offload.js +288 -0
- package/dist/host/v2-offload.js.map +1 -0
- package/dist/host/v2-permissions.d.ts +123 -0
- package/dist/host/v2-permissions.d.ts.map +1 -0
- package/dist/host/v2-permissions.js +190 -0
- package/dist/host/v2-permissions.js.map +1 -0
- package/dist/host/v2-probe.d.ts +85 -0
- package/dist/host/v2-probe.d.ts.map +1 -0
- package/dist/host/v2-probe.js +268 -0
- package/dist/host/v2-probe.js.map +1 -0
- package/dist/host/v2-scope.d.ts +51 -0
- package/dist/host/v2-scope.d.ts.map +1 -0
- package/dist/host/v2-scope.js +58 -0
- package/dist/host/v2-scope.js.map +1 -0
- package/dist/host/v2-session-client.d.ts +74 -0
- package/dist/host/v2-session-client.d.ts.map +1 -0
- package/dist/host/v2-session-client.js +171 -0
- package/dist/host/v2-session-client.js.map +1 -0
- package/dist/host/v2-session.d.ts +85 -0
- package/dist/host/v2-session.d.ts.map +1 -0
- package/dist/host/v2-session.js +171 -0
- package/dist/host/v2-session.js.map +1 -0
- package/dist/host/v2-subagent.d.ts +157 -0
- package/dist/host/v2-subagent.d.ts.map +1 -0
- package/dist/host/v2-subagent.js +286 -0
- package/dist/host/v2-subagent.js.map +1 -0
- package/dist/host/v2-tool.d.ts +67 -0
- package/dist/host/v2-tool.d.ts.map +1 -0
- package/dist/host/v2-tool.js +209 -0
- package/dist/host/v2-tool.js.map +1 -0
- package/dist/host/v2-transcript.d.ts +73 -0
- package/dist/host/v2-transcript.d.ts.map +1 -0
- package/dist/host/v2-transcript.js +151 -0
- package/dist/host/v2-transcript.js.map +1 -0
- package/dist/host/v2-types.d.ts +229 -0
- package/dist/host/v2-types.d.ts.map +1 -0
- package/dist/host/v2-types.js +17 -0
- package/dist/host/v2-types.js.map +1 -0
- package/dist/host/v2.d.ts +42 -0
- package/dist/host/v2.d.ts.map +1 -0
- package/dist/host/v2.js +706 -0
- package/dist/host/v2.js.map +1 -0
- package/dist/host-hooks.d.ts +13 -2
- package/dist/host-hooks.d.ts.map +1 -1
- package/dist/host-hooks.js +18 -5
- package/dist/host-hooks.js.map +1 -1
- package/dist/index.d.ts +23 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -326
- package/dist/index.js.map +1 -1
- package/dist/prompts/lead.d.ts +1 -1
- package/dist/prompts/lead.d.ts.map +1 -1
- package/dist/prompts/lead.js +452 -359
- package/dist/prompts/lead.js.map +1 -1
- package/dist/prompts/shared.d.ts +2 -2
- package/dist/prompts/shared.d.ts.map +1 -1
- package/dist/prompts/shared.js +89 -17
- package/dist/prompts/shared.js.map +1 -1
- package/dist/prompts/specialists.d.ts +2 -2
- package/dist/prompts/specialists.d.ts.map +1 -1
- package/dist/prompts/specialists.js +44 -10
- package/dist/prompts/specialists.js.map +1 -1
- package/dist/task-offload.d.ts +83 -0
- package/dist/task-offload.d.ts.map +1 -0
- package/dist/task-offload.js +174 -0
- package/dist/task-offload.js.map +1 -0
- package/dist/tm/args-schema.d.ts +4 -0
- package/dist/tm/args-schema.d.ts.map +1 -1
- package/dist/tm/args-schema.js +36 -3
- package/dist/tm/args-schema.js.map +1 -1
- package/dist/tm/board.d.ts +113 -0
- package/dist/tm/board.d.ts.map +1 -0
- package/dist/tm/board.js +275 -0
- package/dist/tm/board.js.map +1 -0
- package/dist/tm/browser.d.ts +325 -6
- package/dist/tm/browser.d.ts.map +1 -1
- package/dist/tm/browser.js +1360 -135
- package/dist/tm/browser.js.map +1 -1
- package/dist/tm/config.d.ts +36 -25
- package/dist/tm/config.d.ts.map +1 -1
- package/dist/tm/config.js +29 -7
- package/dist/tm/config.js.map +1 -1
- package/dist/tm/dispatch.d.ts +133 -53
- package/dist/tm/dispatch.d.ts.map +1 -1
- package/dist/tm/dispatch.js +481 -279
- package/dist/tm/dispatch.js.map +1 -1
- package/dist/tm/dupe-guard.d.ts +16 -3
- package/dist/tm/dupe-guard.d.ts.map +1 -1
- package/dist/tm/dupe-guard.js +27 -7
- package/dist/tm/dupe-guard.js.map +1 -1
- package/dist/tm/egress.d.ts +44 -0
- package/dist/tm/egress.d.ts.map +1 -0
- package/dist/tm/egress.js +191 -0
- package/dist/tm/egress.js.map +1 -0
- package/dist/tm/guard.js +1 -1
- package/dist/tm/guard.js.map +1 -1
- package/dist/tm/index.d.ts +67 -2
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +228 -20
- package/dist/tm/index.js.map +1 -1
- package/dist/tm/ledger.d.ts +114 -0
- package/dist/tm/ledger.d.ts.map +1 -0
- package/dist/tm/ledger.js +308 -0
- package/dist/tm/ledger.js.map +1 -0
- package/dist/tm/perm-ask.d.ts +45 -5
- package/dist/tm/perm-ask.d.ts.map +1 -1
- package/dist/tm/perm-ask.js +107 -7
- package/dist/tm/perm-ask.js.map +1 -1
- package/dist/tm/pipelines.d.ts.map +1 -1
- package/dist/tm/pipelines.js +24 -2
- package/dist/tm/pipelines.js.map +1 -1
- package/dist/tm/preview.d.ts +55 -0
- package/dist/tm/preview.d.ts.map +1 -1
- package/dist/tm/preview.js +225 -0
- package/dist/tm/preview.js.map +1 -1
- package/dist/tm/ptc/tool.d.ts.map +1 -1
- package/dist/tm/ptc/tool.js +2 -4
- package/dist/tm/ptc/tool.js.map +1 -1
- package/dist/tm/pty.d.ts.map +1 -1
- package/dist/tm/pty.js +6 -3
- package/dist/tm/pty.js.map +1 -1
- package/dist/tm/search.d.ts +5 -0
- package/dist/tm/search.d.ts.map +1 -1
- package/dist/tm/search.js +40 -8
- package/dist/tm/search.js.map +1 -1
- package/dist/tm/serp-loop.d.ts +45 -0
- package/dist/tm/serp-loop.d.ts.map +1 -0
- package/dist/tm/serp-loop.js +80 -0
- package/dist/tm/serp-loop.js.map +1 -0
- package/dist/tm/stats.d.ts +26 -0
- package/dist/tm/stats.d.ts.map +1 -1
- package/dist/tm/stats.js +194 -4
- package/dist/tm/stats.js.map +1 -1
- package/dist/tm/webfetch.d.ts +56 -0
- package/dist/tm/webfetch.d.ts.map +1 -1
- package/dist/tm/webfetch.js +187 -19
- package/dist/tm/webfetch.js.map +1 -1
- package/dist/tool-coerce.d.ts +24 -0
- package/dist/tool-coerce.d.ts.map +1 -0
- package/dist/tool-coerce.js +63 -0
- package/dist/tool-coerce.js.map +1 -0
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/docs/installation-v2.md +436 -0
- package/docs/installation.md +81 -2
- package/docs/research/agent-data-exchange.md +117 -0
- package/docs/research/browser-pane.md +89 -0
- package/docs/research/host-http-api.md +132 -0
- package/docs/research/host-subagent-injection.md +187 -0
- package/docs/research/plugin-loader-contract.md +261 -0
- package/docs/research/v2-builtin-tools.md +447 -0
- package/docs/v2-port-notes.md +315 -0
- package/index.js +7 -0
- package/package.json +4 -1
- package/scripts/gen-v2-config.mjs +304 -0
- package/scripts/lib/config-surgery.cjs +239 -0
- package/scripts/lib/fake-ctx.mjs +146 -0
package/dist/tm/board.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tm_board_write — the write side of the blackboard (2026-09-23).
|
|
3
|
+
*
|
|
4
|
+
* Why it exists: the board is the one place an oversized deliverable is
|
|
5
|
+
* supposed to go, but reaching it needs a file tool — and three of the six
|
|
6
|
+
* roles carry none. `architect` and `researcher` have no write/edit/bash at
|
|
7
|
+
* all (a deliberate permission-matrix decision), so every "write the design
|
|
8
|
+
* doc to the board" dispatch ended as `BLACKBOARD WRITE FAILED` with the
|
|
9
|
+
* document pasted inline anyway — the reply shape this team exists to enforce
|
|
10
|
+
* (skeleton + path, never a wall of text) was un-followable for exactly the two
|
|
11
|
+
* roles that produce the longest artifacts. Even the documented session folder
|
|
12
|
+
* is out of reach: creating it means running `Get-Date`, which those roles
|
|
13
|
+
* cannot run either.
|
|
14
|
+
*
|
|
15
|
+
* What this is NOT: a general file writer. It places a NEW markdown file
|
|
16
|
+
* inside `<board-root>/<session-key>/<task-slug>/` and nothing else — no
|
|
17
|
+
* overwrite (a revision is a new `-rN` round, per the documented layout), no
|
|
18
|
+
* traversal (each segment is a sanitized slug, then realpath-verified against
|
|
19
|
+
* the root), no workspace or user paths, no `.env` family. The reply returns
|
|
20
|
+
* the path plus the byte count, never the content: bytes riding back through
|
|
21
|
+
* the context window is the very thing the board exists to avoid.
|
|
22
|
+
*/
|
|
23
|
+
import * as fs from "node:fs";
|
|
24
|
+
import * as path from "node:path";
|
|
25
|
+
import { tmError, toToolResult } from "./result.js";
|
|
26
|
+
/** Content cap for one board file (characters). A deliverable past this is not
|
|
27
|
+
* a board file — it is two, or it is the wrong tool. */
|
|
28
|
+
export const BOARD_MAX_CONTENT_CHARS = 200_000;
|
|
29
|
+
/** Files per session folder (across its task dirs): the TTL sweeper is the only
|
|
30
|
+
* reclaim path by design, so an unbounded count is a disk leak. */
|
|
31
|
+
export const BOARD_MAX_FILES_PER_SESSION = 200;
|
|
32
|
+
export const BOARD_MAX_TASKS_PER_SESSION = 40;
|
|
33
|
+
/** `yyyyMMdd-HHmmss`, local — the SAME shape the blackboard note tells the lead
|
|
34
|
+
* to build with `Get-Date -Format yyyyMMdd-HHmmss` / `date +%Y%m%d-%H%M%S`, so
|
|
35
|
+
* a tool-made session folder is indistinguishable from a hand-made one. */
|
|
36
|
+
export function sessionKeyStamp(now = new Date()) {
|
|
37
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
38
|
+
return (`${now.getFullYear()}${p(now.getMonth() + 1)}${p(now.getDate())}` +
|
|
39
|
+
`-${p(now.getHours())}${p(now.getMinutes())}${p(now.getSeconds())}`);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* One path segment out of untrusted model text. Separators and `..` are
|
|
43
|
+
* REWRITTEN rather than rejected (a model that writes `auth/design` means the
|
|
44
|
+
* task `auth-design`), anything that cannot survive a filename is dropped, and
|
|
45
|
+
* CJK is preserved because this project's users write CJK. "" means "nothing
|
|
46
|
+
* usable was given", which the caller turns into an args error.
|
|
47
|
+
*/
|
|
48
|
+
export function sanitizeSlug(raw, max = 60) {
|
|
49
|
+
const s = String(raw ?? "")
|
|
50
|
+
.replace(/[\\/]+/g, "-")
|
|
51
|
+
.replace(/\.\./g, "-")
|
|
52
|
+
.replace(/[<>:"|?*\x00-\x1f]/g, "")
|
|
53
|
+
.replace(/\s+/g, "-")
|
|
54
|
+
.replace(/-{2,}/g, "-")
|
|
55
|
+
.replace(/^[-.]+|[-.]+$/g, "")
|
|
56
|
+
.slice(0, max);
|
|
57
|
+
return s === "." || s === ".." ? "" : s;
|
|
58
|
+
}
|
|
59
|
+
/** `NN` for the next file in a task dir: max existing ordinal + 1, so a hand
|
|
60
|
+
* -written `07-…md` the lead created is counted too. */
|
|
61
|
+
export function nextOrdinal(names) {
|
|
62
|
+
let max = 0;
|
|
63
|
+
for (const n of names) {
|
|
64
|
+
const m = /^(\d{1,4})-/.exec(n);
|
|
65
|
+
if (m)
|
|
66
|
+
max = Math.max(max, Number(m[1]));
|
|
67
|
+
}
|
|
68
|
+
return max + 1;
|
|
69
|
+
}
|
|
70
|
+
/** The round suffix for a revision: "" when the base name is free, else
|
|
71
|
+
* `-r2`, `-r3`… — never a rewrite, because the board's history IS the audit
|
|
72
|
+
* trail the lead reads back. */
|
|
73
|
+
export function roundSuffix(names, base) {
|
|
74
|
+
if (!names.includes(`${base}.md`))
|
|
75
|
+
return "";
|
|
76
|
+
let r = 2;
|
|
77
|
+
while (names.includes(`${base}-r${r}.md`))
|
|
78
|
+
r++;
|
|
79
|
+
return `-r${r}`;
|
|
80
|
+
}
|
|
81
|
+
/** The `NN` that anchors a revision: a family keeps the number its first file
|
|
82
|
+
* got, so `01-architect-design.md` and `01-architect-design-r2.md` sit
|
|
83
|
+
* together in a listing. Advancing the ordinal instead (the first version of
|
|
84
|
+
* this code did) means a revision never gets the `-rN` suffix the documented
|
|
85
|
+
* layout promises, and the round history becomes invisible. */
|
|
86
|
+
export function findFamily(names, role, topic) {
|
|
87
|
+
const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
88
|
+
const re = new RegExp(`^(\\d{1,4})-${esc(role)}-${esc(topic)}(?:-r(\\d+))?\\.md$`);
|
|
89
|
+
let nn = 0;
|
|
90
|
+
let maxRound = 1;
|
|
91
|
+
for (const n of names) {
|
|
92
|
+
const m = re.exec(n);
|
|
93
|
+
if (!m)
|
|
94
|
+
continue;
|
|
95
|
+
if (!nn)
|
|
96
|
+
nn = Number(m[1]);
|
|
97
|
+
maxRound = Math.max(maxRound, Number(m[2] ?? 1));
|
|
98
|
+
}
|
|
99
|
+
if (!nn)
|
|
100
|
+
return null;
|
|
101
|
+
return { base: `${String(nn).padStart(2, "0")}-${role}-${topic}`, round: `-r${maxRound + 1}` };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Plan the write: `<root>/<session>/<task>/<NN>-<role>-<topic><round>.md`.
|
|
105
|
+
* Every segment is sanitized and the resolved session/task pair is checked
|
|
106
|
+
* against the root by REALPATH, because a task dir somebody made earlier could
|
|
107
|
+
* be a symlink pointing at `~/.ssh` — and a writer that only strings paths
|
|
108
|
+
* together would follow it happily.
|
|
109
|
+
*/
|
|
110
|
+
export function planBoardWrite(opts) {
|
|
111
|
+
const session = sanitizeSlug(opts.session, 40);
|
|
112
|
+
const task = sanitizeSlug(opts.task, 60);
|
|
113
|
+
const topic = sanitizeSlug(opts.topic, 60);
|
|
114
|
+
const role = sanitizeSlug(opts.role, 24) || "agent";
|
|
115
|
+
if (!session || !task || !topic) {
|
|
116
|
+
return { error: "session / task / topic 里必须各有至少一个可用字符(会被规整成安全的路径段)" };
|
|
117
|
+
}
|
|
118
|
+
const taskDir = path.join(opts.root, session, task);
|
|
119
|
+
// The session folder is the boundary a runaway task name must not cross.
|
|
120
|
+
let realRoot;
|
|
121
|
+
let realSessionParent;
|
|
122
|
+
try {
|
|
123
|
+
realRoot = fs.realpathSync(opts.root);
|
|
124
|
+
const sessionDir = path.join(realRoot, session);
|
|
125
|
+
if (fs.existsSync(sessionDir)) {
|
|
126
|
+
realSessionParent = fs.realpathSync(sessionDir);
|
|
127
|
+
if (realSessionParent !== path.join(realRoot, session)) {
|
|
128
|
+
return { error: `会话目录 ${session} 是一个符号链接,指向黑板之外——不在写入范围` };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
realRoot = path.resolve(opts.root);
|
|
134
|
+
realSessionParent = "";
|
|
135
|
+
}
|
|
136
|
+
const resolvedTask = path.resolve(taskDir);
|
|
137
|
+
if (resolvedTask !== taskDir || !resolvedTask.startsWith(realRoot + path.sep)) {
|
|
138
|
+
return { error: "解析后的目标路径越出了黑板根目录,拒绝写入" };
|
|
139
|
+
}
|
|
140
|
+
const files = opts.list(taskDir);
|
|
141
|
+
const fam = findFamily(files, role, topic);
|
|
142
|
+
const base = fam ? fam.base : `${String(nextOrdinal(files)).padStart(2, "0")}-${role}-${topic}`;
|
|
143
|
+
const round = fam ? fam.round : roundSuffix(files, base);
|
|
144
|
+
return { dir: taskDir, file: `${base}${round}.md`, rel: path.join(session, task, `${base}${round}.md`), round };
|
|
145
|
+
}
|
|
146
|
+
/** Count what this session folder already holds, so the caps can be enforced
|
|
147
|
+
* before another 400 files arrive. Never throws: an unreadable tree simply
|
|
148
|
+
* counts as nothing. */
|
|
149
|
+
export function sessionUsage(root, session) {
|
|
150
|
+
let files = 0;
|
|
151
|
+
let tasks = 0;
|
|
152
|
+
try {
|
|
153
|
+
for (const entry of fs.readdirSync(path.join(root, session), { withFileTypes: true })) {
|
|
154
|
+
if (!entry.isDirectory())
|
|
155
|
+
continue;
|
|
156
|
+
tasks++;
|
|
157
|
+
try {
|
|
158
|
+
files += fs.readdirSync(path.join(root, session, entry.name)).filter((f) => f.endsWith(".md")).length;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* raced — this task contributes nothing */
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return { files: 0, tasks: 0 };
|
|
167
|
+
}
|
|
168
|
+
return { files, tasks };
|
|
169
|
+
}
|
|
170
|
+
/** Atomic-ish: write a sibling temp file then rename, so a crash mid-write
|
|
171
|
+
* cannot leave a half-written board file that a reader mistakes for the real
|
|
172
|
+
* deliverable. (win32 rename over an existing target throws — which is fine
|
|
173
|
+
* here, because the name was chosen as unused.) */
|
|
174
|
+
export function writeNewFile(file, text) {
|
|
175
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
176
|
+
fs.writeFileSync(tmp, text, "utf8");
|
|
177
|
+
try {
|
|
178
|
+
fs.renameSync(tmp, file);
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
try {
|
|
182
|
+
fs.rmSync(tmp, { force: true });
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
/* nothing to clean */
|
|
186
|
+
}
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
export function buildBoardWriteTool(deps) {
|
|
191
|
+
const tool = "tm_board_write";
|
|
192
|
+
const { pipelines } = deps;
|
|
193
|
+
const traj = (e) => pipelines.store.appendTrajectory({ tool, ...e });
|
|
194
|
+
const maxChars = Math.max(1000, Number(deps.cfg?.boardMaxChars) || BOARD_MAX_CONTENT_CHARS);
|
|
195
|
+
const maxFiles = Math.max(4, Number(deps.cfg?.boardMaxFiles) || BOARD_MAX_FILES_PER_SESSION);
|
|
196
|
+
const root = path.resolve(deps.boardRoot);
|
|
197
|
+
const execute = async (rawArgs, ctx) => {
|
|
198
|
+
const args = rawArgs ?? {};
|
|
199
|
+
const content = String(args.content ?? args.text ?? "");
|
|
200
|
+
if (!content.trim()) {
|
|
201
|
+
return toToolResult(tmError(tool, "args", "缺少 content——黑板文件放的是交付物本身,不是路径"));
|
|
202
|
+
}
|
|
203
|
+
if (content.length > maxChars) {
|
|
204
|
+
return toToolResult(tmError(tool, "args", `content ${content.length} 字符超过上限 ${maxChars}(TM_BOARD_MAX_CHARS)。拆成多个 topic 各写一个文件,别把一份超长文档塞进一次交付——超限的部分不会写盘。`));
|
|
205
|
+
}
|
|
206
|
+
// The role comes from the host's ctx, never from the model: a child that
|
|
207
|
+
// called itself "implementer" would otherwise file its report under another
|
|
208
|
+
// role's name and the lead would trust the wrong author.
|
|
209
|
+
const role = String(ctx?.agent ?? "").trim() || "agent";
|
|
210
|
+
const session = sanitizeSlug(args.session, 40) || (deps.stamp ? deps.stamp() : sessionKeyStamp());
|
|
211
|
+
const planned = planBoardWrite({
|
|
212
|
+
root,
|
|
213
|
+
session,
|
|
214
|
+
task: String(args.task ?? ""),
|
|
215
|
+
role,
|
|
216
|
+
topic: String(args.topic ?? ""),
|
|
217
|
+
list: (dir) => {
|
|
218
|
+
try {
|
|
219
|
+
return fs.readdirSync(dir);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
if ("error" in planned)
|
|
227
|
+
return toToolResult(tmError(tool, "args", planned.error));
|
|
228
|
+
const usage = sessionUsage(root, sanitizeSlug(session, 40));
|
|
229
|
+
if (usage.tasks >= BOARD_MAX_TASKS_PER_SESSION || usage.files >= maxFiles) {
|
|
230
|
+
return toToolResult(tmError(tool, "permission", `会话目录 ${session} 已有 ${usage.files} 个文件 / ${usage.tasks} 个任务目录(上限 ${maxFiles} / ${BOARD_MAX_TASKS_PER_SESSION}),本次不写盘。` +
|
|
231
|
+
`黑板只由 TTL 清扫回收(默认 5 天)——请复用已有 task 目录、把交付合并进一份,或在插件选项 ttlDays 里缩短保留期。`));
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
fs.mkdirSync(planned.dir, { recursive: true });
|
|
235
|
+
// A symlink created INSIDE the task dir between the plan and the write is
|
|
236
|
+
// still a way out, so re-check the parent's realpath before any bytes move.
|
|
237
|
+
const real = fs.realpathSync(planned.dir);
|
|
238
|
+
if (real !== planned.dir && !real.startsWith(root + path.sep)) {
|
|
239
|
+
traj({ step_id: "board", event: "refused", reason: "symlink_escape", target: planned.rel });
|
|
240
|
+
return toToolResult(tmError(tool, "permission", "目标目录经符号链接指向黑板之外,拒绝写入"));
|
|
241
|
+
}
|
|
242
|
+
const file = path.join(real, planned.file);
|
|
243
|
+
if (fs.existsSync(file)) {
|
|
244
|
+
// Chosen as unused a moment ago; another writer in the same round got
|
|
245
|
+
// there first. Say so rather than overwriting their deliverable.
|
|
246
|
+
traj({ step_id: "board", event: "refused", reason: "exists", target: planned.rel });
|
|
247
|
+
return toToolResult(tmError(tool, "args", `${planned.rel} 已经存在(同一轮的并发写入)。换一个 topic 名字,或把 round 交给我自动加后缀。`));
|
|
248
|
+
}
|
|
249
|
+
const header = `<!-- tm_board_write · ${new Date().toISOString()} · role=${role} · session=${session} -->\n`;
|
|
250
|
+
const bytes = Buffer.byteLength(header + content, "utf8");
|
|
251
|
+
writeNewFile(file, header + content);
|
|
252
|
+
traj({ step_id: "board", event: "board_write", session, task: path.basename(planned.dir), file: planned.file, bytes, round: planned.round });
|
|
253
|
+
return toToolResult(`已写入黑板:${file}\n(${bytes} 字节 · ${planned.round ? `修订轮次 ${planned.round}` : "首个版本"} · 作者角色 ${role}。` +
|
|
254
|
+
`正文没有回传——它已经在盘上,把上面这个绝对路径原样写进 CHANGES/HANDOFF,别复述内容。)`);
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
const m = String(e?.message ?? e).slice(0, 200);
|
|
258
|
+
traj({ step_id: "board", event: "error", reason: m });
|
|
259
|
+
return toToolResult(tmError(tool, "execute", `黑板写入失败:${m}`));
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
return {
|
|
263
|
+
description: DESCRIPTION,
|
|
264
|
+
args: deps.args ?? FALLBACK_ARGS,
|
|
265
|
+
execute,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const DESCRIPTION = `Blackboard file writer — the deliverable channel for roles that own no file tools (architect and researcher carry no write/edit/bash, so a board write through the host tools is impossible for them by construction). Writes ONE new markdown file at <board-root>/<session-key>/<task-slug>/NN-<role>-<topic>[-rN].md, where NN and -rN are chosen by this tool (never overwritten: a revision is a new round file, so the board keeps its audit trail). Args: task (slug), topic (slug), content, and optionally session — pass the folder the lead already created so every role in this conversation writes into the SAME folder; omit it and the tool stamps yyyyMMdd-HHmmss for you. The role in the filename comes from the host's ctx, not from what you claim. Scope is enforced, not polite: segments are sanitized, the target's realpath must stay under the board root (a symlinked task dir pointing outside is refused), the name always ends in .md so no .env/rc file can be produced, and content is capped by TM_BOARD_MAX_CHARS with a per-session file cap. The reply is the absolute path plus the byte count and NEVER the content — pasting the deliverable back is the exact thing this channel exists to prevent, so after a successful write the report carries skeleton + path, not the document.`;
|
|
269
|
+
const FALLBACK_ARGS = {
|
|
270
|
+
task: { descriptor: "task: task-slug folder (the one the dispatch named)" },
|
|
271
|
+
topic: { descriptor: "topic: file topic, becomes the name after NN-<role>-" },
|
|
272
|
+
content: { descriptor: "content: the deliverable text itself" },
|
|
273
|
+
session: { descriptor: "session: existing session-key folder from the lead's dispatch (omit to stamp a new one)" },
|
|
274
|
+
};
|
|
275
|
+
//# sourceMappingURL=board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board.js","sourceRoot":"","sources":["../../src/tm/board.ts"],"names":[],"mappings":"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"}
|