@te-river/opencode-team-mode 1.6.0 → 1.6.2

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 (150) hide show
  1. package/README.md +80 -15
  2. package/README.zh-CN.md +67 -18
  3. package/dist/host/note.d.ts +7 -0
  4. package/dist/host/note.d.ts.map +1 -0
  5. package/dist/host/note.js +31 -0
  6. package/dist/host/note.js.map +1 -0
  7. package/dist/host/v1.d.ts +14 -0
  8. package/dist/host/v1.d.ts.map +1 -0
  9. package/dist/host/v1.js +340 -0
  10. package/dist/host/v1.js.map +1 -0
  11. package/dist/host/v2-browser-gate.d.ts +45 -0
  12. package/dist/host/v2-browser-gate.d.ts.map +1 -0
  13. package/dist/host/v2-browser-gate.js +319 -0
  14. package/dist/host/v2-browser-gate.js.map +1 -0
  15. package/dist/host/v2-capabilities.d.ts +78 -0
  16. package/dist/host/v2-capabilities.d.ts.map +1 -0
  17. package/dist/host/v2-capabilities.js +173 -0
  18. package/dist/host/v2-capabilities.js.map +1 -0
  19. package/dist/host/v2-client.d.ts +53 -0
  20. package/dist/host/v2-client.d.ts.map +1 -0
  21. package/dist/host/v2-client.js +193 -0
  22. package/dist/host/v2-client.js.map +1 -0
  23. package/dist/host/v2-events.d.ts +56 -0
  24. package/dist/host/v2-events.d.ts.map +1 -0
  25. package/dist/host/v2-events.js +158 -0
  26. package/dist/host/v2-events.js.map +1 -0
  27. package/dist/host/v2-guard.d.ts +101 -0
  28. package/dist/host/v2-guard.d.ts.map +1 -0
  29. package/dist/host/v2-guard.js +199 -0
  30. package/dist/host/v2-guard.js.map +1 -0
  31. package/dist/host/v2-offload.d.ts +148 -0
  32. package/dist/host/v2-offload.d.ts.map +1 -0
  33. package/dist/host/v2-offload.js +288 -0
  34. package/dist/host/v2-offload.js.map +1 -0
  35. package/dist/host/v2-permissions.d.ts +123 -0
  36. package/dist/host/v2-permissions.d.ts.map +1 -0
  37. package/dist/host/v2-permissions.js +190 -0
  38. package/dist/host/v2-permissions.js.map +1 -0
  39. package/dist/host/v2-probe.d.ts +85 -0
  40. package/dist/host/v2-probe.d.ts.map +1 -0
  41. package/dist/host/v2-probe.js +268 -0
  42. package/dist/host/v2-probe.js.map +1 -0
  43. package/dist/host/v2-scope.d.ts +51 -0
  44. package/dist/host/v2-scope.d.ts.map +1 -0
  45. package/dist/host/v2-scope.js +58 -0
  46. package/dist/host/v2-scope.js.map +1 -0
  47. package/dist/host/v2-session-client.d.ts +105 -0
  48. package/dist/host/v2-session-client.d.ts.map +1 -0
  49. package/dist/host/v2-session-client.js +390 -0
  50. package/dist/host/v2-session-client.js.map +1 -0
  51. package/dist/host/v2-session.d.ts +85 -0
  52. package/dist/host/v2-session.d.ts.map +1 -0
  53. package/dist/host/v2-session.js +171 -0
  54. package/dist/host/v2-session.js.map +1 -0
  55. package/dist/host/v2-subagent.d.ts +157 -0
  56. package/dist/host/v2-subagent.d.ts.map +1 -0
  57. package/dist/host/v2-subagent.js +286 -0
  58. package/dist/host/v2-subagent.js.map +1 -0
  59. package/dist/host/v2-tool.d.ts +67 -0
  60. package/dist/host/v2-tool.d.ts.map +1 -0
  61. package/dist/host/v2-tool.js +209 -0
  62. package/dist/host/v2-tool.js.map +1 -0
  63. package/dist/host/v2-transcript.d.ts +73 -0
  64. package/dist/host/v2-transcript.d.ts.map +1 -0
  65. package/dist/host/v2-transcript.js +151 -0
  66. package/dist/host/v2-transcript.js.map +1 -0
  67. package/dist/host/v2-types.d.ts +229 -0
  68. package/dist/host/v2-types.d.ts.map +1 -0
  69. package/dist/host/v2-types.js +17 -0
  70. package/dist/host/v2-types.js.map +1 -0
  71. package/dist/host/v2.d.ts +42 -0
  72. package/dist/host/v2.d.ts.map +1 -0
  73. package/dist/host/v2.js +853 -0
  74. package/dist/host/v2.js.map +1 -0
  75. package/dist/index.d.ts +23 -17
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +29 -366
  78. package/dist/index.js.map +1 -1
  79. package/dist/prompts/lead.d.ts +1 -1
  80. package/dist/prompts/lead.d.ts.map +1 -1
  81. package/dist/prompts/lead.js +456 -426
  82. package/dist/prompts/lead.js.map +1 -1
  83. package/dist/prompts/shared.d.ts +2 -2
  84. package/dist/prompts/shared.d.ts.map +1 -1
  85. package/dist/prompts/shared.js +38 -11
  86. package/dist/prompts/shared.js.map +1 -1
  87. package/dist/prompts/specialists.d.ts +2 -2
  88. package/dist/prompts/specialists.d.ts.map +1 -1
  89. package/dist/prompts/specialists.js +7 -6
  90. package/dist/prompts/specialists.js.map +1 -1
  91. package/dist/task-offload.d.ts +16 -0
  92. package/dist/task-offload.d.ts.map +1 -1
  93. package/dist/task-offload.js +51 -0
  94. package/dist/task-offload.js.map +1 -1
  95. package/dist/tm/browser.d.ts.map +1 -1
  96. package/dist/tm/browser.js +41 -10
  97. package/dist/tm/browser.js.map +1 -1
  98. package/dist/tm/dispatch.d.ts +86 -1
  99. package/dist/tm/dispatch.d.ts.map +1 -1
  100. package/dist/tm/dispatch.js +360 -39
  101. package/dist/tm/dispatch.js.map +1 -1
  102. package/dist/tm/dupe-guard.d.ts +16 -3
  103. package/dist/tm/dupe-guard.d.ts.map +1 -1
  104. package/dist/tm/dupe-guard.js +27 -7
  105. package/dist/tm/dupe-guard.js.map +1 -1
  106. package/dist/tm/index.d.ts +40 -1
  107. package/dist/tm/index.d.ts.map +1 -1
  108. package/dist/tm/index.js +40 -11
  109. package/dist/tm/index.js.map +1 -1
  110. package/dist/tm/ledger.d.ts +114 -0
  111. package/dist/tm/ledger.d.ts.map +1 -0
  112. package/dist/tm/ledger.js +308 -0
  113. package/dist/tm/ledger.js.map +1 -0
  114. package/dist/tm/perm-ask.d.ts +1 -3
  115. package/dist/tm/perm-ask.d.ts.map +1 -1
  116. package/dist/tm/perm-ask.js +10 -1
  117. package/dist/tm/perm-ask.js.map +1 -1
  118. package/dist/tm/preview.d.ts +55 -0
  119. package/dist/tm/preview.d.ts.map +1 -1
  120. package/dist/tm/preview.js +225 -0
  121. package/dist/tm/preview.js.map +1 -1
  122. package/dist/tm/search.d.ts.map +1 -1
  123. package/dist/tm/search.js +40 -10
  124. package/dist/tm/search.js.map +1 -1
  125. package/dist/tm/serp-loop.d.ts +45 -0
  126. package/dist/tm/serp-loop.d.ts.map +1 -0
  127. package/dist/tm/serp-loop.js +80 -0
  128. package/dist/tm/serp-loop.js.map +1 -0
  129. package/dist/tm/stats.d.ts +29 -0
  130. package/dist/tm/stats.d.ts.map +1 -1
  131. package/dist/tm/stats.js +278 -4
  132. package/dist/tm/stats.js.map +1 -1
  133. package/dist/tm/webfetch.d.ts +4 -0
  134. package/dist/tm/webfetch.d.ts.map +1 -1
  135. package/dist/tm/webfetch.js +75 -8
  136. package/dist/tm/webfetch.js.map +1 -1
  137. package/docs/installation-v2.md +445 -0
  138. package/docs/installation.md +12 -0
  139. package/docs/research/agent-data-exchange.md +117 -0
  140. package/docs/research/browser-pane.md +89 -0
  141. package/docs/research/host-http-api.md +132 -0
  142. package/docs/research/host-subagent-injection.md +187 -0
  143. package/docs/research/plugin-loader-contract.md +261 -0
  144. package/docs/research/v2-builtin-tools.md +447 -0
  145. package/docs/v2-port-notes.md +413 -0
  146. package/index.js +7 -0
  147. package/package.json +64 -61
  148. package/scripts/gen-v2-config.mjs +304 -0
  149. package/scripts/lib/config-surgery.cjs +239 -0
  150. package/scripts/lib/fake-ctx.mjs +169 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * v1 tool definitions -> v2 tool registrations.
