@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,390 @@
1
+ /**
2
+ * The v2 session read seam, shaped like the v1 client the collect path expects (#8).
3
+ *
4
+ * `tm_join` collects a child in two ways: it looks the child up in its own registry
5
+ * (children THIS plugin process created — and since `babfcb8` also the host's `subagent`
6
+ * children), and otherwise it asks the host. That ask was written against v1's SDK client
7
+ * (`client.session.get({path:{id}})`), and on a live host it never once resolved.
8
+ *
9
+ * Why it failed, read out of 2.0.18 rather than guessed (both quotes are from the embedded
10
+ * JS): the plugin-facing wrapper is a schema decode plus a single-object call —
11
+ *
12
+ * te = (schema, fn) => (input) => decode(schema, input ?? {}) → fn(decoded)
13
+ * get: te(N["session.get"], a.session.get)
14
+ *
15
+ * and the host's own call sites are flat:
16
+ *
17
+ * await e.session.get({ sessionID: n })
18
+ * await e.message.list({ sessionID: n, limit: 200, cursor: r })
19
+ *
20
+ * So our adapter had TWO bugs: the key (`path.id` / `id` instead of `sessionID`) and the
21
+ * arity (every shape was passed as a one-element ARRAY, which no `te`-wrapped method
22
+ * accepts). A decode failure looks exactly like "the host has no such method", which is
23
+ * how this stayed wrong for a whole release cycle.
24
+ *
25
+ * What this surface does NOT give, stated rather than discovered later:
26
+ * · no `children` method, so adoption from the host's session tree is still impossible on
27
+ * v2 — only an explicitly named id can be claimed, which is what the lead's prompt says.
28
+ * · no `message`/`messages` domain on the plugin ctx (the host's internal `message.list`
29
+ * is the SDK client, not this surface). `context` is the only candidate that could
30
+ * carry a child's reply, so it is tried, and its outcome — including the NAMES of the
31
+ * keys it returned — is recorded. Key names are safe; a message body is not written to
32
+ * the trajectory by this file.
33
+ * · the HTTP API does expose `GET /api/session/{id}/message` (136 distinct routes were
34
+ * enumerated from a scanned window of the binary, and none of them is a todo list —
35
+ * which settles the `tm_ledger` question: there is no host todo resource to read), but
36
+ * reaching it needs the basic-auth password from
37
+ * `~/.config/opencode/service.json`. A plugin reading the user's credential file to
38
+ * call back into the host is a new trust boundary, so it is NOT done here; it is
39
+ * recorded as the option with its cost attached. See
40
+ * `docs/research/host-http-api.md`.
41
+ */
42
+ /** Measured first, then the v1 spellings kept as fallbacks for an older 2.x build. Each
43
+ * builder returns the ARGUMENT OBJECT — `te`-wrapped methods take one object, not an
44
+ * array, and that alone is why every previous shape failed. */
45
+ const SHAPES = [
46
+ ["sessionID", (id) => ({ sessionID: id })],
47
+ ["path", (id) => ({ path: { id } })],
48
+ ["flat", (id) => ({ id })],
49
+ ];
50
+ function idOf(opts) {
51
+ const o = (opts ?? {});
52
+ return String(o.path?.id ?? o.query?.id ?? o.sessionID ?? o.id ?? "");
53
+ }
54
+ function unwrap(value) {
55
+ if (!value || typeof value !== "object")
56
+ return undefined;
57
+ const rec = value;
58
+ // `{data}` and `{result}` are both envelopes on this surface; reading a field off the
59
+ // wrapper yields undefined, which then reads as "not my child" and refuses a child that is.
60
+ for (const cand of [rec, rec.data, rec.result, rec.session]) {
61
+ if (cand && typeof cand === "object" && (("parentID" in cand) || ("parent_id" in cand) || ("id" in cand))) {
62
+ return cand;
63
+ }
64
+ }
65
+ return rec;
66
+ }
67
+ /** The message-kind values the host writes on its discriminator field — the members of the
68
+ * published union `Session.Message.Info`. Anything else on `type` is a PART kind and must
69
+ * never be read as a message kind. */
70
+ const MESSAGE_KINDS = ["user", "assistant", "system", "synthetic", "skill", "shell", "compaction", "idle"];
71
+ /** The PART kinds the host writes inside a message's `content` bag. A TOP-LEVEL item
72
+ * carrying one of these on `type` with no `role` is a part, not a message (the shape
73
+ * `{type:"tool", content:[{type:"text",…}]}` exists): renaming its bag to `parts` would
74
+ * hand a tool output to the collect path as an unroled assistant candidate. */
75
+ const PART_KINDS = ["text", "reasoning", "tool"];
76
+ /** The discriminator field's own value, lower-cased — "" only when the field is ABSENT
77
+ * (or not a string). "Present but unknown" and "absent" are two different facts, and
78
+ * downstream can only tell them apart if the seam keeps them apart. */
79
+ function rawKind(value) {
80
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
81
+ }
82
+ function messageKind(value) {
83
+ const s = rawKind(value);
84
+ return MESSAGE_KINDS.includes(s) ? s : "";
85
+ }
86
+ /** Which kind of message an item is. The OpenAPI contract puts the discriminator on `type`;
87
+ * the plugin ctx measured on 2.0.20 puts it on `role` — so BOTH are read, a recognised
88
+ * kind first (`role` before `type`), exactly as before.
89
+ *
90
+ * A value that is PRESENT but not a known message kind is carried through verbatim
91
+ * (lower-cased) instead of dropped to "". This INVERTS the previous rule — "an
92
+ * unrecognised value yields "" and the caller leaves the role OFF instead of guessing
93
+ * one" — because that rule was false where it mattered: `lastAssistantMessage` skips on
94
+ * `if (role && role !== "assistant")`, so an EMPTY role IS an assistant candidate,
95
+ * exactly equivalent to guessing "assistant". A host that spelled the discriminator a
96
+ * value outside MESSAGE_KINDS would have had its item delivered as the child's report
97
+ * while the comment claimed the opposite (and while AGENTS.md's "keeps an EMPTY role …
98
+ * rather than guessing" described downstream semantics under which leaving it empty was
99
+ * the guess). Carrying the raw value makes the skip real: unknown kind ⇒ not delivered.
100
+ * Only when BOTH fields are absent — a bare Part[] item — does the role stay unset,
101
+ * which is the shape the collect path reads by the item's own `type:"text"`. */
102
+ function roleOfMessage(rec) {
103
+ const roleRaw = rawKind(rec.role);
104
+ const typeRaw = rawKind(rec.type);
105
+ return messageKind(roleRaw) || messageKind(typeRaw) || roleRaw || typeRaw;
106
+ }
107
+ /** Copy the host's own timestamps, and ONLY those. `time.completed` IS the settle verdict
108
+ * (AGENTS.md), so it is never invented: 2.0.20's plugin ctx carries no `time` field at all,
109
+ * and tm_join then settles from `event` / `injection` / 推定 — which is what it prints. */
110
+ function timeOfMessage(rec) {
111
+ const t = rec.time;
112
+ if (!t || typeof t !== "object")
113
+ return undefined;
114
+ const src = t;
115
+ const out = {};
116
+ const created = Number(src.created);
117
+ if (Number.isFinite(created))
118
+ out.created = created;
119
+ const completed = Number(src.completed);
120
+ if (Number.isFinite(completed))
121
+ out.completed = completed;
122
+ return Object.keys(out).length ? out : undefined;
123
+ }
124
+ /** The `{info,…}` envelope for a message item, carrying ONLY what the host actually wrote. */
125
+ function infoOfMessage(rec, role) {
126
+ const time = timeOfMessage(rec);
127
+ return {
128
+ ...(role ? { role } : {}),
129
+ ...(time ? { time } : {}),
130
+ // an errored assistant turn carries its reason on the item itself in these shapes;
131
+ // without the copy, "no reply" reads as "the agent had nothing to say"
132
+ ...(rec.error == null ? {} : { error: rec.error }),
133
+ };
134
+ }
135
+ /** Turn the host's context items into the `{info,parts}` shape the collect path already
136
+ * understands — HERE, at the seam that knows the shape, so nothing downstream has to guess.
137
+ * Three shapes are in the wild and all three are measurements, not version numbers:
138
+ * · 2.0.18 `[L]`: a FLAT item per message, `{id, time:{created}, text, type}`.
139
+ * · 2.0.20 `[L][D]`: a MESSAGE whose body is `content: (Text|Reasoning|Tool)[]` and whose
140
+ * kind is on `role` — the name-level probe recorded `{keys:["content","id","metadata",
141
+ * "role"]}`. The previous version of this function passed that item through untouched
142
+ * ("already message-shaped"), `lastAssistantMessage` found no `parts` and no `text` on
143
+ * it, and the seam answered while the body was dropped AGAIN — which is why 正文来源=
144
+ * never printed on 2.0.20 (A1).
145
+ * · v1's `[{info,parts[]}]`: passed through untouched, so a host that changes back needs
146
+ * no change here.
147
+ * Only the bag is renamed and the envelope added: the elements are already v1 part shapes
148
+ * (`{type:"text", text}`), and reasoning/tool parts stay exactly as the host wrote them.
149
+ * An empty `content` normalises to empty parts — this function MOVES text, it never
150
+ * manufactures any. */
151
+ export function normaliseContextMessages(list) {
152
+ if (!Array.isArray(list))
153
+ return list;
154
+ return list.map((item) => {
155
+ if (!item || typeof item !== "object")
156
+ return item;
157
+ const rec = item;
158
+ if (rec.info || Array.isArray(rec.parts))
159
+ return item;
160
+ if (Array.isArray(rec.content)) {
161
+ // A PART item (no `role`, `type` a part kind) is not a message: renaming its bag to
162
+ // `parts` would make it an unroled assistant candidate downstream, i.e. a TOOL OUTPUT
163
+ // delivered as the child's report — while passing it through untouched was the SAFE
164
+ // case, because the collect path reads a part's own `type` and skips `tool`.
165
+ if (!rawKind(rec.role) && PART_KINDS.includes(rawKind(rec.type)))
166
+ return item;
167
+ return { info: infoOfMessage(rec, roleOfMessage(rec)), parts: rec.content };
168
+ }
169
+ const text = rec.text;
170
+ if (typeof text !== "string" || !text.trim())
171
+ return item;
172
+ // 2.0.18's flat item: a recognised role word is read from either field; anything else
173
+ // (the measured answer items carry `type:"text"`, a PART kind) falls to "assistant",
174
+ // which is the behaviour that shipped and that the 2.0.18 probe pinned. This branch
175
+ // deliberately keeps the fallback the content[] branch above no longer needs: a flat
176
+ // item's `type` is the PART kind of its own body, not a message discriminator, so
177
+ // carrying the raw value here would skip the real 2.0.18 replies.
178
+ return {
179
+ info: infoOfMessage(rec, messageKind(rec.role) || messageKind(rec.type) || "assistant"),
180
+ parts: [{ type: "text", text }],
181
+ };
182
+ });
183
+ }
184
+ /** WHY a body came back empty, in names and counts only — never a value, a path, or a
185
+ * snippet of text (the R6 口径 binds a diagnostic). tm_join writes this onto the
186
+ * `child_body_missing` trajectory line so the three conclusions stay distinguishable:
187
+ * a real body (`child_body`), a seam that answered with nothing readable in it
188
+ * (`items=2 keys=[content+id+metadata+role] content=1 kinds=[tool] text=0`), and a seam
189
+ * that did not answer at all (`no-context-method`). Without it, "we read it" and "we could
190
+ * not read it" print the same row — goal #6's failure shape. */
191
+ export function contextShapeEvidence(list) {
192
+ if (list === undefined || list === null)
193
+ return "no-list";
194
+ if (!Array.isArray(list))
195
+ return `not-array(${typeof list})`;
196
+ if (list.length === 0)
197
+ return "items=0";
198
+ const last = list[list.length - 1];
199
+ if (!last || typeof last !== "object")
200
+ return `items=${list.length} last=${last === null ? "null" : typeof last}`;
201
+ const rec = last;
202
+ const keys = Object.keys(rec).slice(0, 12).join("+");
203
+ const bag = Array.isArray(rec.content) ? "content" : Array.isArray(rec.parts) ? "parts" : "";
204
+ if (bag) {
205
+ const arr = rec[bag];
206
+ const kinds = Array.from(new Set(arr.map((p) => (p && typeof p === "object" ? String(p.type ?? "?") : typeof p))))
207
+ .slice(0, 6)
208
+ .join("+");
209
+ let withText = 0;
210
+ for (const p of arr) {
211
+ const t = p?.text;
212
+ if (typeof t === "string" && t.trim())
213
+ withText++;
214
+ }
215
+ return `items=${list.length} keys=[${keys}] ${bag}=${arr.length} kinds=[${kinds}] text=${withText}`;
216
+ }
217
+ if (typeof rec.text === "string")
218
+ return `items=${list.length} keys=[${keys}] textlen=${rec.text.length}`;
219
+ return `items=${list.length} keys=[${keys}] nobag`;
220
+ }
221
+ /** The one name this bridge has for itself, so a reply credits the seam that answered and a
222
+ * refusal names the seam that did not — never the v1 endpoint this host does not have. */
223
+ const SEAM = "ctx.session.context";
224
+ export function createV2SessionReader(ctx) {
225
+ const report = {
226
+ attempted: 0, resolved: 0, failedShapes: [], contextTried: 0, contextOk: 0, contextKeys: [],
227
+ interruptTried: 0, interruptConfirmed: 0, interruptRefused: 0, interruptUnknown: 0, interruptKeys: [],
228
+ };
229
+ const domain = ctx?.session;
230
+ const call = async (method, arg) => {
231
+ const fn = domain?.[method];
232
+ if (typeof fn !== "function")
233
+ return undefined;
234
+ // Property access on the domain, never a captured reference: a detached `get` loses
235
+ // its receiver and the host's client throws (the dispatch.ts §10 rule).
236
+ return await fn.call(domain, arg);
237
+ };
238
+ const client = {
239
+ session: {
240
+ get: async (opts) => {
241
+ const id = idOf(opts);
242
+ report.attempted++;
243
+ if (!id || !id.startsWith("ses"))
244
+ return { data: undefined };
245
+ const tried = [];
246
+ for (const [shape, build] of SHAPES) {
247
+ try {
248
+ const raw = await call("get", build(id));
249
+ const rec = unwrap(raw);
250
+ if (rec) {
251
+ report.resolved++;
252
+ report.usedShape = shape;
253
+ report.failedShapes = [];
254
+ const parent = rec.parentID ?? rec.parent_id;
255
+ return { data: { id, parentID: typeof parent === "string" ? parent : undefined, raw: rec } };
256
+ }
257
+ tried.push(shape);
258
+ }
259
+ catch (err) {
260
+ tried.push(shape);
261
+ report.lastError = String(err?.message ?? err).slice(0, 160);
262
+ }
263
+ }
264
+ report.failedShapes = tried;
265
+ return { data: undefined };
266
+ },
267
+ /** The reply path: `ctx.session.context({sessionID})` is the in-process seam that
268
+ * answers for a child's messages. Measured on 2.0.18 it returns an ARRAY of flat
269
+ * `{id, time:{created}, text, type}` items; measured on 2.0.20 it returns items of
270
+ * `{id, role, metadata, content:[…]}` — the shape the published
271
+ * `Session.Message.Info` contract describes, with the kind on `role` instead of the
272
+ * documented `type`. Neither is v1's `[{info:{role},parts:[…]}]`, and both were the
273
+ * reason `tm_join` said it could not read a reply that was sitting right there:
274
+ * `lastAssistantMessage` tolerates an unknown shape by returning NO text, so the call
275
+ * succeeded and the body was silently dropped. Both shapes are therefore NORMALISED
276
+ * here, at the seam that knows them, so the collect path stays single-shaped — and
277
+ * every answer carries WHICH seam it came from plus the SHAPE it saw, because a reply
278
+ * that credits "session.messages" (a v1 endpoint this host does not have) is a claim
279
+ * about the host nobody measured, and a missing body with no shape on it is the same
280
+ * claim in the other direction. */
281
+ messages: async (opts) => {
282
+ const id = idOf(opts);
283
+ if (!id)
284
+ return { data: undefined, via: SEAM, shape: "no-id" };
285
+ if (typeof domain?.context !== "function") {
286
+ // The seam is ABSENT, which is a different fact from "it answered with nothing".
287
+ report.contextError = domain ? "ctx.session has no context method" : "ctx has no session domain";
288
+ return { data: undefined, via: SEAM, shape: domain ? "no-context-method" : "no-session-domain" };
289
+ }
290
+ report.contextTried++;
291
+ try {
292
+ const raw = await call("context", { sessionID: id });
293
+ const rec = unwrap(raw);
294
+ if (!rec)
295
+ return { data: undefined, via: SEAM, shape: `seam-answered-${raw === null ? "null" : typeof raw}` };
296
+ report.contextOk++;
297
+ report.contextKeys = Array.isArray(rec) ? ["array"] : Object.keys(rec).slice(0, 24);
298
+ const list = Array.isArray(rec) ? rec : (rec.messages ?? rec.data ?? rec);
299
+ const seen = contextShapeEvidence(list);
300
+ report.contextShape = seen;
301
+ return { data: normaliseContextMessages(list), via: SEAM, shape: seen };
302
+ }
303
+ catch (err) {
304
+ report.contextError = String(err?.message ?? err).slice(0, 160);
305
+ return { data: undefined, via: SEAM, shape: "context-threw" };
306
+ }
307
+ },
308
+ /** #33 — the STOP path. `tm_join { cancel: true }` was written against v1's
309
+ * `client.session.abort`, and this bridge never wrapped it, so on 2.x every
310
+ * background child was un-stoppable by the lead (the host gives no dialog and
311
+ * no card for a child the plugin observed rather than created).
312
+ *
313
+ * What the host DOES give a plugin is `ctx.session.interrupt`, and its contract
314
+ * is quoted from the v2 API page rather than inferred:
315
+ *
316
+ * POST /api/session/{sessionID}/interrupt
317
+ * "Returns interrupted=true when an active execution was interrupted and
318
+ * false for the idle no-op."
319
+ *
320
+ * That one sentence is why this seam must not collapse into a boolean: `false`
321
+ * is a real answer meaning "nothing was running", not "the stop failed", and a
322
+ * reply that called it 已停止 would be goal #6's overstated claim. Three
323
+ * outcomes therefore survive to the caller, plus the two failure cases (no
324
+ * seam, host threw):
325
+ * stopped — `interrupted === true`, the host stopped an active execution
326
+ * idle — `interrupted === false`, documented no-op
327
+ * unknown — the call answered but carried no `interrupted` boolean
328
+ * no-seam — this host's ctx has no `interrupt`
329
+ * threw — the host refused; its own message rides back
330
+ *
331
+ * The shape is `session.interrupt({sessionID})` — the same flat object `get` and
332
+ * `context` take (the rule AGENTS.md records for every `te`-wrapped method), and
333
+ * the v1 `{path:{id}}` spellings are NOT retried here because a wrong key on THIS
334
+ * method is not a decode failure but an interrupt of the wrong session.
335
+ *
336
+ * `resume` is deliberately never sent: `resume=true` continues pending steering
337
+ * input after the interrupt, which is the opposite of what a caller who asked to
338
+ * cancel a runaway child wants.
339
+ *
340
+ * Privacy: the key NAMES the host returned are recorded; the value text is not
341
+ * (R6 binds a diagnostic). */
342
+ interrupt: async (opts) => {
343
+ const id = idOf(opts);
344
+ report.interruptTried++;
345
+ if (!id || typeof domain?.interrupt !== "function")
346
+ return { data: { outcome: "no-seam" } };
347
+ // Property access on the domain, never a captured reference (see `call`).
348
+ const fn = domain.interrupt;
349
+ try {
350
+ const raw = await fn.call(domain, { sessionID: id });
351
+ const rec = unwrap(raw);
352
+ report.interruptKeys = rec ? Object.keys(rec).slice(0, 16) : ["(non-object)"];
353
+ // `interrupted` can ride the returned object or one of the envelopes `unwrap`
354
+ // recognises (`{data}` / `{result}` / `{session}`) — reading only the outer one
355
+ // turns a real stop into `unknown`, and `unknown` reads as "we could not tell".
356
+ const carriers = [rec, raw?.data, raw?.result];
357
+ let flag;
358
+ for (const cand of carriers) {
359
+ const v = cand?.interrupted;
360
+ if (typeof v === "boolean") {
361
+ flag = v;
362
+ break;
363
+ }
364
+ }
365
+ if (flag === true)
366
+ report.interruptConfirmed++;
367
+ else if (flag === false)
368
+ report.interruptRefused++;
369
+ else
370
+ report.interruptUnknown++;
371
+ const note = carriers
372
+ .map((c) => c?.message)
373
+ .find((m) => typeof m === "string");
374
+ return {
375
+ data: {
376
+ outcome: flag === true ? "stopped" : flag === false ? "idle" : "unknown",
377
+ ...(note ? { message: note } : {}),
378
+ },
379
+ };
380
+ }
381
+ catch (err) {
382
+ report.interruptError = String(err?.message ?? err).slice(0, 160);
383
+ return { data: { outcome: "threw", message: report.interruptError } };
384
+ }
385
+ },
386
+ },
387
+ };
388
+ return { client, report };
389
+ }
390
+ //# sourceMappingURL=v2-session-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-session-client.js","sourceRoot":"","sources":["../../src/host/v2-session-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The v2 session-request layer (goal #4 and #6 of the product).
3
+ *
4
+ * Three things that v1 could only approximate, because 1.18.x gave a plugin one
5
+ * mutable slot before execution and no way to touch an assembled request:
6
+ *
7
+ * 1. the tool surface. v1's whitelist was enforced by permission DENY, which
8
+ * stops a call but leaves the tool's description and schema in EVERY request
9
+ * — the model pays ~9.5K tokens for thirteen governed tools plus the native
10
+ * catalog it is forbidden to use. `session.hook("context")` can `delete
11
+ * event.tools.<name>`, so the whitelist finally decides what the model sees.
12
+ * 2. `temperature`. It is a documented legacy agent field on v2 (and the
13
+ * runner "preserves these values but does not yet send them"), so the
14
+ * all-agents-0.2 invariant has to be set on the outgoing request instead.
15
+ * 3. the blackboard root. v1 appended the resolved path to the team prompt at
16
+ * config time; a v2 agent is a config FILE, which cannot carry a
17
+ * per-workspace path, so it goes on the request.
18
+ *
19
+ * Everything here is additive and reversible: each hook returns a disposable
20
+ * registration, and nothing is claimed that the host did not hand us.
21
+ */
22
+ import type { V2Registration, V2Context } from "./v2-types.js";
23
+ /** Sentinel for "this role may not browse at all" — it removes the host's whole
24
+ * browser catalog (45 `browser_*` tools on 2.0.16), not just our own door.
25
+ * Leaving them in would hand back, at the request layer, exactly the surface the
26
+ * whitelist exists to withhold. */
27
+ export declare const BROWSER_CATALOG = "browser_*";
28
+ /**
29
+ * The tools one agent must never be offered. Only a literal `deny` removes:
30
+ * the `{ "*": "ask" }` object form means "callable, gated", and deleting such a
31
+ * tool would silently drop a capability the matrix grants with a dialog.
32
+ *
33
+ * `read`/`grep`/`glob` are exempted by name (`V2_LADDER_ACTIONS`), which is the
34
+ * other half of the `tm_read`/`tm_grep`/`tm_bash` retirement: v1 denied the
35
+ * native file tools because the governed aliases existed, and on v2 those
36
+ * aliases are not registered, so honouring the deny here would leave a role with
37
+ * no way to open a file at all. Nothing is lost by letting them ride — the path
38
+ * scope P2 enforced in code is the host's own `external_directory` action, which
39
+ * was observed live answering `effect:"ask"` with a real `permission.asked`
40
+ * behind it, i.e. a dialog instead of a hard throw.
41
+ */
42
+ export declare function toolsToRemove(permission: Record<string, unknown> | undefined | null): string[];
43
+ /** Built once per agent id so the hook body stays a set lookup on a hot path. */
44
+ export declare function removalPlan(agents: Record<string, {
45
+ permission?: Record<string, unknown>;
46
+ }>): Map<string, Set<string>>;
47
+ export interface SessionLayerInput {
48
+ /** 0 disables the temperature write entirely (the host's model default wins). */
49
+ temperature: number | false;
50
+ /** The resolved blackboard addendum, or "" when there is nothing to say. */
51
+ note: string;
52
+ /** Which agent ids receive the note — v1 gave it to the lead only. */
53
+ noteAgents: string[];
54
+ plan: Map<string, Set<string>>;
55
+ /** Team-scope isolation (#22). `session.context` fires for EVERY agent on the
56
+ * host, so temperature, the board note and the compaction survival list are
57
+ * writes to somebody else's request unless the agent is one of ours. The tool
58
+ * trim is already keyed by agent (a foreign role is not in the plan, so nothing
59
+ * is deleted); this closes the other three. */
60
+ scope?: import("./v2-scope.js").TeamScope;
61
+ }
62
+ export interface SessionLayerReport {
63
+ temperature: number | false;
64
+ removed: Record<string, number>;
65
+ notePushed: boolean;
66
+ compactionLines: number;
67
+ /** Did a `tm_*` name ever appear in an assembled request's own tool surface?
68
+ * This is the only evidence that direct delivery happened: `options.codemode:false`
69
+ * is what WE send, and a live 2.0.16 session proved the host still put every
70
+ * `tm_*` in the Code Mode catalog ("They cannot be called directly…") while the
71
+ * model's own callable list was nine native tools. Reporting the sent flag as if it
72
+ * were the outcome is the overstated claim this product exists to refuse. */
73
+ tmInRequestSurface: boolean;
74
+ }
75
+ /**
76
+ * Register the request-layer hooks. Returns the registrations (so the caller
77
+ * can dispose them) and a live report object — the counts are read off what the
78
+ * hooks actually did, not off what the matrix intends, because "we trimmed the
79
+ * surface" is a claim the user can only check against the request.
80
+ */
81
+ export declare function applyV2SessionLayer(ctx: V2Context, input: SessionLayerInput): Promise<{
82
+ registrations: V2Registration[];
83
+ report: SessionLayerReport;
84
+ }>;
85
+ //# sourceMappingURL=v2-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-session.d.ts","sourceRoot":"","sources":["../../src/host/v2-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAoB,SAAS,EAAE,MAAM,eAAe,CAAA;AAUhF;;;oCAGoC;AACpC,eAAO,MAAM,eAAe,cAAc,CAAA;AAI1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAyB9F;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAC/D,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAI1B;AAKD,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,WAAW,EAAE,MAAM,GAAG,KAAK,CAAA;IAC3B,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAC9B;;;;oDAIgD;IAChD,KAAK,CAAC,EAAE,OAAO,eAAe,EAAE,SAAS,CAAA;CAC1C;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,GAAG,KAAK,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,UAAU,EAAE,OAAO,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB;;;;;kFAK8E;IAC9E,kBAAkB,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC;IAAE,aAAa,EAAE,cAAc,EAAE,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAgF1E"}