@te-river/opencode-team-mode 1.6.0 → 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 +80 -15
- package/README.zh-CN.md +67 -18
- 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/index.d.ts +23 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -366
- 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 -426
- 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 +30 -10
- 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 +7 -6
- package/dist/prompts/specialists.js.map +1 -1
- package/dist/task-offload.d.ts +16 -0
- package/dist/task-offload.d.ts.map +1 -1
- package/dist/task-offload.js +51 -0
- package/dist/task-offload.js.map +1 -1
- package/dist/tm/browser.d.ts.map +1 -1
- package/dist/tm/browser.js +41 -10
- package/dist/tm/browser.js.map +1 -1
- package/dist/tm/dispatch.d.ts +47 -0
- package/dist/tm/dispatch.d.ts.map +1 -1
- package/dist/tm/dispatch.js +230 -31
- 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/index.d.ts +40 -1
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +40 -11
- 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 +1 -3
- package/dist/tm/perm-ask.d.ts.map +1 -1
- package/dist/tm/perm-ask.js +10 -1
- package/dist/tm/perm-ask.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/search.d.ts.map +1 -1
- package/dist/tm/search.js +40 -10
- 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 +10 -0
- package/dist/tm/stats.d.ts.map +1 -1
- package/dist/tm/stats.js +160 -0
- package/dist/tm/stats.js.map +1 -1
- package/dist/tm/webfetch.d.ts +4 -0
- package/dist/tm/webfetch.d.ts.map +1 -1
- package/dist/tm/webfetch.js +75 -8
- package/dist/tm/webfetch.js.map +1 -1
- package/docs/installation-v2.md +436 -0
- package/docs/installation.md +12 -0
- 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 +64 -61
- package/scripts/gen-v2-config.mjs +304 -0
- package/scripts/lib/config-surgery.cjs +239 -0
- package/scripts/lib/fake-ctx.mjs +146 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { parseHostEnvelope } from "../task-offload.js";
|
|
4
|
+
const URLish = (s) => {
|
|
5
|
+
if (typeof s !== "string")
|
|
6
|
+
return false;
|
|
7
|
+
return /^https?:\/\//i.test(s.trim()) || /^\[[0-9a-f:.]+\]$/i.test(s.trim());
|
|
8
|
+
};
|
|
9
|
+
const keysOf = (v) => {
|
|
10
|
+
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
11
|
+
return [];
|
|
12
|
+
return Object.keys(v).sort();
|
|
13
|
+
};
|
|
14
|
+
/** Any ctx domain whose `hook` is absent is reported rather than crashing boot. */
|
|
15
|
+
function hookFn(ctx, domain) {
|
|
16
|
+
const d = ctx?.[domain];
|
|
17
|
+
const h = d?.hook;
|
|
18
|
+
return typeof h === "function" ? h : null;
|
|
19
|
+
}
|
|
20
|
+
export async function applyV2Probe(ctx, opts = {}) {
|
|
21
|
+
const env = opts.env ?? process.env;
|
|
22
|
+
const file = typeof env.TM_V2_PROBE === "string" && env.TM_V2_PROBE.trim() ? env.TM_V2_PROBE.trim() : null;
|
|
23
|
+
const maxLines = Number.isFinite(Number(opts.maxLines)) && Number(opts.maxLines) > 0 ? Number(opts.maxLines) : 400;
|
|
24
|
+
const flushMs = Number.isFinite(Number(opts.flushMs)) && Number(opts.flushMs) >= 0 ? Number(opts.flushMs) : 20_000;
|
|
25
|
+
const report = {
|
|
26
|
+
agentsSeen: [],
|
|
27
|
+
toolNames: [],
|
|
28
|
+
executed: [],
|
|
29
|
+
executedAfter: [],
|
|
30
|
+
actions: [],
|
|
31
|
+
urlResources: 0,
|
|
32
|
+
evaluations: 0,
|
|
33
|
+
messages: 0,
|
|
34
|
+
taskEnvelopes: 0,
|
|
35
|
+
maxEnvelopeChars: 0,
|
|
36
|
+
messageShapes: [],
|
|
37
|
+
envelopeForms: new Set(),
|
|
38
|
+
hooksMissing: [],
|
|
39
|
+
ctxDomains: [],
|
|
40
|
+
probeTarget: file ? path.basename(file) : "",
|
|
41
|
+
lines: 0,
|
|
42
|
+
};
|
|
43
|
+
report.ctxDomains = Object.keys((ctx ?? {})).sort();
|
|
44
|
+
const seenToolNames = new Set();
|
|
45
|
+
const seenExecuted = new Set();
|
|
46
|
+
const seenExecutedAfter = new Set();
|
|
47
|
+
const seenActions = new Set();
|
|
48
|
+
const seenAgents = new Set();
|
|
49
|
+
const seenBeforeShapes = new Set();
|
|
50
|
+
const messageShapes = [];
|
|
51
|
+
const envelopeForms = report.envelopeForms;
|
|
52
|
+
const write = (rec) => {
|
|
53
|
+
if (!file || report.lines >= maxLines)
|
|
54
|
+
return;
|
|
55
|
+
report.lines += 1;
|
|
56
|
+
try {
|
|
57
|
+
fs.appendFileSync(file, `${JSON.stringify({ at: new Date().toISOString(), ...rec })}\n`);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
/* a probe that cannot write stays silent; it must never break a tool call */
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
let lastFlush = 0;
|
|
64
|
+
let lastSummary = "";
|
|
65
|
+
// Declared BEFORE any hook is registered: the host can fire a context hook while
|
|
66
|
+
// this function is still awaiting its own registrations, and a callback landing
|
|
67
|
+
// in the temporal dead zone would throw inside somebody's model request.
|
|
68
|
+
const flush = (force = false) => {
|
|
69
|
+
if (!opts.onSummary)
|
|
70
|
+
return;
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
if (!force && now - lastFlush < flushMs)
|
|
73
|
+
return;
|
|
74
|
+
const summary = probeSummary(report);
|
|
75
|
+
const flat = JSON.stringify(summary);
|
|
76
|
+
// An idle session re-runs the context hook on every request; writing an
|
|
77
|
+
// identical line each time would be noise that buries the ones that differ.
|
|
78
|
+
if (!force && flat === lastSummary)
|
|
79
|
+
return;
|
|
80
|
+
lastFlush = now;
|
|
81
|
+
lastSummary = flat;
|
|
82
|
+
try {
|
|
83
|
+
opts.onSummary(summary);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
/* observability is an extra, never a reason to fail a request */
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const pending = [];
|
|
90
|
+
const registrations = [];
|
|
91
|
+
const arm = (domain, point, cb) => {
|
|
92
|
+
const hook = hookFn(ctx, domain);
|
|
93
|
+
if (!hook) {
|
|
94
|
+
report.hooksMissing.push(`${domain}.${point}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// The host's convention is `ctx.session.hook("context", …)` — the POINT name,
|
|
98
|
+
// not "session.context". Passing the dotted form would register a hook under a
|
|
99
|
+
// name nothing fires, and the probe would report an empty surface as if the host
|
|
100
|
+
// had none. The label keeps the domain so a missing seam reads unambiguously.
|
|
101
|
+
// The body is wrapped so a defect HERE can never surface as a failed tool call
|
|
102
|
+
// or a broken model request: an observer that can break the thing it observes is
|
|
103
|
+
// not an observer. (This was not theoretical — a callback referencing a `const`
|
|
104
|
+
// declared further down the module hit its temporal dead zone while the host was
|
|
105
|
+
// mid-hook, which is exactly how the shape recorder reported nothing.)
|
|
106
|
+
const guarded = (event) => {
|
|
107
|
+
try {
|
|
108
|
+
cb(event);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
const tag = `${domain}.${point}`;
|
|
112
|
+
if (!report.hooksMissing.includes(`${tag}:callback-threw`))
|
|
113
|
+
report.hooksMissing.push(`${tag}:callback-threw`);
|
|
114
|
+
void err;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
try {
|
|
118
|
+
pending.push(Promise.resolve(hook(point, guarded)));
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
report.hooksMissing.push(`${domain}.${point}:${String(err?.message ?? err).slice(0, 60)}`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
arm("session", "context", (raw) => {
|
|
125
|
+
const event = raw;
|
|
126
|
+
const names = Object.keys(event?.tools ?? {});
|
|
127
|
+
const msgs = Array.isArray(event.messages) ? event.messages : [];
|
|
128
|
+
report.messages = Math.max(report.messages, msgs.length);
|
|
129
|
+
// The KEY NAMES of what a message actually is — recorded because guessing the
|
|
130
|
+
// shape is what made the v1 envelope matcher quietly dead: the probe reported
|
|
131
|
+
// "0 envelopes" and the honest reading was "I do not know where this lands",
|
|
132
|
+
// not "nothing lands". Names only, never content.
|
|
133
|
+
if (msgs.length && !messageShapes.length) {
|
|
134
|
+
for (const m of msgs.slice(0, 3)) {
|
|
135
|
+
const keys = keysOf(m);
|
|
136
|
+
const nested = {};
|
|
137
|
+
for (const k of keys) {
|
|
138
|
+
const v = m[k];
|
|
139
|
+
if (v && typeof v === "object")
|
|
140
|
+
nested[k] = Array.isArray(v) ? [`array(${v.length})`] : keysOf(v).slice(0, 8);
|
|
141
|
+
}
|
|
142
|
+
messageShapes.push({ keys, nested });
|
|
143
|
+
}
|
|
144
|
+
report.messageShapes = messageShapes;
|
|
145
|
+
write({ where: "message-shape", shapes: messageShapes });
|
|
146
|
+
}
|
|
147
|
+
// Shape only: a boolean "this looks like the host's envelope" and a character
|
|
148
|
+
// count. Nothing of the body is kept, hashed or written.
|
|
149
|
+
for (const m of msgs) {
|
|
150
|
+
// Read the TEXT of each part. JSON.stringify was wrong twice over: escaping
|
|
151
|
+
// the quotes means an envelope inside a part never matches its own parser (so
|
|
152
|
+
// this counter reported 0 on a host that was emitting them), and it would have
|
|
153
|
+
// serialized fields nobody should have in a probe file.
|
|
154
|
+
const texts = [];
|
|
155
|
+
if (typeof m === "string")
|
|
156
|
+
texts.push(m);
|
|
157
|
+
else {
|
|
158
|
+
const parts = m?.parts;
|
|
159
|
+
if (Array.isArray(parts)) {
|
|
160
|
+
for (const pt of parts) {
|
|
161
|
+
if (typeof pt?.text === "string")
|
|
162
|
+
texts.push(pt.text);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (typeof m?.text === "string")
|
|
166
|
+
texts.push(m.text);
|
|
167
|
+
}
|
|
168
|
+
// Asked of the same parser the offload uses — a probe that greps for the v1
|
|
169
|
+
// string while the host emits another reports "0 envelopes" forever, and a
|
|
170
|
+
// zero like that is indistinguishable from "nothing was big enough".
|
|
171
|
+
for (const text of texts) {
|
|
172
|
+
const env = parseHostEnvelope(text);
|
|
173
|
+
if (!env)
|
|
174
|
+
continue;
|
|
175
|
+
report.taskEnvelopes += 1;
|
|
176
|
+
report.maxEnvelopeChars = Math.max(report.maxEnvelopeChars, text.length);
|
|
177
|
+
report.envelopeForms.add(env.form);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const n of names)
|
|
181
|
+
seenToolNames.add(n);
|
|
182
|
+
const agent = String(event?.agent ?? "?");
|
|
183
|
+
if (!seenAgents.has(agent)) {
|
|
184
|
+
seenAgents.add(agent);
|
|
185
|
+
report.agentsSeen = [...seenAgents].sort();
|
|
186
|
+
write({ where: "context", agent, toolCount: names.length, tools: names.slice().sort() });
|
|
187
|
+
}
|
|
188
|
+
report.toolNames = [...seenToolNames].sort();
|
|
189
|
+
flush(false);
|
|
190
|
+
});
|
|
191
|
+
arm("tool", "execute.before", (raw) => {
|
|
192
|
+
const event = raw;
|
|
193
|
+
const id = String(event?.tool ?? "?");
|
|
194
|
+
if (!seenExecuted.has(id)) {
|
|
195
|
+
seenExecuted.add(id);
|
|
196
|
+
report.executed = [...seenExecuted].sort();
|
|
197
|
+
write({ where: "execute.before", tool: id, inputKeys: keysOf(event?.input) });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
// A tool already on record still tells us something new when its argument
|
|
201
|
+
// table differs — the native browser namespace is the open question here, and
|
|
202
|
+
// one line per distinct argument shape is what answers it.
|
|
203
|
+
const shape = keysOf(event?.input).join(",");
|
|
204
|
+
if (id.includes("browser") && !seenBeforeShapes.has(`${id}(${shape})`)) {
|
|
205
|
+
seenBeforeShapes.add(`${id}(${shape})`);
|
|
206
|
+
write({ where: "execute.before.input", tool: id, inputKeys: keysOf(event?.input) });
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
arm("tool", "execute.after", (raw) => {
|
|
210
|
+
const event = raw;
|
|
211
|
+
const id = String(event?.tool ?? "?");
|
|
212
|
+
if (!seenExecutedAfter.has(id)) {
|
|
213
|
+
seenExecutedAfter.add(id);
|
|
214
|
+
report.executedAfter = [...seenExecutedAfter].sort();
|
|
215
|
+
write({ where: "execute.after", tool: id, resultKeys: keysOf(event?.result) });
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
arm("permission", "evaluate", (raw) => {
|
|
219
|
+
const event = raw;
|
|
220
|
+
report.evaluations += 1;
|
|
221
|
+
const action = String(event?.action ?? "?");
|
|
222
|
+
const resources = Array.isArray(event?.resources) ? event.resources : [];
|
|
223
|
+
const hasUrl = resources.some(URLish);
|
|
224
|
+
if (hasUrl)
|
|
225
|
+
report.urlResources += 1;
|
|
226
|
+
if (seenActions.has(action))
|
|
227
|
+
return;
|
|
228
|
+
seenActions.add(action);
|
|
229
|
+
report.actions = [...seenActions].sort();
|
|
230
|
+
write({ where: "permission.evaluate", action, resourceCount: resources.length, hasUrl });
|
|
231
|
+
});
|
|
232
|
+
// A registration that rejects is a host fact worth recording — silently dropping
|
|
233
|
+
// it would leave the probe reporting "no browser tools" when the real reason is
|
|
234
|
+
// that the hook never attached.
|
|
235
|
+
const settled = await Promise.allSettled(pending);
|
|
236
|
+
settled.forEach((r, i) => {
|
|
237
|
+
if (r.status === "fulfilled" && r.value && typeof r.value.dispose === "function")
|
|
238
|
+
registrations.push(r.value);
|
|
239
|
+
else if (r.status === "rejected")
|
|
240
|
+
report.hooksMissing.push(`#${i}:${String(r.reason?.message ?? r.reason).slice(0, 60)}`);
|
|
241
|
+
});
|
|
242
|
+
flush(true);
|
|
243
|
+
return { enabled: Boolean(file), report, registrations, flush };
|
|
244
|
+
}
|
|
245
|
+
/** Compact form for the trajectory — names are safe, values never are. */
|
|
246
|
+
export function probeSummary(report) {
|
|
247
|
+
const browserTools = report.toolNames.filter((n) => n.toLowerCase().includes("browser"));
|
|
248
|
+
return {
|
|
249
|
+
probe_agents: report.agentsSeen.join(" "),
|
|
250
|
+
probe_tool_count: report.toolNames.length,
|
|
251
|
+
probe_browser_tools: browserTools.join(" "),
|
|
252
|
+
probe_executed: report.executed.join(" "),
|
|
253
|
+
probe_executed_after: report.executedAfter.join(" "),
|
|
254
|
+
probe_actions: report.actions.join(" "),
|
|
255
|
+
probe_evaluations: report.evaluations,
|
|
256
|
+
probe_messages: report.messages,
|
|
257
|
+
probe_task_envelopes: report.taskEnvelopes,
|
|
258
|
+
probe_max_envelope_chars: report.maxEnvelopeChars,
|
|
259
|
+
probe_message_shapes: JSON.stringify(report.messageShapes).slice(0, 500),
|
|
260
|
+
probe_envelope_forms: [...report.envelopeForms].join(" "),
|
|
261
|
+
probe_url_resources: report.urlResources,
|
|
262
|
+
probe_hooks_missing: report.hooksMissing.join(" "),
|
|
263
|
+
probe_ctx_domains: report.ctxDomains.join(" "),
|
|
264
|
+
probe_lines: report.lines,
|
|
265
|
+
probe_target: report.probeTarget,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=v2-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-probe.js","sourceRoot":"","sources":["../../src/host/v2-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team-scope isolation for the v2 personality (#22, user requirement 2026-09-25).
|
|
3
|
+
*
|
|
4
|
+
* "Everything the plugin changes must stay inside Team mode; the other modes
|
|
5
|
+
* (build, plan, anything the user installed) must look exactly like a freshly
|
|
6
|
+
* installed OpenCode." Every v2 hook we register is GLOBAL — `execute.after`,
|
|
7
|
+
* `permission.evaluate`, `session.context` fire for every session on the host, not
|
|
8
|
+
* only for ours. Without one shared answer to "is this ours?", the plugin would
|
|
9
|
+
* · delete tools from a build agent's request,
|
|
10
|
+
* · set `temperature` on somebody else's model call,
|
|
11
|
+
* · offload a stranger's tool result into OUR run store,
|
|
12
|
+
* · force `background: true` on a dispatch the user made on purpose,
|
|
13
|
+
* · and tighten a permission the user's own config already decided.
|
|
14
|
+
*
|
|
15
|
+
* The answer is deliberately three-valued, and the third value is the one that
|
|
16
|
+
* needs explaining. `unknown` means the host did not tell us which agent this is
|
|
17
|
+
* (the field is optional in the shape we were handed). We then treat the call as
|
|
18
|
+
* NOT ours — requirement first, coverage second — but we COUNT it, because
|
|
19
|
+
* "governance is live" and "governance silently stopped applying because a field
|
|
20
|
+
* went missing in a host upgrade" are two different facts, and the second one has
|
|
21
|
+
* to be readable from `tm_stats` rather than inferred from a bad feeling.
|
|
22
|
+
*
|
|
23
|
+
* A session can also become known from the inside: every call to one of OUR tools
|
|
24
|
+
* carries a session id and an agent in its own context, so `learn()` records that
|
|
25
|
+
* pair and a later `execute.after` for the same session resolves even if the host
|
|
26
|
+
* left `agent` off that event.
|
|
27
|
+
*/
|
|
28
|
+
export type ScopeVerdict = "ours" | "foreign" | "unknown";
|
|
29
|
+
export interface V2ScopeReport {
|
|
30
|
+
/** calls that belong to a Team role — the ones we are allowed to touch */
|
|
31
|
+
ours: number;
|
|
32
|
+
/** calls we identified as somebody else's and left completely alone */
|
|
33
|
+
foreign: number;
|
|
34
|
+
/** calls where the host gave us no agent at all — skipped, and the number that
|
|
35
|
+
* tells whether the governance layers are actually live */
|
|
36
|
+
unknown: number;
|
|
37
|
+
}
|
|
38
|
+
export interface TeamScope {
|
|
39
|
+
readonly names: ReadonlySet<string>;
|
|
40
|
+
isOurs(agent: unknown): boolean;
|
|
41
|
+
decide(event: {
|
|
42
|
+
agent?: unknown;
|
|
43
|
+
sessionID?: unknown;
|
|
44
|
+
} | null | undefined): ScopeVerdict;
|
|
45
|
+
learn(agent: unknown, sessionID: unknown): void;
|
|
46
|
+
readonly report: V2ScopeReport;
|
|
47
|
+
/** counted at each call site, so a layer that never fires cannot look healthy */
|
|
48
|
+
count(verdict: ScopeVerdict): ScopeVerdict;
|
|
49
|
+
}
|
|
50
|
+
export declare function createTeamScope(names: Iterable<string>): TeamScope;
|
|
51
|
+
//# sourceMappingURL=v2-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-scope.d.ts","sourceRoot":"","sources":["../../src/host/v2-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;AAEzD,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAA;IACf;gEAC4D;IAC5D,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACnC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAA;IAC/B,MAAM,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,CAAA;IACxF,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAAA;IAC/C,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,iFAAiF;IACjF,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAAA;CAC3C;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,SAAS,CAyBlE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team-scope isolation for the v2 personality (#22, user requirement 2026-09-25).
|
|
3
|
+
*
|
|
4
|
+
* "Everything the plugin changes must stay inside Team mode; the other modes
|
|
5
|
+
* (build, plan, anything the user installed) must look exactly like a freshly
|
|
6
|
+
* installed OpenCode." Every v2 hook we register is GLOBAL — `execute.after`,
|
|
7
|
+
* `permission.evaluate`, `session.context` fire for every session on the host, not
|
|
8
|
+
* only for ours. Without one shared answer to "is this ours?", the plugin would
|
|
9
|
+
* · delete tools from a build agent's request,
|
|
10
|
+
* · set `temperature` on somebody else's model call,
|
|
11
|
+
* · offload a stranger's tool result into OUR run store,
|
|
12
|
+
* · force `background: true` on a dispatch the user made on purpose,
|
|
13
|
+
* · and tighten a permission the user's own config already decided.
|
|
14
|
+
*
|
|
15
|
+
* The answer is deliberately three-valued, and the third value is the one that
|
|
16
|
+
* needs explaining. `unknown` means the host did not tell us which agent this is
|
|
17
|
+
* (the field is optional in the shape we were handed). We then treat the call as
|
|
18
|
+
* NOT ours — requirement first, coverage second — but we COUNT it, because
|
|
19
|
+
* "governance is live" and "governance silently stopped applying because a field
|
|
20
|
+
* went missing in a host upgrade" are two different facts, and the second one has
|
|
21
|
+
* to be readable from `tm_stats` rather than inferred from a bad feeling.
|
|
22
|
+
*
|
|
23
|
+
* A session can also become known from the inside: every call to one of OUR tools
|
|
24
|
+
* carries a session id and an agent in its own context, so `learn()` records that
|
|
25
|
+
* pair and a later `execute.after` for the same session resolves even if the host
|
|
26
|
+
* left `agent` off that event.
|
|
27
|
+
*/
|
|
28
|
+
export function createTeamScope(names) {
|
|
29
|
+
const set = new Set([...names].map(String));
|
|
30
|
+
const bySession = new Map();
|
|
31
|
+
const report = { ours: 0, foreign: 0, unknown: 0 };
|
|
32
|
+
const scope = {
|
|
33
|
+
names: set,
|
|
34
|
+
isOurs: (agent) => typeof agent === "string" && set.has(agent),
|
|
35
|
+
learn(agent, sessionID) {
|
|
36
|
+
if (typeof sessionID !== "string" || !sessionID)
|
|
37
|
+
return;
|
|
38
|
+
if (typeof agent === "string" && set.has(agent))
|
|
39
|
+
bySession.set(sessionID, agent);
|
|
40
|
+
},
|
|
41
|
+
decide(event) {
|
|
42
|
+
const agent = event?.agent;
|
|
43
|
+
if (typeof agent === "string" && agent)
|
|
44
|
+
return set.has(agent) ? "ours" : "foreign";
|
|
45
|
+
const sid = event?.sessionID;
|
|
46
|
+
if (typeof sid === "string" && bySession.has(sid))
|
|
47
|
+
return "ours";
|
|
48
|
+
return "unknown";
|
|
49
|
+
},
|
|
50
|
+
count(verdict) {
|
|
51
|
+
report[verdict]++;
|
|
52
|
+
return verdict;
|
|
53
|
+
},
|
|
54
|
+
report,
|
|
55
|
+
};
|
|
56
|
+
return scope;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=v2-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-scope.js","sourceRoot":"","sources":["../../src/host/v2-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAwBH,MAAM,UAAU,eAAe,CAAC,KAAuB;IACrD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC3C,MAAM,MAAM,GAAkB,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;IACjE,MAAM,KAAK,GAAc;QACvB,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;QAC9D,KAAK,CAAC,KAAK,EAAE,SAAS;YACpB,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,SAAS;gBAAE,OAAM;YACvD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QAClF,CAAC;QACD,MAAM,CAAC,KAAK;YACV,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,CAAA;YAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK;gBAAE,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;YAClF,MAAM,GAAG,GAAG,KAAK,EAAE,SAAS,CAAA;YAC5B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,MAAM,CAAA;YAChE,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,KAAK,CAAC,OAAO;YACX,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;YACjB,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,MAAM;KACP,CAAA;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
export interface V2SessionReaderReport {
|
|
43
|
+
/** calls made through this adapter */
|
|
44
|
+
attempted: number;
|
|
45
|
+
/** calls that produced an object with a parent id */
|
|
46
|
+
resolved: number;
|
|
47
|
+
/** which argument shape the host answered — `sessionID` is the measured one */
|
|
48
|
+
usedShape?: string;
|
|
49
|
+
/** last error text, unwrapped from the host's own error envelope */
|
|
50
|
+
lastError?: string;
|
|
51
|
+
/** shapes tried and failed on the last call */
|
|
52
|
+
failedShapes: string[];
|
|
53
|
+
/** `ctx.session.context` was reached at all */
|
|
54
|
+
contextTried: number;
|
|
55
|
+
contextOk: number;
|
|
56
|
+
contextError?: string;
|
|
57
|
+
/** the KEY NAMES the context call returned (names only, never values) */
|
|
58
|
+
contextKeys: string[];
|
|
59
|
+
}
|
|
60
|
+
export interface V2SessionReader {
|
|
61
|
+
/** a `{session:{get,messages}}` object safe to hand to code written for the v1 client */
|
|
62
|
+
client: unknown;
|
|
63
|
+
report: V2SessionReaderReport;
|
|
64
|
+
}
|
|
65
|
+
/** Turn the host's flat context items into the `{info,parts}` shape the collect path
|
|
66
|
+
* already understands. Only the ROLE is inferred here, and only from the item's own `type`
|
|
67
|
+
* field (measured values: "user" for the brief, something else for the answer); a
|
|
68
|
+
* `time.completed` is NEVER invented, because that field is the settle verdict and a
|
|
69
|
+
* fabricated one would let tm_join claim a child finished at a time nobody observed.
|
|
70
|
+
* Anything already shaped like v1 passes through untouched, so a host that changes back
|
|
71
|
+
* does not need this code to change. */
|
|
72
|
+
export declare function normaliseContextMessages(list: unknown): unknown;
|
|
73
|
+
export declare function createV2SessionReader(ctx: unknown): V2SessionReader;
|
|
74
|
+
//# sourceMappingURL=v2-session-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-session-client.d.ts","sourceRoot":"","sources":["../../src/host/v2-session-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,qBAAqB,CAAA;CAC9B;AA+BD;;;;;;yCAMyC;AACzC,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAgB/D;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAwEnE"}
|
|
@@ -0,0 +1,171 @@
|
|
|
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
|
+
/** Turn the host's flat context items into the `{info,parts}` shape the collect path
|
|
68
|
+
* already understands. Only the ROLE is inferred here, and only from the item's own `type`
|
|
69
|
+
* field (measured values: "user" for the brief, something else for the answer); a
|
|
70
|
+
* `time.completed` is NEVER invented, because that field is the settle verdict and a
|
|
71
|
+
* fabricated one would let tm_join claim a child finished at a time nobody observed.
|
|
72
|
+
* Anything already shaped like v1 passes through untouched, so a host that changes back
|
|
73
|
+
* does not need this code to change. */
|
|
74
|
+
export function normaliseContextMessages(list) {
|
|
75
|
+
if (!Array.isArray(list))
|
|
76
|
+
return list;
|
|
77
|
+
return list.map((item) => {
|
|
78
|
+
if (!item || typeof item !== "object")
|
|
79
|
+
return item;
|
|
80
|
+
const rec = item;
|
|
81
|
+
if (rec.info || Array.isArray(rec.parts) || Array.isArray(rec.content))
|
|
82
|
+
return item;
|
|
83
|
+
const text = rec.text;
|
|
84
|
+
if (typeof text !== "string" || !text.trim())
|
|
85
|
+
return item;
|
|
86
|
+
const type = String(rec.type ?? "");
|
|
87
|
+
const role = /^user$/i.test(type) ? "user" : "assistant";
|
|
88
|
+
const created = rec.time?.created;
|
|
89
|
+
return {
|
|
90
|
+
info: { role, ...(typeof created === "number" ? { time: { created } } : {}) },
|
|
91
|
+
parts: [{ type: "text", text }],
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
export function createV2SessionReader(ctx) {
|
|
96
|
+
const report = {
|
|
97
|
+
attempted: 0, resolved: 0, failedShapes: [], contextTried: 0, contextOk: 0, contextKeys: [],
|
|
98
|
+
};
|
|
99
|
+
const domain = ctx?.session;
|
|
100
|
+
const call = async (method, arg) => {
|
|
101
|
+
const fn = domain?.[method];
|
|
102
|
+
if (typeof fn !== "function")
|
|
103
|
+
return undefined;
|
|
104
|
+
// Property access on the domain, never a captured reference: a detached `get` loses
|
|
105
|
+
// its receiver and the host's client throws (the dispatch.ts §10 rule).
|
|
106
|
+
return await fn.call(domain, arg);
|
|
107
|
+
};
|
|
108
|
+
const client = {
|
|
109
|
+
session: {
|
|
110
|
+
get: async (opts) => {
|
|
111
|
+
const id = idOf(opts);
|
|
112
|
+
report.attempted++;
|
|
113
|
+
if (!id || !id.startsWith("ses"))
|
|
114
|
+
return { data: undefined };
|
|
115
|
+
const tried = [];
|
|
116
|
+
for (const [shape, build] of SHAPES) {
|
|
117
|
+
try {
|
|
118
|
+
const raw = await call("get", build(id));
|
|
119
|
+
const rec = unwrap(raw);
|
|
120
|
+
if (rec) {
|
|
121
|
+
report.resolved++;
|
|
122
|
+
report.usedShape = shape;
|
|
123
|
+
report.failedShapes = [];
|
|
124
|
+
const parent = rec.parentID ?? rec.parent_id;
|
|
125
|
+
return { data: { id, parentID: typeof parent === "string" ? parent : undefined, raw: rec } };
|
|
126
|
+
}
|
|
127
|
+
tried.push(shape);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
tried.push(shape);
|
|
131
|
+
report.lastError = String(err?.message ?? err).slice(0, 160);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
report.failedShapes = tried;
|
|
135
|
+
return { data: undefined };
|
|
136
|
+
},
|
|
137
|
+
/** The reply path: `ctx.session.context({sessionID})` is the in-process seam that
|
|
138
|
+
* answers for a child's messages — measured on 2.0.18, where it returns an ARRAY of
|
|
139
|
+
* `{id, time:{created}, text, type}`. That is NOT v1's `[{info:{role},parts:[…]}]`,
|
|
140
|
+
* and this is the reason `tm_join` kept saying it could not read a reply that was
|
|
141
|
+
* sitting right there: `lastAssistantMessage` tolerates an unknown shape by returning
|
|
142
|
+
* no text, so the call succeeded and the body was silently dropped. The flat shape is
|
|
143
|
+
* therefore NORMALISED here, at the seam that knows it, so the collect path stays
|
|
144
|
+
* single-shaped — and the result says WHICH seam answered, because a reply that
|
|
145
|
+
* credits "session.messages" (a v1 endpoint this host does not have) is a claim about
|
|
146
|
+
* the host that nobody measured. */
|
|
147
|
+
messages: async (opts) => {
|
|
148
|
+
const id = idOf(opts);
|
|
149
|
+
if (!id || typeof domain?.context !== "function")
|
|
150
|
+
return { data: undefined };
|
|
151
|
+
report.contextTried++;
|
|
152
|
+
try {
|
|
153
|
+
const raw = await call("context", { sessionID: id });
|
|
154
|
+
const rec = unwrap(raw);
|
|
155
|
+
if (!rec)
|
|
156
|
+
return { data: undefined };
|
|
157
|
+
report.contextOk++;
|
|
158
|
+
report.contextKeys = Array.isArray(rec) ? ["array"] : Object.keys(rec).slice(0, 24);
|
|
159
|
+
const list = Array.isArray(rec) ? rec : (rec.messages ?? rec.data ?? rec);
|
|
160
|
+
return { data: normaliseContextMessages(list), via: "ctx.session.context" };
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
report.contextError = String(err?.message ?? err).slice(0, 160);
|
|
164
|
+
return { data: undefined };
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
return { client, report };
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=v2-session-client.js.map
|