3
+ *
4
+ * Two shapes have to be translated, and both translations are load-bearing:
5
+ *
6
+ * 1. THE RESULT. v1 tools answer `{output: string, attachments?: [...]}`. A
7
+ * live probe measured what the v2 host does with that: every tool that
8
+ * returned a bare `output` without declaring an `output` schema came back as
9
+ * "Tool result declared output without an output schema". So the v2 adapter
10
+ * answers with `content` parts instead — text plus `file` entries, which is
11
+ * also the first time tm_browser's screenshot attachment has had a host
12
+ * contract we can VERIFY rather than assume (the v1 capability row for it is
13
+ * still 未验证).
14
+ * 2. THE CONTEXT. Our tools read `{directory, sessionID, agent, ask}` off the
15
+ * per-call ctx. v2's ToolContext carries `{sessionID, agent, messageID, id,
16
+ * progress}` and NO directory and NO ask bridge. Directory comes from the
17
+ * boot location; the missing ask bridge is left missing on purpose, because
18
+ * `askFnOf` then reports "unavailable" and every governed call fails CLOSED
19
+ * rather than pretending somebody approved it.
20
+ */
21
+ import type { ToolDefinition } from "../types.js";
22
+ import type { V2ToolContext, V2ToolInfo, V2ToolResult } from "./v2-types.js";
23
+ /**
24
+ * `args` is a ZodRawShape (see `src/tm/args-schema.ts`) — but it is a
25
+ * *descriptor* when zod could not be loaded, and it may already be a JSON
26
+ * Schema. `exact:false` means the model gets no parameter guidance for this
27
+ * tool, which the caller reports instead of hiding: a tool the model cannot
28
+ * call correctly is a tool that is broken, whatever the code says.
29
+ */
30
+ export declare function inputSchemaFor(args: unknown): Promise<{
31
+ schema: Record<string, unknown>;
32
+ exact: boolean;
33
+ source: string;
34
+ note?: string;
35
+ }>;
36
+ /** The per-execute literal our pipelines expect. */
37
+ export declare function v2ToolCtx(ctx: V2ToolContext, directory: string): Record<string, unknown>;
38
+ export declare function v2Result(res: unknown): V2ToolResult;
39
+ export interface V2ToolBinding {
40
+ readonly tool: V2ToolInfo;
41
+ readonly inputExact: boolean;
42
+ /** How the schema was obtained: "zod" | "json-schema" | "descriptor" |
43
+ * "permissive". `exact` alone cannot tell a translated zod shape from a
44
+ * regex read of a descriptor string, and the boot log must not claim the
45
+ * two are the same fact. */
46
+ readonly inputSource: string;
47
+ readonly note?: string;
48
+ }
49
+ /**
50
+ * Wrap one v1 ToolDefinition. `execute` may be absent on exotic hosts; a tool
51
+ * that cannot run must not be registered at all, because the model would spend
52
+ * a round on it and get nothing.
53
+ */
54
+ export declare function bindV2Tool(name: string, def: ToolDefinition, directory: string,
55
+ /** Every call to OUR tool tells the host-scope resolver which sessions belong to
56
+ * Team (#22) — the one fact about a session we can learn from the inside. */
57
+ onCall?: (agent: unknown, sessionID: unknown) => void,
58
+ /** `codemodeDirect: true` sends `options:{codemode:false}`, which the 2.0.16
59
+ * binary uses as the visibility switch: without it a registered tool reaches the
60
+ * model ONLY inside the Code Mode catalog, with its description cut to the first
61
+ * line — so every governance sentence we wrote below that line never arrives.
62
+ * Off by default because the cost is the whole definition set riding every
63
+ * request; the number is measured, not argued (see TM_V2_CODEMODE). */
64
+ opts?: {
65
+ codemodeDirect?: boolean;
66
+ }): Promise<V2ToolBinding | null>;
67
+ //# sourceMappingURL=v2-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-tool.d.ts","sourceRoot":"","sources":["../../src/host/v2-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAA;AACnF,OAAO,KAAK,EAAa,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAkFvF;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgC7F;AAED,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWxF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAcnD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B;;;iCAG6B;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM;AACjB;8EAC8E;AAC9E,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI;AACrD;;;;;wEAKwE;AACxE,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAkB/B"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * v1 tool definitions -> v2 tool registrations.
3
+ *
4
+ * Two shapes have to be translated, and both translations are load-bearing:
5
+ *
6
+ * 1. THE RESULT. v1 tools answer `{output: string, attachments?: [...]}`. A
7
+ * live probe measured what the v2 host does with that: every tool that
8
+ * returned a bare `output` without declaring an `output` schema came back as
9
+ * "Tool result declared output without an output schema". So the v2 adapter
10
+ * answers with `content` parts instead — text plus `file` entries, which is
11
+ * also the first time tm_browser's screenshot attachment has had a host
12
+ * contract we can VERIFY rather than assume (the v1 capability row for it is
13
+ * still 未验证).
14
+ * 2. THE CONTEXT. Our tools read `{directory, sessionID, agent, ask}` off the
15
+ * per-call ctx. v2's ToolContext carries `{sessionID, agent, messageID, id,
16
+ * progress}` and NO directory and NO ask bridge. Directory comes from the
17
+ * boot location; the missing ask bridge is left missing on purpose, because
18
+ * `askFnOf` then reports "unavailable" and every governed call fails CLOSED
19
+ * rather than pretending somebody approved it.
20
+ */
21
+ /** zod is a peer the host ships, never a dependency we require: the same
22
+ * variable-specifier trick `args-schema.ts` uses for the arg schemas. */
23
+ async function loadZod() {
24
+ try {
25
+ const spec = "zod";
26
+ const mod = (await import(spec));
27
+ const z = (mod.z ?? mod.default?.z);
28
+ return z && typeof z.object === "function" ? z : null;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ /** A descriptor entry: `{ key: { descriptor: "name: type (…) — guidance" } }`.
35
+ * Three tools ship this shape (tm_join / tm_pty / tm_stats) because their args
36
+ * are built without zod, and feeding it to `z.object()` throws
37
+ * `undefined is not an object (evaluating 'schema._zod.def')` — measured live,
38
+ * where those three reached the model with NO parameter guidance at all.
39
+ * The descriptor's leading `name: type` is parseable, and the whole string is
40
+ * the guidance, so translating it is strictly better than a permissive schema. */
41
+ const DESCRIPTOR_HEAD = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([\s\S]*)$/;
42
+ /** `typed` is what follows the `name:` in the descriptor — the type is read off
43
+ * its first token. Passing the whole line instead would read the parameter
44
+ * NAME plus its colon (`action:`), which matches no type shape at all, so every
45
+ * descriptor would collapse to `string` and the enum/array/number guidance
46
+ * would be silently lost. `full` stays the description verbatim: the guidance
47
+ * after the type is the part the model actually needs. */
48
+ function descriptorToProperty(full, typed) {
49
+ const head = (typed.trim().match(/^[^\s(,]+/) ?? [""])[0];
50
+ let type = "string";
51
+ let enumValues;
52
+ if (/^[A-Za-z][\w.]*\[\]$/.test(head)) {
53
+ type = "array";
54
+ }
55
+ else if (/^\d+$/.test(head) || /^(number|int|integer)/i.test(head)) {
56
+ type = "number";
57
+ }
58
+ else if (/^(true|false|boolean)$/i.test(head)) {
59
+ type = "boolean";
60
+ }
61
+ else if (/^[A-Za-z0-9_|-]*\|[A-Za-z0-9_|-]+$/.test(head)) {
62
+ enumValues = head.split("|").filter(Boolean);
63
+ type = "string";
64
+ }
65
+ const prop = { type };
66
+ if (type === "array")
67
+ prop.items = { type: "string" };
68
+ if (enumValues)
69
+ prop.enum = enumValues;
70
+ prop.description = full.trim();
71
+ return prop;
72
+ }
73
+ function fromDescriptors(shape) {
74
+ const properties = {};
75
+ const required = [];
76
+ let seen = 0;
77
+ for (const [key, value] of Object.entries(shape)) {
78
+ const text = typeof value === "string"
79
+ ? `${key}: ${value}`
80
+ : typeof value?.descriptor === "string"
81
+ ? String(value.descriptor)
82
+ : null;
83
+ if (!text)
84
+ continue;
85
+ seen++;
86
+ const m = text.match(DESCRIPTOR_HEAD);
87
+ properties[key] = m
88
+ ? descriptorToProperty(text, m[2] ?? "")
89
+ : { type: "string", description: text };
90
+ // `(required)` is explicit in the fallback schemas; `(optional` marks the
91
+ // rest. Anything unmarked stays optional — execute() coerces raw args
92
+ // itself, and a wrong `required` makes the host reject a valid call.
93
+ if (/\(required\)/i.test(text) && !/optional/i.test(text))
94
+ required.push(key);
95
+ }
96
+ if (!seen || seen !== Object.keys(shape).length)
97
+ return null;
98
+ const schema = { type: "object", properties, additionalProperties: false };
99
+ if (required.length)
100
+ schema.required = required;
101
+ return { schema, required };
102
+ }
103
+ /**
104
+ * `args` is a ZodRawShape (see `src/tm/args-schema.ts`) — but it is a
105
+ * *descriptor* when zod could not be loaded, and it may already be a JSON
106
+ * Schema. `exact:false` means the model gets no parameter guidance for this
107
+ * tool, which the caller reports instead of hiding: a tool the model cannot
108
+ * call correctly is a tool that is broken, whatever the code says.
109
+ */
110
+ export async function inputSchemaFor(args) {
111
+ if (args && typeof args === "object") {
112
+ const shape = args;
113
+ if (typeof shape.type === "string" && (shape.properties || shape.additionalProperties !== undefined)) {
114
+ return { schema: shape, exact: true, source: "json-schema" };
115
+ }
116
+ const descriptors = fromDescriptors(shape);
117
+ if (descriptors) {
118
+ return { schema: descriptors.schema, exact: true, source: "descriptor" };
119
+ }
120
+ const z = await loadZod();
121
+ const toJSONSchema = z?.toJSONSchema;
122
+ if (z && toJSONSchema) {
123
+ try {
124
+ const schema = toJSONSchema(z.object(shape));
125
+ return { schema, exact: true, source: "zod" };
126
+ }
127
+ catch (err) {
128
+ return {
129
+ schema: { type: "object", additionalProperties: true },
130
+ exact: false,
131
+ source: "permissive",
132
+ note: `zod 形状转换失败:${err?.message ?? String(err)}`,
133
+ };
134
+ }
135
+ }
136
+ }
137
+ return {
138
+ schema: { type: "object", additionalProperties: true },
139
+ exact: false,
140
+ source: "permissive",
141
+ note: "宿主未提供 zod,参数表退化为不限形状",
142
+ };
143
+ }
144
+ /** The per-execute literal our pipelines expect. */
145
+ export function v2ToolCtx(ctx, directory) {
146
+ const c = (ctx ?? {});
147
+ return {
148
+ // A future host may carry a per-call directory (sessions CAN move); honor it
149
+ // when present instead of pinning the boot value.
150
+ directory: typeof c.directory === "string" && c.directory ? c.directory : directory,
151
+ sessionID: String(c.sessionID ?? ""),
152
+ agent: String(c.agent ?? ""),
153
+ // NOTE: no `ask` on purpose — see the header. Adding a stub that resolves
154
+ // would be the self-allowing this codebase refuses.
155
+ };
156
+ }
157
+ export function v2Result(res) {
158
+ // `ToolResult` is a union: most tm_* answers are already plain strings.
159
+ if (typeof res === "string")
160
+ return { content: [{ type: "text", text: res }] };
161
+ const out = (res ?? {});
162
+ const text = typeof out.output === "string" ? out.output : String(out.output ?? "");
163
+ const content = [{ type: "text", text }];
164
+ for (const att of (out.attachments ?? [])) {
165
+ if (!att || typeof att.url !== "string" || !att.url)
166
+ continue;
167
+ content.push({ type: "file", uri: att.url, mime: att.mime, name: att.filename });
168
+ }
169
+ const metadata = out.metadata;
170
+ return metadata && typeof metadata === "object"
171
+ ? { content, metadata }
172
+ : { content };
173
+ }
174
+ /**
175
+ * Wrap one v1 ToolDefinition. `execute` may be absent on exotic hosts; a tool
176
+ * that cannot run must not be registered at all, because the model would spend
177
+ * a round on it and get nothing.
178
+ */
179
+ export async function bindV2Tool(name, def, directory,
180
+ /** Every call to OUR tool tells the host-scope resolver which sessions belong to
181
+ * Team (#22) — the one fact about a session we can learn from the inside. */
182
+ onCall,
183
+ /** `codemodeDirect: true` sends `options:{codemode:false}`, which the 2.0.16
184
+ * binary uses as the visibility switch: without it a registered tool reaches the
185
+ * model ONLY inside the Code Mode catalog, with its description cut to the first
186
+ * line — so every governance sentence we wrote below that line never arrives.
187
+ * Off by default because the cost is the whole definition set riding every
188
+ * request; the number is measured, not argued (see TM_V2_CODEMODE). */
189
+ opts = {}) {
190
+ if (typeof def?.execute !== "function")
191
+ return null;
192
+ const { schema, exact, source, note } = await inputSchemaFor(def.args);
193
+ const tool = {
194
+ name,
195
+ description: String(def.description ?? ""),
196
+ input: schema,
197
+ ...(opts.codemodeDirect ? { options: { codemode: false } } : {}),
198
+ async execute(args, ctx) {
199
+ onCall?.(ctx?.agent, ctx?.sessionID);
200
+ // Our tools are defensive about raw model args already (they coerce
201
+ // string booleans and JSON-array strings themselves), so nothing is
202
+ // normalized here beyond a guaranteed object.
203
+ const res = await def.execute?.((args ?? {}), v2ToolCtx(ctx, directory));
204
+ return v2Result(res);
205
+ },
206
+ };
207
+ return { tool, inputExact: exact, inputSource: source, note };
208
+ }
209
+ //# sourceMappingURL=v2-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-tool.js","sourceRoot":"","sources":["../../src/host/v2-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Reading a CHILD session's own messages — in process, with no credential.
3
+ *
4
+ * This is the answer to the HTTP-API decision (task #32). The host's own API
5
+ * (`docs/research/host-http-api.md`) does expose `GET /api/session/{id}/message`, and using
6
+ * it would have meant reading the Basic-auth password out of
7
+ * `<global-config>/service.json` — a secret that would then live in this plugin's memory,
8
+ * in every error string the fetch layer can produce, and in any log line that quotes a
9
+ * request. The user's condition for going there was "prove it cannot leak".
10
+ *
11
+ * Measured instead, on a live 2.0.18 with a plugin that only inspects its own ctx (zero
12
+ * model tokens, `--model nope/nope`): the plugin ctx carries a full `session` domain —
13
+ *
14
+ * hook create get switchAgent switchModel prompt generate command synthetic interrupt
15
+ * update move wait context
16
+ *
17
+ * and `ctx.session.context({ sessionID })` returns the session's message array. On the child
18
+ * session of a real background dispatch that array had 5 items shaped
19
+ * `{id, time:{created}, text, type}`. `ctx.session.get({sessionID})` returns
20
+ * `{id, parentID, projectID, agent, model, outcome, tokens, title, location}`.
21
+ *
22
+ * So the capability was in front of us the whole time and the password was never needed:
23
+ * nothing here opens a socket, reads a credential file, or can be redirected to a port that
24
+ * is not our own host process. That is a stronger guarantee than "we will keep the secret
25
+ * safe" — there is no secret.
26
+ *
27
+ * The one thing this MUST still earn is scope. `session.context` will answer for ANY session
28
+ * id handed to it, including the user's unrelated `build`/`plan` sessions, which makes it a
29
+ * private-content oracle if used carelessly. Therefore: parentage is verified with
30
+ * `session.get` FIRST, and a session that is not the caller's own child is refused without
31
+ * being read. The refusal is counted (`refused`) so "we did not look" stays distinguishable
32
+ * from "we looked and were denied". Text bodies are never written to the trajectory — ids,
33
+ * item counts and the chosen message's TYPE only, per R6.
34
+ */
35
+ export interface V2TranscriptReport {
36
+ /** read() calls made */
37
+ attempted: number;
38
+ /** calls that returned a non-empty body */
39
+ resolved: number;
40
+ /** calls refused because session.get said the child is not the caller's */
41
+ refused: number;
42
+ /** calls where the parentage check itself could not answer (no seam, host error) */
43
+ unverifiable: number;
44
+ lastError?: string;
45
+ }
46
+ export interface V2TranscriptResult {
47
+ text: string;
48
+ /** how many messages the host handed back */
49
+ items: number;
50
+ /** the `type` of the message the body was taken from, when it had one */
51
+ pickedType?: string;
52
+ /** why there is no body — names the seam that failed, never a guess */
53
+ error?: string;
54
+ }
55
+ export interface V2TranscriptReader {
56
+ read: (sessionID: string, callerSessionID: string) => Promise<V2TranscriptResult>;
57
+ report: V2TranscriptReport;
58
+ /** Whether this host gives the seam at all — the caller says so out loud when not. */
59
+ active: boolean;
60
+ }
61
+ /** The child's ANSWER is the last non-user message that carries text. Taking the last,
62
+ * rather than concatenating the transcript, is the whole point: the lead asked for the
63
+ * report, and the earlier turns are the work it does not want to pay tokens for. The type
64
+ * of the chosen item is returned so the reply can say where the text came from instead of
65
+ * implying it read the whole session. */
66
+ export declare function pickChildReply(items: unknown[]): {
67
+ text: string;
68
+ type?: string;
69
+ };
70
+ export declare function createV2TranscriptReader(ctx: unknown): V2TranscriptReader;
71
+ /** One line for tm_stats: what the reader was asked for and what it could say. */
72
+ export declare function transcriptSummary(r: V2TranscriptReport): string;
73
+ //# sourceMappingURL=v2-transcript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-transcript.d.ts","sourceRoot":"","sources":["../../src/host/v2-transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAA;IACf,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjF,MAAM,EAAE,kBAAkB,CAAA;IAC1B,sFAAsF;IACtF,MAAM,EAAE,OAAO,CAAA;CAChB;AAkCD;;;;0CAI0C;AAC1C,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAQhF;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CA2DzE;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAO/D"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Reading a CHILD session's own messages — in process, with no credential.
3
+ *
4
+ * This is the answer to the HTTP-API decision (task #32). The host's own API
5
+ * (`docs/research/host-http-api.md`) does expose `GET /api/session/{id}/message`, and using
6
+ * it would have meant reading the Basic-auth password out of
7
+ * `<global-config>/service.json` — a secret that would then live in this plugin's memory,
8
+ * in every error string the fetch layer can produce, and in any log line that quotes a
9
+ * request. The user's condition for going there was "prove it cannot leak".
10
+ *
11
+ * Measured instead, on a live 2.0.18 with a plugin that only inspects its own ctx (zero
12
+ * model tokens, `--model nope/nope`): the plugin ctx carries a full `session` domain —
13
+ *
14
+ * hook create get switchAgent switchModel prompt generate command synthetic interrupt
15
+ * update move wait context
16
+ *
17
+ * and `ctx.session.context({ sessionID })` returns the session's message array. On the child
18
+ * session of a real background dispatch that array had 5 items shaped
19
+ * `{id, time:{created}, text, type}`. `ctx.session.get({sessionID})` returns
20
+ * `{id, parentID, projectID, agent, model, outcome, tokens, title, location}`.
21
+ *
22
+ * So the capability was in front of us the whole time and the password was never needed:
23
+ * nothing here opens a socket, reads a credential file, or can be redirected to a port that
24
+ * is not our own host process. That is a stronger guarantee than "we will keep the secret
25
+ * safe" — there is no secret.
26
+ *
27
+ * The one thing this MUST still earn is scope. `session.context` will answer for ANY session
28
+ * id handed to it, including the user's unrelated `build`/`plan` sessions, which makes it a
29
+ * private-content oracle if used carelessly. Therefore: parentage is verified with
30
+ * `session.get` FIRST, and a session that is not the caller's own child is refused without
31
+ * being read. The refusal is counted (`refused`) so "we did not look" stays distinguishable
32
+ * from "we looked and were denied". Text bodies are never written to the trajectory — ids,
33
+ * item counts and the chosen message's TYPE only, per R6.
34
+ */
35
+ /** Unwrap whatever envelope the host puts on a result object. */
36
+ function unwrap(raw) {
37
+ if (!raw || typeof raw !== "object")
38
+ return null;
39
+ const rec = raw;
40
+ for (const cand of [rec, rec.data, rec.result, rec.session]) {
41
+ if (cand && typeof cand === "object")
42
+ return cand;
43
+ }
44
+ return rec;
45
+ }
46
+ /** The text one message item carries, across the shapes the host has been seen to use:
47
+ * a bare `text` (measured on 2.0.18), `parts[]` (the persisted message shape), and
48
+ * `content[]` (the tool-result shape). Never descends into a tool payload. */
49
+ function itemText(raw) {
50
+ if (!raw || typeof raw !== "object")
51
+ return null;
52
+ const it = raw;
53
+ const type = String(it.type ?? it.role ?? "");
54
+ const direct = it.text;
55
+ if (typeof direct === "string" && direct.trim())
56
+ return { text: direct, type };
57
+ for (const key of ["parts", "content"]) {
58
+ const arr = it[key];
59
+ if (!Array.isArray(arr))
60
+ continue;
61
+ const texts = arr
62
+ .map((p) => (p && typeof p === "object" ? p.text : undefined))
63
+ .filter((t) => typeof t === "string" && t.trim().length > 0);
64
+ if (texts.length)
65
+ return { text: texts.join(String.fromCharCode(10)), type };
66
+ }
67
+ return null;
68
+ }
69
+ /** The child's ANSWER is the last non-user message that carries text. Taking the last,
70
+ * rather than concatenating the transcript, is the whole point: the lead asked for the
71
+ * report, and the earlier turns are the work it does not want to pay tokens for. The type
72
+ * of the chosen item is returned so the reply can say where the text came from instead of
73
+ * implying it read the whole session. */
74
+ export function pickChildReply(items) {
75
+ for (let i = items.length - 1; i >= 0; i--) {
76
+ const t = itemText(items[i]);
77
+ if (!t)
78
+ continue;
79
+ if (/^user$/i.test(t.type))
80
+ continue;
81
+ return { text: t.text, type: t.type || undefined };
82
+ }
83
+ return { text: "" };
84
+ }
85
+ export function createV2TranscriptReader(ctx) {
86
+ const report = { attempted: 0, resolved: 0, refused: 0, unverifiable: 0 };
87
+ const session = ctx?.session;
88
+ const getContext = session?.context;
89
+ const get = session?.get;
90
+ const active = typeof getContext === "function";
91
+ const call = async (fn, arg) => await fn.call(session, arg);
92
+ const read = async (sessionID, callerSessionID) => {
93
+ report.attempted++;
94
+ if (!active || typeof getContext !== "function") {
95
+ return { text: "", items: 0, error: "这个宿主没给 ctx.session.context" };
96
+ }
97
+ if (!sessionID || !callerSessionID)
98
+ return { text: "", items: 0, error: "缺少会话 id,无法核验归属" };
99
+ // Scope FIRST. A reader that takes whatever id it is handed is a private-content oracle,
100
+ // and "the user approved the API" does not extend to their unrelated sessions.
101
+ if (typeof get !== "function") {
102
+ report.unverifiable++;
103
+ return { text: "", items: 0, error: "宿主没给 ctx.session.get,无法核验子会话归属,因此没有读取正文" };
104
+ }
105
+ let parentID;
106
+ try {
107
+ const rec = unwrap(await call(get, { sessionID }));
108
+ const p = rec?.parentID ?? rec?.parent_id;
109
+ parentID = typeof p === "string" && p ? p : undefined;
110
+ }
111
+ catch (err) {
112
+ report.unverifiable++;
113
+ report.lastError = String(err?.message ?? err).slice(0, 160);
114
+ return { text: "", items: 0, error: `归属核验失败:${report.lastError ?? "宿主未回应"}` };
115
+ }
116
+ if (!parentID) {
117
+ report.unverifiable++;
118
+ return { text: "", items: 0, error: "宿主回答里没有 parentID,无法确认这个会话是你的子会话,因此没有读取正文" };
119
+ }
120
+ if (parentID !== callerSessionID) {
121
+ report.refused++;
122
+ return { text: "", items: 0, error: "这个会话不是你的子会话(宿主给的 parentID 不匹配),我没有读它" };
123
+ }
124
+ try {
125
+ const raw = await call(getContext, { sessionID });
126
+ const arr = Array.isArray(raw) ? raw : Array.isArray(raw?.data) ? raw.data : null;
127
+ if (!arr) {
128
+ report.lastError = "context 返回值不是数组";
129
+ return { text: "", items: 0, error: report.lastError };
130
+ }
131
+ const picked = pickChildReply(arr);
132
+ if (picked.text)
133
+ report.resolved++;
134
+ return { text: picked.text, items: arr.length, pickedType: picked.type };
135
+ }
136
+ catch (err) {
137
+ report.lastError = String(err?.message ?? err).slice(0, 160);
138
+ return { text: "", items: 0, error: `ctx.session.context 失败:${report.lastError}` };
139
+ }
140
+ };
141
+ return { read, report, active };
142
+ }
143
+ /** One line for tm_stats: what the reader was asked for and what it could say. */
144
+ export function transcriptSummary(r) {
145
+ if (!r.attempted)
146
+ return "子会话正文读取:没被调用过(缝在场,没数据)";
147
+ return (`子会话正文读取:尝试 ${r.attempted} · 拿到正文 ${r.resolved} · ` +
148
+ `归属不符拒绝 ${r.refused} · 无法核验 ${r.unverifiable}` +
149
+ (r.lastError ? ` · 最后错误:${r.lastError}` : ""));
150
+ }
151
+ //# sourceMappingURL=v2-transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-transcript.js","sourceRoot":"","sources":["../../src/host/v2-transcript.ts"],"names":[],"mappings":"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"}