@volter-ai-dev/supercode-ui 0.1.69 → 0.1.71
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 +37 -1
- package/activity.mjs +5 -1235
- package/chunks/chunk-ATCOWFRV.mjs +105 -0
- package/chunks/chunk-LOP6XOON.mjs +671 -0
- package/chunks/chunk-LQMYNJPU.mjs +120 -0
- package/chunks/chunk-LS6JBXNT.mjs +1237 -0
- package/chunks/chunk-O7Q2PELK.mjs +201 -0
- package/chunks/chunk-OW42DS6P.mjs +842 -0
- package/chunks/chunk-SJ3YTA6Z.mjs +316 -0
- package/chunks/chunk-SSYNT434.mjs +224 -0
- package/chunks/chunk-V3UM7H7W.mjs +328 -0
- package/chunks/chunk-XD2WJYSL.mjs +29 -0
- package/chunks/chunk-ZLYHUYE2.mjs +62 -0
- package/components.d.ts +3 -0
- package/components.mjs +59 -3766
- package/composer.mjs +8 -580
- package/conversation.mjs +16 -1373
- package/embed.mjs +15 -3681
- package/icon.mjs +3 -58
- package/index.d.ts +25 -0
- package/logo.mjs +5 -87
- package/messenger.d.ts +3 -0
- package/messenger.mjs +21 -3677
- package/package.json +3 -2
- package/react/activity.mjs +5 -1235
- package/react/chunks/chunk-2RIHDJT6.mjs +842 -0
- package/react/chunks/chunk-7ES5FSLG.mjs +316 -0
- package/react/chunks/chunk-GV5KV5UY.mjs +105 -0
- package/react/chunks/chunk-GYQOTTZ5.mjs +224 -0
- package/react/chunks/chunk-LS6JBXNT.mjs +1237 -0
- package/react/chunks/chunk-OINC7LV7.mjs +62 -0
- package/react/chunks/chunk-TQHX2DQG.mjs +120 -0
- package/react/chunks/chunk-UKHDCPME.mjs +328 -0
- package/react/chunks/chunk-UKMTRNJN.mjs +671 -0
- package/react/chunks/chunk-ZM5X5LOF.mjs +29 -0
- package/react/chunks/chunk-ZXD7NZXI.mjs +201 -0
- package/react/components.mjs +59 -3766
- package/react/composer.mjs +8 -580
- package/react/conversation.mjs +16 -1373
- package/react/icon.mjs +3 -58
- package/react/index.d.ts +25 -0
- package/react/logo.mjs +5 -87
- package/react/messenger.d.ts +3 -0
- package/react/messenger.mjs +21 -3677
- package/react/sessions.mjs +9 -519
- package/react/settings.mjs +9 -425
- package/react/subagents.mjs +8 -1546
- package/sessions.mjs +9 -519
- package/settings.mjs +9 -425
- package/styles.css +12 -0
- package/subagents.mjs +8 -1546
|
@@ -0,0 +1,1237 @@
|
|
|
1
|
+
// core.mjs
|
|
2
|
+
var HARNESS_NAMES = Object.freeze({
|
|
3
|
+
"claude-code": "Claude Code",
|
|
4
|
+
codex: "Codex",
|
|
5
|
+
gemini: "Gemini CLI",
|
|
6
|
+
goose: "Goose",
|
|
7
|
+
opencode: "OpenCode",
|
|
8
|
+
pi: "Pi",
|
|
9
|
+
grok: "Grok"
|
|
10
|
+
});
|
|
11
|
+
var DEFAULT_LABELS = Object.freeze({
|
|
12
|
+
chats: "Chats",
|
|
13
|
+
newChat: "New chat",
|
|
14
|
+
searchChats: "Search chats",
|
|
15
|
+
askAgent: "Ask your agent\u2026",
|
|
16
|
+
attachContext: "Attach files or images",
|
|
17
|
+
continueHere: "Continue here",
|
|
18
|
+
continueWithTerminal: "Continue with terminal",
|
|
19
|
+
joinLive: "Join live",
|
|
20
|
+
forkHere: "Fork here"
|
|
21
|
+
});
|
|
22
|
+
var EMPTY_UI_STATE = Object.freeze({
|
|
23
|
+
pill: Object.freeze({ tone: "off", label: "connecting\u2026" }),
|
|
24
|
+
startup: "connecting",
|
|
25
|
+
transcript: Object.freeze([]),
|
|
26
|
+
busy: false,
|
|
27
|
+
operation: null,
|
|
28
|
+
needsInput: false,
|
|
29
|
+
harness: "",
|
|
30
|
+
mode: "none",
|
|
31
|
+
strategy: null,
|
|
32
|
+
participant: Object.freeze({ kind: "local-user", label: null, origin: null }),
|
|
33
|
+
workspaceRef: Object.freeze({ kind: "none", value: null }),
|
|
34
|
+
mirror: null,
|
|
35
|
+
holder: null,
|
|
36
|
+
canSend: false,
|
|
37
|
+
canSteer: false,
|
|
38
|
+
canResume: false,
|
|
39
|
+
supportsResume: false,
|
|
40
|
+
continuationModes: Object.freeze([]),
|
|
41
|
+
canBranch: false,
|
|
42
|
+
supportsBranch: false,
|
|
43
|
+
canAttach: false,
|
|
44
|
+
supportsAttach: false,
|
|
45
|
+
canDetach: false,
|
|
46
|
+
canOpenTerminal: false,
|
|
47
|
+
canExport: false,
|
|
48
|
+
canReduce: false,
|
|
49
|
+
canInterrupt: false,
|
|
50
|
+
canRespond: false,
|
|
51
|
+
canConfigureSettings: false,
|
|
52
|
+
messaging: null,
|
|
53
|
+
workspace: "",
|
|
54
|
+
taskPlan: Object.freeze({ source: "none", items: Object.freeze([]), residueCount: 0, observedAt: null }),
|
|
55
|
+
semantics: Object.freeze({ fidelity: null, residue: Object.freeze([]), residueCount: 0, parseErrors: 0, rawRecords: 0, subagents: Object.freeze([]) }),
|
|
56
|
+
terminalHandoff: null,
|
|
57
|
+
exportBackTarget: null,
|
|
58
|
+
exportReceipt: null,
|
|
59
|
+
reductionReceipt: null,
|
|
60
|
+
interopSettings: null,
|
|
61
|
+
interopSettingsError: null,
|
|
62
|
+
harnessAuthentication: null,
|
|
63
|
+
error: null,
|
|
64
|
+
recoverable: false,
|
|
65
|
+
harnesses: Object.freeze([]),
|
|
66
|
+
history: Object.freeze({ sessionLimit: 0, hasMoreSessions: false, transcriptLimit: 120, hasEarlier: false }),
|
|
67
|
+
savedDraft: "",
|
|
68
|
+
attention: Object.freeze([]),
|
|
69
|
+
sessions: Object.freeze([]),
|
|
70
|
+
subagentInspector: null,
|
|
71
|
+
attached: null,
|
|
72
|
+
owned: null,
|
|
73
|
+
attachError: null,
|
|
74
|
+
agentPackage: null,
|
|
75
|
+
contributions: Object.freeze([]),
|
|
76
|
+
agentPackageError: null,
|
|
77
|
+
agentPackageCapabilityState: null,
|
|
78
|
+
agentPackageCapabilityError: null
|
|
79
|
+
});
|
|
80
|
+
var ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "reasoning", "request", "notice"]);
|
|
81
|
+
var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
|
|
82
|
+
var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch", "reduce"]);
|
|
83
|
+
var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering", "ready"]);
|
|
84
|
+
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
85
|
+
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
86
|
+
var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
|
|
87
|
+
var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "required", "configured", "unavailable", "launching", "awaiting_user", "verifying", "authenticated", "failed", "cancelled"]);
|
|
88
|
+
var MAX_TOOL_FIELDS = 8;
|
|
89
|
+
var MAX_TOOL_FIELD_CHARS = 800;
|
|
90
|
+
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
91
|
+
var MAX_CONTRIBUTIONS = 64;
|
|
92
|
+
var MAX_CONTRIBUTION_JSON_DEPTH = 12;
|
|
93
|
+
var MAX_CONTRIBUTION_COLLECTION = 100;
|
|
94
|
+
var MAX_CONTRIBUTION_STRING_CHARS = 16e3;
|
|
95
|
+
function record(value) {
|
|
96
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
97
|
+
}
|
|
98
|
+
function readHarnessAuthentication(value) {
|
|
99
|
+
const flow = record(value);
|
|
100
|
+
if (flow?.schema !== "supercode.harness-authentication-flow.v1" || !AUTHENTICATION_PHASES.has(flow.phase)) return null;
|
|
101
|
+
const plan = record(flow.plan);
|
|
102
|
+
const error = record(flow.error);
|
|
103
|
+
return {
|
|
104
|
+
schema: "supercode.harness-authentication-flow.v1",
|
|
105
|
+
revision: Number.isSafeInteger(flow.revision) ? Math.max(0, flow.revision) : 0,
|
|
106
|
+
phase: flow.phase,
|
|
107
|
+
harness: typeof flow.harness === "string" ? boundedString(flow.harness, 100) : null,
|
|
108
|
+
plan: plan ? {
|
|
109
|
+
method: plan.method === "device_code" ? "device_code" : "browser",
|
|
110
|
+
interaction: plan.interaction === "device_code" ? "device_code" : "browser",
|
|
111
|
+
browserBehavior: plan.browserBehavior === "none" ? "none" : "native_auto",
|
|
112
|
+
headless: plan.headless === true,
|
|
113
|
+
instructions: boundedString(plan.instructions, 2e3)
|
|
114
|
+
} : null,
|
|
115
|
+
error: error && typeof error.message === "string" ? { code: boundedString(error.code, 100), message: boundedString(error.message, 2e3) } : null
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function string(value, fallback = "") {
|
|
119
|
+
return typeof value === "string" ? value : fallback;
|
|
120
|
+
}
|
|
121
|
+
function number(value, fallback = 0) {
|
|
122
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
123
|
+
}
|
|
124
|
+
function nullableNumber(value) {
|
|
125
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
126
|
+
}
|
|
127
|
+
function relativeContributionPath(value) {
|
|
128
|
+
if (typeof value !== "string" || value.startsWith("/") || /^[a-z]:[\\/]/i.test(value)) return null;
|
|
129
|
+
return value.replaceAll("\\", "/").split("/").some((segment) => segment === "..") ? null : boundedString(value, 1e3);
|
|
130
|
+
}
|
|
131
|
+
function contributionJson(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
132
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") {
|
|
133
|
+
return typeof value === "string" ? boundedString(value, MAX_CONTRIBUTION_STRING_CHARS) : value;
|
|
134
|
+
}
|
|
135
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
136
|
+
if (depth >= MAX_CONTRIBUTION_JSON_DEPTH || !value || typeof value !== "object" || seen.has(value)) {
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
139
|
+
seen.add(value);
|
|
140
|
+
if (Array.isArray(value)) {
|
|
141
|
+
const result2 = [];
|
|
142
|
+
for (const item of value.slice(0, MAX_CONTRIBUTION_COLLECTION)) {
|
|
143
|
+
const normalized = contributionJson(item, depth + 1, seen);
|
|
144
|
+
if (normalized !== void 0) result2.push(normalized);
|
|
145
|
+
}
|
|
146
|
+
seen.delete(value);
|
|
147
|
+
return result2;
|
|
148
|
+
}
|
|
149
|
+
const source = record(value);
|
|
150
|
+
if (!source) return void 0;
|
|
151
|
+
const result = {};
|
|
152
|
+
for (const [key, item] of Object.entries(source).slice(0, MAX_CONTRIBUTION_COLLECTION)) {
|
|
153
|
+
const normalized = contributionJson(item, depth + 1, seen);
|
|
154
|
+
if (normalized !== void 0) result[boundedString(key, 200)] = normalized;
|
|
155
|
+
}
|
|
156
|
+
seen.delete(value);
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
function normalizeContributions(value) {
|
|
160
|
+
if (!Array.isArray(value)) return [];
|
|
161
|
+
return value.slice(0, MAX_CONTRIBUTIONS).flatMap((candidate) => {
|
|
162
|
+
const item = record(candidate);
|
|
163
|
+
const placement = record(item?.placement);
|
|
164
|
+
const source = relativeContributionPath(item?.source);
|
|
165
|
+
if (item?.schema !== "supercode/contribution-v1" || typeof item.id !== "string" || !item.id.trim() || typeof item.kind !== "string" || !item.kind.trim() || source === null) return [];
|
|
166
|
+
const data = contributionJson(item.data);
|
|
167
|
+
if (data === void 0) return [];
|
|
168
|
+
return [{
|
|
169
|
+
schema: "supercode/contribution-v1",
|
|
170
|
+
id: boundedString(item.id, 200),
|
|
171
|
+
kind: boundedString(item.kind, 100),
|
|
172
|
+
...typeof item.title === "string" ? { title: boundedString(item.title, 500) } : {},
|
|
173
|
+
...placement ? { placement: {
|
|
174
|
+
...typeof placement.surface === "string" ? { surface: boundedString(placement.surface, 100) } : {},
|
|
175
|
+
...typeof placement.region === "string" ? { region: boundedString(placement.region, 100) } : {}
|
|
176
|
+
} } : {},
|
|
177
|
+
data,
|
|
178
|
+
source
|
|
179
|
+
}];
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function readAgentPackage(value) {
|
|
183
|
+
const agentPackage = record(value);
|
|
184
|
+
const capabilities = record(agentPackage?.capabilities);
|
|
185
|
+
const storage = record(agentPackage?.storage);
|
|
186
|
+
const relativePath = relativeContributionPath(storage?.relativePath);
|
|
187
|
+
if (agentPackage?.schemaVersion !== 1 || typeof agentPackage.id !== "string" || typeof agentPackage.name !== "string" || typeof agentPackage.version !== "string" || !capabilities || !Array.isArray(capabilities.required) || !Array.isArray(capabilities.optional) || !storage || relativePath === null) return null;
|
|
188
|
+
const resources = record(agentPackage.resources);
|
|
189
|
+
return {
|
|
190
|
+
id: boundedString(agentPackage.id, 200),
|
|
191
|
+
name: boundedString(agentPackage.name, 500),
|
|
192
|
+
version: boundedString(agentPackage.version, 100),
|
|
193
|
+
description: typeof agentPackage.description === "string" ? boundedString(agentPackage.description, 2e3) : null,
|
|
194
|
+
capabilities: {
|
|
195
|
+
required: capabilities.required.filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200)),
|
|
196
|
+
optional: capabilities.optional.filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200))
|
|
197
|
+
},
|
|
198
|
+
storage: { relativePath },
|
|
199
|
+
resources: resources ? Object.fromEntries(Object.entries(resources).flatMap(([id, candidate]) => {
|
|
200
|
+
const state = record(candidate);
|
|
201
|
+
if (state?.schema !== "supercode/package-resource-state-v1") return [];
|
|
202
|
+
if (state.status === "absent" && typeof state.contributionId === "string") {
|
|
203
|
+
return [[boundedString(id, 200), {
|
|
204
|
+
schema: "supercode/package-resource-state-v1",
|
|
205
|
+
status: "absent",
|
|
206
|
+
contributionId: boundedString(state.contributionId, 200)
|
|
207
|
+
}]];
|
|
208
|
+
}
|
|
209
|
+
if (state.status === "error" && typeof state.contributionId === "string" && typeof state.message === "string") {
|
|
210
|
+
return [[boundedString(id, 200), {
|
|
211
|
+
schema: "supercode/package-resource-state-v1",
|
|
212
|
+
status: "error",
|
|
213
|
+
contributionId: boundedString(state.contributionId, 200),
|
|
214
|
+
message: boundedString(state.message)
|
|
215
|
+
}]];
|
|
216
|
+
}
|
|
217
|
+
const resource = record(state?.resource);
|
|
218
|
+
const data = contributionJson(resource?.data);
|
|
219
|
+
if (state?.status !== "ready" || resource?.schema !== "supercode/package-resource-v1" || typeof resource.contributionId !== "string" || !["json", "text"].includes(resource.format) || typeof resource.mediaType !== "string" || data === void 0) return [];
|
|
220
|
+
return [[boundedString(id, 200), {
|
|
221
|
+
schema: "supercode/package-resource-state-v1",
|
|
222
|
+
status: "ready",
|
|
223
|
+
resource: {
|
|
224
|
+
schema: "supercode/package-resource-v1",
|
|
225
|
+
contributionId: boundedString(resource.contributionId, 200),
|
|
226
|
+
format: resource.format,
|
|
227
|
+
mediaType: boundedString(resource.mediaType, 200),
|
|
228
|
+
data
|
|
229
|
+
}
|
|
230
|
+
}]];
|
|
231
|
+
})) : {}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function readAgentPackageCapabilityState(value) {
|
|
235
|
+
const state = record(value);
|
|
236
|
+
if (!state) return null;
|
|
237
|
+
const fields = ["availableRequired", "missingRequired", "enabledOptional", "unavailableOptional"];
|
|
238
|
+
if (!fields.every((field) => Array.isArray(state[field]))) return null;
|
|
239
|
+
return {
|
|
240
|
+
ready: state.ready === true,
|
|
241
|
+
...Object.fromEntries(fields.map((field) => [
|
|
242
|
+
field,
|
|
243
|
+
state[field].filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200))
|
|
244
|
+
]))
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function relativeAge(updatedAt, now = Date.now()) {
|
|
248
|
+
if (typeof updatedAt !== "number" || !Number.isFinite(updatedAt) || updatedAt <= 0) return "";
|
|
249
|
+
const delta = Math.max(0, now - updatedAt);
|
|
250
|
+
if (delta < 6e4) return "now";
|
|
251
|
+
if (delta < 36e5) return `${Math.floor(delta / 6e4)}m ago`;
|
|
252
|
+
if (delta < 864e5) return `${Math.floor(delta / 36e5)}h ago`;
|
|
253
|
+
if (delta < 6048e5) return `${Math.floor(delta / 864e5)}d ago`;
|
|
254
|
+
return `${Math.floor(delta / 6048e5)}w ago`;
|
|
255
|
+
}
|
|
256
|
+
function boundedString(value, max = 2e3) {
|
|
257
|
+
if (typeof value !== "string") return "";
|
|
258
|
+
return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
|
|
259
|
+
}
|
|
260
|
+
function argumentValue(argumentsText) {
|
|
261
|
+
if (!argumentsText) return null;
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(argumentsText);
|
|
264
|
+
} catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function firstString(source, keys) {
|
|
269
|
+
for (const key of keys) {
|
|
270
|
+
if (typeof source?.[key] === "string" && source[key].trim()) return source[key].trim();
|
|
271
|
+
}
|
|
272
|
+
return "";
|
|
273
|
+
}
|
|
274
|
+
function decodedLiteral(value) {
|
|
275
|
+
if (!value) return "";
|
|
276
|
+
if (value.startsWith('"')) {
|
|
277
|
+
try {
|
|
278
|
+
return JSON.parse(value);
|
|
279
|
+
} catch {
|
|
280
|
+
return "";
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return value.slice(1, -1).replaceAll("\\n", "\n").replaceAll("\\t", " ").replaceAll("\\r", "\r").replaceAll("\\`", "`").replaceAll("\\'", "'").replaceAll("\\\\", "\\");
|
|
284
|
+
}
|
|
285
|
+
function sourceString(source, keys) {
|
|
286
|
+
if (!source) return "";
|
|
287
|
+
const names = keys.join("|");
|
|
288
|
+
const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
289
|
+
return decodedLiteral(match?.[1]);
|
|
290
|
+
}
|
|
291
|
+
function assignedString(source, keys) {
|
|
292
|
+
if (!source) return "";
|
|
293
|
+
const names = keys.join("|");
|
|
294
|
+
const match = new RegExp(`\\b(?:${names})\\s*=\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
295
|
+
return decodedLiteral(match?.[1]);
|
|
296
|
+
}
|
|
297
|
+
function callArgumentSource(source, open) {
|
|
298
|
+
let depth = 1;
|
|
299
|
+
let quote = "";
|
|
300
|
+
let escaped = false;
|
|
301
|
+
let lineComment = false;
|
|
302
|
+
let blockComment = false;
|
|
303
|
+
for (let index = open + 1; index < source.length; index += 1) {
|
|
304
|
+
const char = source[index];
|
|
305
|
+
const next = source[index + 1];
|
|
306
|
+
if (lineComment) {
|
|
307
|
+
if (char === "\n") lineComment = false;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (blockComment) {
|
|
311
|
+
if (char === "*" && next === "/") {
|
|
312
|
+
blockComment = false;
|
|
313
|
+
index += 1;
|
|
314
|
+
}
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (quote) {
|
|
318
|
+
if (escaped) escaped = false;
|
|
319
|
+
else if (char === "\\") escaped = true;
|
|
320
|
+
else if (char === quote) quote = "";
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (char === "/" && next === "/") {
|
|
324
|
+
lineComment = true;
|
|
325
|
+
index += 1;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (char === "/" && next === "*") {
|
|
329
|
+
blockComment = true;
|
|
330
|
+
index += 1;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
334
|
+
quote = char;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (char === "(") depth += 1;
|
|
338
|
+
else if (char === ")" && (depth -= 1) === 0) return source.slice(open + 1, index);
|
|
339
|
+
}
|
|
340
|
+
return source.slice(open + 1);
|
|
341
|
+
}
|
|
342
|
+
function toolCalls(source) {
|
|
343
|
+
const calls = [];
|
|
344
|
+
let quote = "";
|
|
345
|
+
let escaped = false;
|
|
346
|
+
let lineComment = false;
|
|
347
|
+
let blockComment = false;
|
|
348
|
+
for (let index = 0; index < source.length && calls.length < 8; index += 1) {
|
|
349
|
+
const char = source[index];
|
|
350
|
+
const next = source[index + 1];
|
|
351
|
+
if (lineComment) {
|
|
352
|
+
if (char === "\n") lineComment = false;
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (blockComment) {
|
|
356
|
+
if (char === "*" && next === "/") {
|
|
357
|
+
blockComment = false;
|
|
358
|
+
index += 1;
|
|
359
|
+
}
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (quote) {
|
|
363
|
+
if (escaped) escaped = false;
|
|
364
|
+
else if (char === "\\") escaped = true;
|
|
365
|
+
else if (char === quote) quote = "";
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (char === "/" && next === "/") {
|
|
369
|
+
lineComment = true;
|
|
370
|
+
index += 1;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (char === "/" && next === "*") {
|
|
374
|
+
blockComment = true;
|
|
375
|
+
index += 1;
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
379
|
+
quote = char;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (!source.startsWith("tools.", index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? "")) continue;
|
|
383
|
+
const nameStart = index + 6;
|
|
384
|
+
let nameEnd = nameStart;
|
|
385
|
+
while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? "")) nameEnd += 1;
|
|
386
|
+
let open = nameEnd;
|
|
387
|
+
while (/\s/.test(source[open] ?? "")) open += 1;
|
|
388
|
+
if (nameEnd === nameStart || source[open] !== "(") continue;
|
|
389
|
+
calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
|
|
390
|
+
index = open;
|
|
391
|
+
}
|
|
392
|
+
return calls;
|
|
393
|
+
}
|
|
394
|
+
function toolEnvelope(entry) {
|
|
395
|
+
const value = argumentValue(entry.arguments);
|
|
396
|
+
const source = typeof value === "string" ? value : value === null ? entry.arguments ?? "" : "";
|
|
397
|
+
const calls = source ? toolCalls(source) : [];
|
|
398
|
+
const tools = [...new Set(calls.map((call) => call.name))];
|
|
399
|
+
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
400
|
+
return { args: record(value), source, callSource: calls[0]?.arguments ?? "", tools, name };
|
|
401
|
+
}
|
|
402
|
+
function patchPath(source) {
|
|
403
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? "";
|
|
404
|
+
}
|
|
405
|
+
function explicitNumber(sources, keys) {
|
|
406
|
+
for (const source of sources) {
|
|
407
|
+
for (const key of keys) {
|
|
408
|
+
const value = source?.[key];
|
|
409
|
+
const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
|
|
410
|
+
if (typeof parsed === "number" && Number.isFinite(parsed)) return parsed;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
function toolDetail(category) {
|
|
416
|
+
return { read: "file", search: "matches", edit: "diff", command: "terminal", test: "terminal", web: "web", agent: "agent", plan: "plan" }[category] ?? "fields";
|
|
417
|
+
}
|
|
418
|
+
function usefulToolFields(args) {
|
|
419
|
+
if (!args) return [];
|
|
420
|
+
const hidden = /* @__PURE__ */ new Set(["command", "cmd", "file_path", "target_file", "path", "query", "pattern", "url", "patch", "diff", "old_string", "new_string", "content", "prompt", "description", "task", "plan", "todos"]);
|
|
421
|
+
return Object.entries(args).flatMap(([key, value]) => {
|
|
422
|
+
if (hidden.has(key) || value === null || value === void 0) return [];
|
|
423
|
+
const rendered = typeof value === "string" ? value : JSON.stringify(value);
|
|
424
|
+
if (!rendered) return [];
|
|
425
|
+
return [{ label: key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase()), value: boundedString(rendered, MAX_TOOL_FIELD_CHARS) }];
|
|
426
|
+
}).slice(0, MAX_TOOL_FIELDS);
|
|
427
|
+
}
|
|
428
|
+
function planItems(args) {
|
|
429
|
+
const source = Array.isArray(args?.plan) ? args.plan : Array.isArray(args?.todos) ? args.todos : [];
|
|
430
|
+
return source.flatMap((item) => {
|
|
431
|
+
if (typeof item === "string" && item.trim()) return [{ label: boundedString(item.trim(), 300), status: "" }];
|
|
432
|
+
const value = record(item);
|
|
433
|
+
const label = firstString(value, ["step", "title", "content", "text"]);
|
|
434
|
+
if (!label) return [];
|
|
435
|
+
return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
|
|
436
|
+
}).slice(0, 12);
|
|
437
|
+
}
|
|
438
|
+
function agentItems(name, resultText) {
|
|
439
|
+
if (!/list.?agents/i.test(name)) return [];
|
|
440
|
+
return (resultText ?? "").split("\n").flatMap((line) => {
|
|
441
|
+
const parts = line.trim().split(/\s+·\s+/).filter(Boolean);
|
|
442
|
+
return parts.length > 1 ? [{ label: boundedString(parts[0], 120), status: boundedString(parts.slice(1).join(" \xB7 "), 180) }] : [];
|
|
443
|
+
}).slice(0, 12);
|
|
444
|
+
}
|
|
445
|
+
function editPreview(args, resultText, source) {
|
|
446
|
+
const direct = firstString(args, ["patch", "diff"]);
|
|
447
|
+
if (direct) return direct;
|
|
448
|
+
const oldText = firstString(args, ["old_string"]);
|
|
449
|
+
const newText = firstString(args, ["new_string"]);
|
|
450
|
+
if (oldText || newText) {
|
|
451
|
+
return [
|
|
452
|
+
...oldText.split("\n").map((line) => `- ${line}`),
|
|
453
|
+
...newText.split("\n").map((line) => `+ ${line}`)
|
|
454
|
+
].join("\n");
|
|
455
|
+
}
|
|
456
|
+
const patch = /\*\*\* Begin Patch[\s\S]*?\*\*\* End Patch/.exec(source ?? "")?.[0];
|
|
457
|
+
if (patch) return patch;
|
|
458
|
+
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
459
|
+
}
|
|
460
|
+
function toolResultEnvelope(resultText) {
|
|
461
|
+
const match = /^Script (?:completed|failed)\r?\nWall time ([0-9.]+) seconds\r?\nOutput:\r?\n([\s\S]*)$/.exec(resultText ?? "");
|
|
462
|
+
if (!match) {
|
|
463
|
+
try {
|
|
464
|
+
const value = JSON.parse(resultText ?? "");
|
|
465
|
+
const object = record(value);
|
|
466
|
+
return {
|
|
467
|
+
preview: typeof value === "string" ? value : firstString(object, ["output", "message", "text", "summary", "result"]) || resultText || "",
|
|
468
|
+
value: object,
|
|
469
|
+
durationMs: null
|
|
470
|
+
};
|
|
471
|
+
} catch {
|
|
472
|
+
return { preview: resultText ?? "", value: null, durationMs: null };
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const durationMs = Number(match[1]) * 1e3;
|
|
476
|
+
try {
|
|
477
|
+
const value = record(JSON.parse(match[2]));
|
|
478
|
+
return {
|
|
479
|
+
preview: typeof value?.output === "string" ? value.output : match[2],
|
|
480
|
+
value,
|
|
481
|
+
durationMs: Number.isFinite(durationMs) ? durationMs : null
|
|
482
|
+
};
|
|
483
|
+
} catch {
|
|
484
|
+
return { preview: match[2], value: null, durationMs: Number.isFinite(durationMs) ? durationMs : null };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function semanticAgentPreview(name, status, outcome) {
|
|
488
|
+
const normalized = name.toLocaleLowerCase();
|
|
489
|
+
if (status === "error") return outcome.preview;
|
|
490
|
+
if (/^(?:agent|task)$|spawn.?agent/.test(normalized) && outcome.preview) return "Agent is working in the background.";
|
|
491
|
+
if (/send.?message|followup.?task/.test(normalized) && outcome.preview) {
|
|
492
|
+
return /resumed from transcript|resumedAgentId/i.test(outcome.preview) ? "Agent resumed in the background." : "Message delivered.";
|
|
493
|
+
}
|
|
494
|
+
return outcome.preview;
|
|
495
|
+
}
|
|
496
|
+
function verificationCommand(command) {
|
|
497
|
+
let shell = "";
|
|
498
|
+
let quote = "";
|
|
499
|
+
let escaped = false;
|
|
500
|
+
for (const char of command) {
|
|
501
|
+
if (escaped) {
|
|
502
|
+
escaped = false;
|
|
503
|
+
shell += quote ? " " : char;
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
if (char === "\\") {
|
|
507
|
+
escaped = true;
|
|
508
|
+
shell += quote ? " " : char;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (quote) {
|
|
512
|
+
if (char === quote) quote = "";
|
|
513
|
+
shell += " ";
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
517
|
+
quote = char;
|
|
518
|
+
shell += " ";
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
shell += char;
|
|
522
|
+
}
|
|
523
|
+
return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
|
|
524
|
+
}
|
|
525
|
+
function classifyTool(name, command) {
|
|
526
|
+
const normalized = name.toLocaleLowerCase();
|
|
527
|
+
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
528
|
+
if (/update.?plan|todo|checklist|taskcreate|taskupdate|create.?goal|update.?goal/.test(normalized)) return "plan";
|
|
529
|
+
if (/search.?replace|edit|write|patch|replace|create_file|apply_patch/.test(normalized)) return "edit";
|
|
530
|
+
if (/read|view|open_file|list_dir/.test(normalized)) return "read";
|
|
531
|
+
if (/web.?search|web.?fetch|fetch.?url/.test(normalized)) return "web";
|
|
532
|
+
if (/search|find|grep|glob|toolsearch/.test(normalized)) return "search";
|
|
533
|
+
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
534
|
+
if (/agent|subagent|send.?message|delegate|followup.?task|taskstop|taskoutput|^task$/.test(normalized)) return "agent";
|
|
535
|
+
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
536
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
|
|
537
|
+
return "other";
|
|
538
|
+
}
|
|
539
|
+
function toolAction(status, category, name, tools) {
|
|
540
|
+
const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
|
|
541
|
+
if (tools.length > 1) return [`Running ${tools.length} actions`, `Ran ${tools.length} actions`, `${tools.length} actions failed`][position];
|
|
542
|
+
const normalized = name.toLocaleLowerCase();
|
|
543
|
+
if (/send.?message|followup.?task/.test(normalized)) return ["Messaging agent", "Messaged agent", "Agent message failed"][position];
|
|
544
|
+
if (/taskstop|interrupt.?agent|kill_command_or_subagent/.test(normalized)) return ["Stopping agent", "Stopped agent", "Stop failed"][position];
|
|
545
|
+
if (/list.?agents|taskoutput|wait.?agent/.test(normalized)) return ["Checking agents", "Checked agents", "Agent check failed"][position];
|
|
546
|
+
if (/get_command_or_subagent_output|write_stdin|^wait$/.test(normalized)) return ["Waiting for", "Checked", "Check failed"][position];
|
|
547
|
+
if (/web.?search/.test(normalized)) return ["Searching web", "Searched web", "Web search failed"][position];
|
|
548
|
+
if (/web.?fetch|fetch.?url/.test(normalized)) return ["Fetching page", "Fetched page", "Page fetch failed"][position];
|
|
549
|
+
if (/^skill$|use.?skill|load.?skill/.test(normalized)) return ["Loading skill", "Loaded skill", "Skill load failed"][position];
|
|
550
|
+
if (/taskcreate/.test(normalized)) return ["Adding task", "Added task", "Task creation failed"][position];
|
|
551
|
+
if (/taskupdate/.test(normalized)) return ["Updating task", "Updated task", "Task update failed"][position];
|
|
552
|
+
if (/create.?goal/.test(normalized)) return ["Creating goal", "Created goal", "Goal creation failed"][position];
|
|
553
|
+
if (/update.?goal/.test(normalized)) return ["Updating goal", "Updated goal", "Goal update failed"][position];
|
|
554
|
+
const actions = {
|
|
555
|
+
read: ["Reading", "Read", "Read failed"],
|
|
556
|
+
search: ["Searching", "Searched", "Search failed"],
|
|
557
|
+
edit: ["Editing", "Edited", "Edit failed"],
|
|
558
|
+
command: ["Running command", "Ran command", "Command failed"],
|
|
559
|
+
test: ["Running tests", "Ran tests", "Tests failed"],
|
|
560
|
+
web: ["Browsing", "Browsed", "Browser action failed"],
|
|
561
|
+
agent: ["Starting agent", "Started agent", "Agent failed"],
|
|
562
|
+
plan: ["Updating plan", "Updated plan", "Plan update failed"]
|
|
563
|
+
};
|
|
564
|
+
return actions[category]?.[position] ?? (status === "error" ? `${name} failed` : name.replaceAll(/[_-]+/g, " "));
|
|
565
|
+
}
|
|
566
|
+
function createToolPresentation(entry) {
|
|
567
|
+
const envelope = toolEnvelope(entry);
|
|
568
|
+
const args = envelope.args;
|
|
569
|
+
const outcome = toolResultEnvelope(entry.resultText);
|
|
570
|
+
const patchSource = assignedString(envelope.source, ["patch"]) || envelope.source;
|
|
571
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
|
|
572
|
+
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
573
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(patchSource);
|
|
574
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
|
|
575
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
|
|
576
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "objective", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "objective", "prompt"]);
|
|
577
|
+
const agentTarget = category === "agent" ? firstString(record(outcome.value), ["command", "name"]) || firstString(args, ["target", "task_name", "taskId", "task_id", "agentId", "agent_id", "resume", "team_name"]) || sourceString(envelope.callSource, ["target", "task_name", "taskId", "task_id", "agentId", "agent_id", "resume", "team_name"]) : "";
|
|
578
|
+
const skillTarget = /^skill$|use.?skill|load.?skill/i.test(envelope.name) ? firstString(args, ["skill", "name"]) || sourceString(envelope.callSource, ["skill", "name"]) : "";
|
|
579
|
+
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
580
|
+
const items = category === "agent" ? agentItems(envelope.name, outcome.preview) : planItems(args);
|
|
581
|
+
const taskId = firstString(args, ["taskId", "task_id"]);
|
|
582
|
+
const planTarget = category === "plan" ? items.length ? `${items.length} ${items.length === 1 ? "item" : "items"}` : taskId ? `task ${taskId}` : "" : "";
|
|
583
|
+
const target = path || command || query || url || subject || agentTarget || skillTarget || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
584
|
+
const previewSource = category === "edit" ? editPreview(args, outcome.preview, patchSource) : category === "agent" ? semanticAgentPreview(envelope.name, entry.status ?? "completed", outcome) : outcome.preview;
|
|
585
|
+
const result = record(entry.resultContent);
|
|
586
|
+
const metadata = record(entry.metadata);
|
|
587
|
+
const resultMetadata = record(result?.metadata);
|
|
588
|
+
return {
|
|
589
|
+
name: boundedString(envelope.name, 120),
|
|
590
|
+
action: boundedString(toolAction(entry.status ?? "completed", category, envelope.name, envelope.tools), 120),
|
|
591
|
+
category,
|
|
592
|
+
detail: toolDetail(category),
|
|
593
|
+
target: boundedString(target, 300),
|
|
594
|
+
command: boundedString(command, MAX_TOOL_FIELD_CHARS),
|
|
595
|
+
path: boundedString(path, MAX_TOOL_FIELD_CHARS),
|
|
596
|
+
query: boundedString(query, MAX_TOOL_FIELD_CHARS),
|
|
597
|
+
url: boundedString(url, MAX_TOOL_FIELD_CHARS),
|
|
598
|
+
subject: boundedString(subject, MAX_TOOL_FIELD_CHARS),
|
|
599
|
+
preview: boundedString(previewSource, MAX_TOOL_PREVIEW_CHARS),
|
|
600
|
+
fields: usefulToolFields(args),
|
|
601
|
+
items,
|
|
602
|
+
tools: envelope.tools,
|
|
603
|
+
exitCode: explicitNumber([outcome.value, result, resultMetadata, metadata], ["exit_code", "exitCode", "pi_bash_exit_code"]),
|
|
604
|
+
durationMs: explicitNumber([outcome.value, result, resultMetadata, metadata], ["duration_ms", "durationMs", "elapsed_ms", "elapsedMs", "totalDurationMs"]) ?? outcome.durationMs,
|
|
605
|
+
additions: explicitNumber([result, resultMetadata, metadata], ["additions", "lines_added"]),
|
|
606
|
+
deletions: explicitNumber([result, resultMetadata, metadata], ["deletions", "lines_removed"]),
|
|
607
|
+
matches: explicitNumber([result, resultMetadata, metadata], ["matches", "match_count", "result_count"])
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function readToolPresentation(value, entry) {
|
|
611
|
+
const generated = createToolPresentation(entry);
|
|
612
|
+
const item = record(value);
|
|
613
|
+
if (!item) return generated;
|
|
614
|
+
const fields = Array.isArray(item.fields) ? item.fields.flatMap((raw) => {
|
|
615
|
+
const field = record(raw);
|
|
616
|
+
return field && typeof field.label === "string" && typeof field.value === "string" ? [{ label: boundedString(field.label, 80), value: boundedString(field.value, MAX_TOOL_FIELD_CHARS) }] : [];
|
|
617
|
+
}).slice(0, MAX_TOOL_FIELDS) : generated.fields;
|
|
618
|
+
const items = Array.isArray(item.items) ? item.items.flatMap((raw) => {
|
|
619
|
+
const planItem = record(raw);
|
|
620
|
+
return planItem && typeof planItem.label === "string" ? [{ label: boundedString(planItem.label, 300), status: boundedString(planItem.status, 40) }] : [];
|
|
621
|
+
}).slice(0, 12) : generated.items;
|
|
622
|
+
const tools = Array.isArray(item.tools) ? item.tools.filter((tool) => typeof tool === "string").map((tool) => boundedString(tool, 120)).slice(0, 8) : generated.tools;
|
|
623
|
+
return {
|
|
624
|
+
name: boundedString(item.name, 120) || generated.name,
|
|
625
|
+
action: boundedString(item.action, 120) || generated.action,
|
|
626
|
+
category: TOOL_CATEGORIES.has(item.category) ? item.category : generated.category,
|
|
627
|
+
detail: TOOL_DETAILS.has(item.detail) ? item.detail : generated.detail,
|
|
628
|
+
target: boundedString(item.target, 300) || generated.target,
|
|
629
|
+
command: boundedString(item.command, MAX_TOOL_FIELD_CHARS) || generated.command,
|
|
630
|
+
path: boundedString(item.path, MAX_TOOL_FIELD_CHARS) || generated.path,
|
|
631
|
+
query: boundedString(item.query, MAX_TOOL_FIELD_CHARS) || generated.query,
|
|
632
|
+
url: boundedString(item.url, MAX_TOOL_FIELD_CHARS) || generated.url,
|
|
633
|
+
subject: boundedString(item.subject, MAX_TOOL_FIELD_CHARS) || generated.subject,
|
|
634
|
+
preview: boundedString(item.preview, MAX_TOOL_PREVIEW_CHARS) || generated.preview,
|
|
635
|
+
fields,
|
|
636
|
+
items,
|
|
637
|
+
tools,
|
|
638
|
+
exitCode: nullableNumber(item.exitCode) ?? generated.exitCode,
|
|
639
|
+
durationMs: nullableNumber(item.durationMs) ?? generated.durationMs,
|
|
640
|
+
additions: nullableNumber(item.additions) ?? generated.additions,
|
|
641
|
+
deletions: nullableNumber(item.deletions) ?? generated.deletions,
|
|
642
|
+
matches: nullableNumber(item.matches) ?? generated.matches
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
var OPAQUE_RAW_CHARS = 4e3;
|
|
646
|
+
function opaqueEntry(item) {
|
|
647
|
+
const previouslyOpaque = item.role === "opaque";
|
|
648
|
+
let raw;
|
|
649
|
+
if (previouslyOpaque && typeof item.raw === "string") {
|
|
650
|
+
raw = item.raw;
|
|
651
|
+
} else {
|
|
652
|
+
try {
|
|
653
|
+
raw = JSON.stringify(item, null, 2) ?? "";
|
|
654
|
+
} catch {
|
|
655
|
+
raw = "[unserializable entry payload]";
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
const kind = previouslyOpaque && typeof item.kind === "string" ? item.kind : typeof item.role === "string" ? item.role : "";
|
|
659
|
+
return {
|
|
660
|
+
id: item.id,
|
|
661
|
+
role: "opaque",
|
|
662
|
+
kind: boundedString(kind, 120) || "unknown",
|
|
663
|
+
text: typeof item.text === "string" ? boundedString(item.text, OPAQUE_RAW_CHARS) : "",
|
|
664
|
+
ts: nullableNumber(item.ts),
|
|
665
|
+
truncated: item.truncated === true || raw.length > OPAQUE_RAW_CHARS,
|
|
666
|
+
raw: boundedString(raw, OPAQUE_RAW_CHARS)
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
function readTranscript(value) {
|
|
670
|
+
if (!Array.isArray(value)) return [];
|
|
671
|
+
const result = [];
|
|
672
|
+
for (const candidate of value) {
|
|
673
|
+
const item = record(candidate);
|
|
674
|
+
if (!item || typeof item.id !== "string") continue;
|
|
675
|
+
if (typeof item.text !== "string" || !ROLES.has(item.role)) {
|
|
676
|
+
result.push(opaqueEntry(item));
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
const entry = {
|
|
680
|
+
id: item.id,
|
|
681
|
+
role: item.role,
|
|
682
|
+
text: item.text,
|
|
683
|
+
ts: nullableNumber(item.ts),
|
|
684
|
+
truncated: item.truncated === true,
|
|
685
|
+
...Number.isSafeInteger(item.messageIndex) && item.messageIndex > 0 ? { messageIndex: item.messageIndex } : {}
|
|
686
|
+
};
|
|
687
|
+
for (const key of ["label", "arguments", "resultText", "code"]) {
|
|
688
|
+
if (typeof item[key] === "string") entry[key] = item[key];
|
|
689
|
+
}
|
|
690
|
+
if (["pending", "completed", "error"].includes(item.status)) entry.status = item.status;
|
|
691
|
+
if (item.role === "tool") entry.presentation = readToolPresentation(item.presentation, entry);
|
|
692
|
+
if (typeof item.streaming === "boolean") entry.streaming = item.streaming;
|
|
693
|
+
if (Array.isArray(item.context)) {
|
|
694
|
+
entry.context = item.context.flatMap((raw) => {
|
|
695
|
+
const context = record(raw);
|
|
696
|
+
return context && typeof context.label === "string" && typeof context.detail === "string" ? [{
|
|
697
|
+
...typeof context.id === "string" ? { id: context.id } : {},
|
|
698
|
+
...typeof context.kind === "string" ? { kind: context.kind } : {},
|
|
699
|
+
label: context.label,
|
|
700
|
+
detail: context.detail
|
|
701
|
+
}] : [];
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
if (Array.isArray(item.images)) {
|
|
705
|
+
entry.images = item.images.flatMap((raw) => {
|
|
706
|
+
const image = record(raw);
|
|
707
|
+
return image && typeof image.label === "string" ? [{
|
|
708
|
+
...typeof image.id === "string" ? { id: image.id } : {},
|
|
709
|
+
label: image.label,
|
|
710
|
+
...typeof image.url === "string" ? { url: image.url } : {},
|
|
711
|
+
...typeof image.reference === "string" && image.reference.length <= 4e3 ? { reference: image.reference } : {},
|
|
712
|
+
...typeof image.mediaType === "string" && image.mediaType.startsWith("image/") && image.mediaType.length <= 100 ? { mediaType: image.mediaType } : {},
|
|
713
|
+
...Number.isSafeInteger(image.byteSize) && image.byteSize >= 0 ? { byteSize: image.byteSize } : {}
|
|
714
|
+
}] : [];
|
|
715
|
+
}).slice(0, 4);
|
|
716
|
+
}
|
|
717
|
+
const request = record(item.request);
|
|
718
|
+
if (request && typeof request.requestKind === "string" && typeof request.payloadText === "string") {
|
|
719
|
+
entry.request = {
|
|
720
|
+
requestId: request.requestId,
|
|
721
|
+
requestKind: request.requestKind,
|
|
722
|
+
payloadText: request.payloadText,
|
|
723
|
+
options: Array.isArray(request.options) ? request.options.flatMap((raw) => {
|
|
724
|
+
const option = record(raw);
|
|
725
|
+
return option && typeof option.optionId === "string" && typeof option.name === "string" ? [{ optionId: option.optionId, name: option.name, kind: string(option.kind, "other") }] : [];
|
|
726
|
+
}) : [],
|
|
727
|
+
cancellable: request.cancellable === true,
|
|
728
|
+
status: request.status === "responded" ? "responded" : "pending",
|
|
729
|
+
resolution: record(request.resolution)
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
result.push(entry);
|
|
733
|
+
}
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
function readParticipant(value) {
|
|
737
|
+
const participant = record(value);
|
|
738
|
+
if (!participant) return { kind: "local-user", label: null, origin: null };
|
|
739
|
+
return {
|
|
740
|
+
kind: ["local-user", "foreign", "unknown"].includes(participant.kind) ? participant.kind : "unknown",
|
|
741
|
+
label: typeof participant.label === "string" && participant.label ? boundedString(participant.label, 200) : null,
|
|
742
|
+
origin: typeof participant.origin === "string" && participant.origin ? boundedString(participant.origin, 100) : null
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
function readWorkspaceRef(value, fallbackPath = "") {
|
|
746
|
+
const ref = record(value);
|
|
747
|
+
if (ref && ["repo", "none", "channel"].includes(ref.kind)) {
|
|
748
|
+
return {
|
|
749
|
+
kind: ref.kind,
|
|
750
|
+
value: ref.kind === "none" ? null : typeof ref.value === "string" && ref.value ? boundedString(ref.value, 500) : null
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
return fallbackPath ? { kind: "repo", value: boundedString(fallbackPath, 500) } : { kind: "none", value: null };
|
|
754
|
+
}
|
|
755
|
+
function readMirror(value) {
|
|
756
|
+
const mirror = record(value);
|
|
757
|
+
if (!mirror || typeof mirror.canonicalHarness !== "string" || !mirror.canonicalHarness) return null;
|
|
758
|
+
return {
|
|
759
|
+
canonicalHarness: boundedString(mirror.canonicalHarness, 100),
|
|
760
|
+
canonicalKey: typeof mirror.canonicalKey === "string" && mirror.canonicalKey ? boundedString(mirror.canonicalKey, 300) : null,
|
|
761
|
+
bounded: mirror.bounded === true,
|
|
762
|
+
truncated: mirror.truncated === true,
|
|
763
|
+
origin: typeof mirror.origin === "string" && mirror.origin ? boundedString(mirror.origin, 200) : null
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function readHolder(value) {
|
|
767
|
+
const holder = record(value);
|
|
768
|
+
if (!holder) return null;
|
|
769
|
+
const surface = typeof holder.surface === "string" && holder.surface ? boundedString(holder.surface, 100) : null;
|
|
770
|
+
return {
|
|
771
|
+
surface,
|
|
772
|
+
canTakeOver: holder.canTakeOver === true && surface !== null && surface !== "supercode"
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
var TRIGGER_KINDS = ["human", "channel", "cron", "heartbeat", "webhook", "parent", "api", "unknown"];
|
|
776
|
+
function readTrigger(value) {
|
|
777
|
+
const trigger = record(value);
|
|
778
|
+
if (!trigger) return null;
|
|
779
|
+
const kind = trigger.kind === "manual" ? "human" : trigger.kind;
|
|
780
|
+
return {
|
|
781
|
+
kind: TRIGGER_KINDS.includes(kind) ? kind : "unknown",
|
|
782
|
+
label: typeof trigger.label === "string" && trigger.label ? boundedString(trigger.label, 200) : null,
|
|
783
|
+
surface: typeof trigger.surface === "string" && trigger.surface ? boundedString(trigger.surface, 300) : null
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
function readCrossSurface(value) {
|
|
787
|
+
const moved = record(value);
|
|
788
|
+
if (!moved || typeof moved.state !== "string" || !moved.state) return null;
|
|
789
|
+
return {
|
|
790
|
+
state: boundedString(moved.state, 100),
|
|
791
|
+
platform: typeof moved.platform === "string" && moved.platform ? boundedString(moved.platform, 100) : null,
|
|
792
|
+
error: typeof moved.error === "string" && moved.error ? boundedString(moved.error, 500) : null
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
function readRecurring(value) {
|
|
796
|
+
const recurring = record(value);
|
|
797
|
+
if (!recurring || typeof recurring.groupKey !== "string" || !recurring.groupKey) return null;
|
|
798
|
+
const runs = Number.isSafeInteger(recurring.runs) && recurring.runs > 0 ? recurring.runs : 1;
|
|
799
|
+
return {
|
|
800
|
+
groupKey: boundedString(recurring.groupKey, 300),
|
|
801
|
+
runs,
|
|
802
|
+
lastStatus: ["ok", "failed", "mixed"].includes(recurring.lastStatus) ? recurring.lastStatus : null
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
function readSessions(value) {
|
|
806
|
+
if (!Array.isArray(value)) return [];
|
|
807
|
+
return value.flatMap((raw) => {
|
|
808
|
+
const row = record(raw);
|
|
809
|
+
if (!row || typeof row.key !== "string" || typeof row.harness !== "string") return [];
|
|
810
|
+
return [{
|
|
811
|
+
key: row.key,
|
|
812
|
+
harness: row.harness,
|
|
813
|
+
name: string(row.name),
|
|
814
|
+
cwd: string(row.cwd),
|
|
815
|
+
title: string(row.title),
|
|
816
|
+
preview: string(row.preview),
|
|
817
|
+
age: string(row.age),
|
|
818
|
+
previewUpdatedAt: nullableNumber(row.previewUpdatedAt),
|
|
819
|
+
updatedAt: nullableNumber(row.updatedAt),
|
|
820
|
+
messages: nullableNumber(row.messages),
|
|
821
|
+
active: row.active === true,
|
|
822
|
+
writable: row.writable === true,
|
|
823
|
+
live: row.live === true,
|
|
824
|
+
runtimeStatus: row.runtimeStatus === "running" || row.runtimeStatus === "busy" || row.runtimeStatus === "idle" ? row.runtimeStatus : null,
|
|
825
|
+
...Number.isSafeInteger(row.subagentCount) && row.subagentCount > 0 ? { subagentCount: row.subagentCount } : {},
|
|
826
|
+
activity: ACTIVITY_PRIORITY[row.activity] !== void 0 ? row.activity : void 0,
|
|
827
|
+
...row.participant !== void 0 ? { participant: readParticipant(row.participant) } : {},
|
|
828
|
+
workspaceRef: readWorkspaceRef(row.workspaceRef, string(row.cwd)),
|
|
829
|
+
...readMirror(row.mirror) ? { mirror: readMirror(row.mirror) } : {},
|
|
830
|
+
...readTrigger(row.trigger) ? { trigger: readTrigger(row.trigger) } : {},
|
|
831
|
+
...readRecurring(row.recurring) ? { recurring: readRecurring(row.recurring) } : {},
|
|
832
|
+
...readCrossSurface(row.crossSurface) ? { crossSurface: readCrossSurface(row.crossSurface) } : {}
|
|
833
|
+
}];
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
function readSubagentInspector(value) {
|
|
837
|
+
const inspector = record(value);
|
|
838
|
+
if (!inspector || typeof inspector.parentKey !== "string" || !inspector.parentKey) return null;
|
|
839
|
+
return {
|
|
840
|
+
parentKey: inspector.parentKey,
|
|
841
|
+
parentTitle: boundedString(string(inspector.parentTitle), 500),
|
|
842
|
+
status: ["loading", "ready", "error"].includes(inspector.status) ? inspector.status : "loading",
|
|
843
|
+
items: readSessions(inspector.items).slice(0, 100),
|
|
844
|
+
selectedKey: typeof inspector.selectedKey === "string" && inspector.selectedKey ? inspector.selectedKey : null,
|
|
845
|
+
transcript: readTranscript(inspector.transcript).slice(-120),
|
|
846
|
+
error: typeof inspector.error === "string" ? boundedString(inspector.error) : null
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
function readAttached(value) {
|
|
850
|
+
const item = record(value);
|
|
851
|
+
if (!item || typeof item.harness !== "string") return null;
|
|
852
|
+
return { key: string(item.key), harness: item.harness, name: string(item.name), cwd: string(item.cwd), title: string(item.title) };
|
|
853
|
+
}
|
|
854
|
+
function readTaskPlan(value) {
|
|
855
|
+
const plan = record(value);
|
|
856
|
+
if (!plan) return { ...EMPTY_UI_STATE.taskPlan, items: [] };
|
|
857
|
+
return {
|
|
858
|
+
source: ["codex-update-plan", "claude-tasks", "opencode-todos"].includes(plan.source) ? plan.source : "none",
|
|
859
|
+
items: Array.isArray(plan.items) ? plan.items.flatMap((raw) => {
|
|
860
|
+
const item = record(raw);
|
|
861
|
+
if (!item || typeof item.id !== "string" || typeof item.title !== "string") return [];
|
|
862
|
+
return [{
|
|
863
|
+
id: item.id,
|
|
864
|
+
title: item.title,
|
|
865
|
+
status: ["pending", "in_progress", "completed", "cancelled", "unknown"].includes(item.status) ? item.status : "unknown",
|
|
866
|
+
...typeof item.nativeStatus === "string" ? { nativeStatus: item.nativeStatus } : {},
|
|
867
|
+
...Array.isArray(item.blockedBy) ? { blockedBy: item.blockedBy.filter((value2) => typeof value2 === "string") } : {}
|
|
868
|
+
}];
|
|
869
|
+
}) : [],
|
|
870
|
+
residueCount: number(plan.residueCount),
|
|
871
|
+
observedAt: nullableNumber(plan.observedAt)
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
function readSemantics(value) {
|
|
875
|
+
const semantics = record(value);
|
|
876
|
+
if (!semantics) return { ...EMPTY_UI_STATE.semantics, residue: [], subagents: [] };
|
|
877
|
+
return {
|
|
878
|
+
fidelity: FIDELITY.has(semantics.fidelity) ? semantics.fidelity : null,
|
|
879
|
+
residue: Array.isArray(semantics.residue) ? semantics.residue.filter((item) => typeof item === "string") : [],
|
|
880
|
+
residueCount: number(semantics.residueCount),
|
|
881
|
+
parseErrors: number(semantics.parseErrors),
|
|
882
|
+
rawRecords: number(semantics.rawRecords),
|
|
883
|
+
subagents: Array.isArray(semantics.subagents) ? semantics.subagents.flatMap((raw) => {
|
|
884
|
+
const child = record(raw);
|
|
885
|
+
if (!child || typeof child.id !== "string" || typeof child.source !== "string") return [];
|
|
886
|
+
return [{ id: child.id, source: child.source, model: typeof child.model === "string" ? child.model : null, messages: number(child.messages), fidelity: FIDELITY.has(child.fidelity) ? child.fidelity : "semantic" }];
|
|
887
|
+
}) : []
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
function readTerminalHandoff(value) {
|
|
891
|
+
const handoff = record(value);
|
|
892
|
+
if (!handoff || typeof handoff.program !== "string" || !handoff.program.trim() || !Array.isArray(handoff.arguments) || !handoff.arguments.every((argument) => typeof argument === "string") || typeof handoff.cwd !== "string") return null;
|
|
893
|
+
return { program: handoff.program, arguments: [...handoff.arguments], cwd: handoff.cwd };
|
|
894
|
+
}
|
|
895
|
+
function readExportReceipt(value) {
|
|
896
|
+
const receipt = record(value);
|
|
897
|
+
if (!receipt || typeof receipt.targetHarness !== "string" || !["byte_lossless", "value_lossless", "semantic"].includes(receipt.fidelity) || typeof receipt.path !== "string" || !receipt.path.trim() || !Number.isInteger(receipt.files) || receipt.files < 1 || !Number.isInteger(receipt.residueCount) || receipt.residueCount < 0) return null;
|
|
898
|
+
return {
|
|
899
|
+
targetHarness: receipt.targetHarness,
|
|
900
|
+
fidelity: receipt.fidelity,
|
|
901
|
+
path: receipt.path,
|
|
902
|
+
files: receipt.files,
|
|
903
|
+
residueCount: receipt.residueCount
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
function readReductionReceipt(value) {
|
|
907
|
+
const receipt = record(value);
|
|
908
|
+
if (!receipt || typeof receipt.sourceTokens !== "number" || !Number.isFinite(receipt.sourceTokens) || typeof receipt.reducedTokens !== "number" || !Number.isFinite(receipt.reducedTokens) || receipt.sourceTokens <= receipt.reducedTokens || receipt.reducedTokens < 0 || typeof receipt.ratio !== "number" || !Number.isFinite(receipt.ratio) || receipt.ratio <= 1 || typeof receipt.sidecarId !== "string" || !receipt.sidecarId.trim() || receipt.verified !== true || receipt.reversible !== true || typeof receipt.targetHarness !== "string" || !receipt.targetHarness.trim()) return null;
|
|
909
|
+
return {
|
|
910
|
+
sourceTokens: receipt.sourceTokens,
|
|
911
|
+
reducedTokens: receipt.reducedTokens,
|
|
912
|
+
ratio: receipt.ratio,
|
|
913
|
+
sidecarId: receipt.sidecarId,
|
|
914
|
+
verified: true,
|
|
915
|
+
reversible: true,
|
|
916
|
+
targetHarness: receipt.targetHarness
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
function readInteropSettings(value) {
|
|
920
|
+
const report = record(value);
|
|
921
|
+
if (report?.schema !== "supercode.harness-interop-settings.v1" || typeof report.harness !== "string" || typeof report.revision !== "string" || !Array.isArray(report.controls) || !Array.isArray(report.advisories)) return null;
|
|
922
|
+
const controls = report.controls.slice(0, 20).flatMap((raw) => {
|
|
923
|
+
const control = record(raw);
|
|
924
|
+
if (!control || typeof control.key !== "string" || typeof control.label !== "string") return [];
|
|
925
|
+
return [{
|
|
926
|
+
key: boundedString(control.key, 200),
|
|
927
|
+
nativeKey: boundedString(control.native_key ?? control.nativeKey, 200),
|
|
928
|
+
label: boundedString(control.label, 300),
|
|
929
|
+
description: boundedString(control.description),
|
|
930
|
+
scope: ["user", "project", "managed", "command_line"].includes(control.scope) ? control.scope : "user",
|
|
931
|
+
sourcePath: boundedString(control.source_path ?? control.sourcePath, 4e3),
|
|
932
|
+
configuredValue: typeof (control.configured_value ?? control.configuredValue) === "string" ? boundedString(control.configured_value ?? control.configuredValue, 500) : null,
|
|
933
|
+
effectiveValue: typeof (control.effective_value ?? control.effectiveValue) === "string" ? boundedString(control.effective_value ?? control.effectiveValue, 500) : null,
|
|
934
|
+
effectiveKnown: (control.effective_known ?? control.effectiveKnown) === true,
|
|
935
|
+
effectiveNote: boundedString(control.effective_note ?? control.effectiveNote),
|
|
936
|
+
choices: Array.isArray(control.choices) ? control.choices.slice(0, 20).flatMap((candidate) => {
|
|
937
|
+
const choice = record(candidate);
|
|
938
|
+
return choice && typeof choice.value === "string" && typeof choice.label === "string" ? [{
|
|
939
|
+
value: boundedString(choice.value, 500),
|
|
940
|
+
label: boundedString(choice.label, 300),
|
|
941
|
+
description: boundedString(choice.description),
|
|
942
|
+
...typeof choice.risk === "string" ? { risk: boundedString(choice.risk) } : {}
|
|
943
|
+
}] : [];
|
|
944
|
+
}) : [],
|
|
945
|
+
writable: control.writable === true,
|
|
946
|
+
resettable: control.resettable === true,
|
|
947
|
+
requiresRestart: (control.requires_restart ?? control.requiresRestart) === true
|
|
948
|
+
}];
|
|
949
|
+
});
|
|
950
|
+
const advisories = report.advisories.slice(0, 20).flatMap((raw) => {
|
|
951
|
+
const advisory = record(raw);
|
|
952
|
+
const recommendation = record(advisory?.recommendation);
|
|
953
|
+
const change = record(recommendation?.change);
|
|
954
|
+
if (!advisory || !recommendation || !change || typeof advisory.code !== "string" || typeof advisory.title !== "string" || typeof advisory.setting !== "string" || typeof change.key !== "string") return [];
|
|
955
|
+
return [{
|
|
956
|
+
code: boundedString(advisory.code, 200),
|
|
957
|
+
severity: ["info", "warning", "error"].includes(advisory.severity) ? advisory.severity : "warning",
|
|
958
|
+
title: boundedString(advisory.title, 500),
|
|
959
|
+
message: boundedString(advisory.message),
|
|
960
|
+
setting: boundedString(advisory.setting, 200),
|
|
961
|
+
recommendation: {
|
|
962
|
+
label: boundedString(recommendation.label, 500),
|
|
963
|
+
description: boundedString(recommendation.description),
|
|
964
|
+
consequence: boundedString(recommendation.consequence),
|
|
965
|
+
change: {
|
|
966
|
+
key: boundedString(change.key, 200),
|
|
967
|
+
value: typeof change.value === "string" ? boundedString(change.value, 500) : null
|
|
968
|
+
},
|
|
969
|
+
command: boundedString(recommendation.command, 4e3)
|
|
970
|
+
}
|
|
971
|
+
}];
|
|
972
|
+
});
|
|
973
|
+
return {
|
|
974
|
+
schema: "supercode.harness-interop-settings.v1",
|
|
975
|
+
harness: report.harness,
|
|
976
|
+
revision: boundedString(report.revision, 500),
|
|
977
|
+
controls,
|
|
978
|
+
advisories
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
function normalizeUiState(value) {
|
|
982
|
+
const raw = record(value) ?? {};
|
|
983
|
+
const pill = record(raw.pill);
|
|
984
|
+
const history = record(raw.history);
|
|
985
|
+
const attachError = record(raw.attachError);
|
|
986
|
+
const canResume = raw.canResume === true;
|
|
987
|
+
const continuationModes = Array.isArray(raw.continuationModes) ? [...new Set(raw.continuationModes.filter((mode) => mode === "headless" || mode === "terminal"))] : canResume ? ["headless"] : [];
|
|
988
|
+
return {
|
|
989
|
+
pill: { tone: ["live", "warn", "dead"].includes(pill?.tone) ? pill.tone : "off", label: string(pill?.label, "connecting\u2026") },
|
|
990
|
+
startup: STARTUP.has(raw.startup) ? raw.startup : "connecting",
|
|
991
|
+
transcript: readTranscript(raw.transcript),
|
|
992
|
+
busy: raw.busy === true,
|
|
993
|
+
operation: typeof raw.operation === "string" ? raw.operation : null,
|
|
994
|
+
needsInput: raw.needsInput === true,
|
|
995
|
+
harness: string(raw.harness),
|
|
996
|
+
mode: MODES.has(raw.mode) ? raw.mode : "none",
|
|
997
|
+
strategy: STRATEGIES.has(raw.strategy) ? raw.strategy : null,
|
|
998
|
+
canSend: raw.canSend === true,
|
|
999
|
+
canSteer: raw.canSteer === true,
|
|
1000
|
+
canResume,
|
|
1001
|
+
supportsResume: raw.supportsResume === true,
|
|
1002
|
+
continuationModes,
|
|
1003
|
+
canBranch: raw.canBranch === true,
|
|
1004
|
+
supportsBranch: raw.supportsBranch === true,
|
|
1005
|
+
canAttach: raw.canAttach === true,
|
|
1006
|
+
supportsAttach: raw.supportsAttach === true,
|
|
1007
|
+
canDetach: raw.canDetach === true,
|
|
1008
|
+
canOpenTerminal: raw.canOpenTerminal === true,
|
|
1009
|
+
canExport: raw.canExport === true,
|
|
1010
|
+
canReduce: raw.canReduce === true,
|
|
1011
|
+
canInterrupt: raw.canInterrupt === true,
|
|
1012
|
+
canRespond: raw.canRespond === true,
|
|
1013
|
+
canConfigureSettings: raw.canConfigureSettings === true,
|
|
1014
|
+
messaging: raw.messaging === "live_peer" ? "live_peer" : null,
|
|
1015
|
+
workspace: string(raw.workspace),
|
|
1016
|
+
workspaceRef: readWorkspaceRef(raw.workspaceRef, string(raw.workspace)),
|
|
1017
|
+
participant: readParticipant(raw.participant),
|
|
1018
|
+
mirror: readMirror(raw.mirror),
|
|
1019
|
+
holder: readHolder(raw.holder),
|
|
1020
|
+
taskPlan: readTaskPlan(raw.taskPlan),
|
|
1021
|
+
semantics: readSemantics(raw.semantics),
|
|
1022
|
+
terminalHandoff: readTerminalHandoff(raw.terminalHandoff),
|
|
1023
|
+
exportBackTarget: typeof raw.exportBackTarget === "string" ? raw.exportBackTarget : null,
|
|
1024
|
+
exportReceipt: readExportReceipt(raw.exportReceipt),
|
|
1025
|
+
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
1026
|
+
interopSettings: readInteropSettings(raw.interopSettings),
|
|
1027
|
+
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
1028
|
+
harnessAuthentication: readHarnessAuthentication(raw.harnessAuthentication),
|
|
1029
|
+
error: typeof raw.error === "string" ? raw.error : null,
|
|
1030
|
+
recoverable: raw.recoverable === true,
|
|
1031
|
+
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
1032
|
+
const item = record(candidate);
|
|
1033
|
+
if (!item || typeof item.id !== "string") return [];
|
|
1034
|
+
const startable = item.startable === true;
|
|
1035
|
+
const launchModes = Array.isArray(item.launchModes) ? [...new Set(item.launchModes.filter((mode) => mode === "headless" || mode === "terminal"))] : startable ? ["headless"] : [];
|
|
1036
|
+
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes.includes("terminal") ? "terminal" : launchModes[0] ?? null;
|
|
1037
|
+
const capabilities = record(item.capabilities);
|
|
1038
|
+
return [{
|
|
1039
|
+
id: item.id,
|
|
1040
|
+
label: string(item.label, harnessDisplayName(item.id)),
|
|
1041
|
+
installed: item.installed === true,
|
|
1042
|
+
startable,
|
|
1043
|
+
reason: typeof item.reason === "string" ? boundedString(item.reason) : null,
|
|
1044
|
+
auth: ["ready", "configured", "required", "unknown"].includes(item.auth) ? item.auth : "unknown",
|
|
1045
|
+
runtime: ["ready", "degraded", "unavailable"].includes(item.runtime) ? item.runtime : startable ? "ready" : "unavailable",
|
|
1046
|
+
protocol: boundedString(item.protocol, 100),
|
|
1047
|
+
repair: typeof item.repair === "string" ? boundedString(item.repair, 4e3) : null,
|
|
1048
|
+
capabilities: {
|
|
1049
|
+
start: capabilities?.start === true,
|
|
1050
|
+
resume: capabilities?.resume === true,
|
|
1051
|
+
attach: capabilities?.attach === true,
|
|
1052
|
+
send: capabilities?.send === true,
|
|
1053
|
+
interrupt: capabilities?.interrupt === true,
|
|
1054
|
+
steer: capabilities?.steer === true,
|
|
1055
|
+
respond: capabilities?.respond === true
|
|
1056
|
+
},
|
|
1057
|
+
launchModes,
|
|
1058
|
+
preferredLaunchMode
|
|
1059
|
+
}];
|
|
1060
|
+
}) : [],
|
|
1061
|
+
history: { sessionLimit: number(history?.sessionLimit), hasMoreSessions: history?.hasMoreSessions === true, transcriptLimit: number(history?.transcriptLimit, 120), hasEarlier: history?.hasEarlier === true },
|
|
1062
|
+
savedDraft: string(raw.savedDraft),
|
|
1063
|
+
attention: Array.isArray(raw.attention) ? raw.attention.flatMap((candidate) => {
|
|
1064
|
+
const item = record(candidate);
|
|
1065
|
+
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {}, ...Number.isSafeInteger(item.unreadCount) && item.unreadCount > 0 ? { unreadCount: item.unreadCount } : {} }] : [];
|
|
1066
|
+
}) : [],
|
|
1067
|
+
sessions: readSessions(raw.sessions),
|
|
1068
|
+
subagentInspector: readSubagentInspector(raw.subagentInspector),
|
|
1069
|
+
attached: readAttached(raw.attached),
|
|
1070
|
+
owned: readAttached(raw.owned),
|
|
1071
|
+
attachError: attachError && typeof attachError.key === "string" && typeof attachError.message === "string" ? { key: attachError.key, message: attachError.message } : null,
|
|
1072
|
+
agentPackage: readAgentPackage(raw.agentPackage),
|
|
1073
|
+
contributions: normalizeContributions(raw.contributions),
|
|
1074
|
+
agentPackageError: typeof raw.agentPackageError === "string" ? boundedString(raw.agentPackageError) : null,
|
|
1075
|
+
agentPackageCapabilityState: readAgentPackageCapabilityState(raw.agentPackageCapabilityState),
|
|
1076
|
+
agentPackageCapabilityError: typeof raw.agentPackageCapabilityError === "string" ? boundedString(raw.agentPackageCapabilityError) : null
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function harnessDisplayName(id) {
|
|
1080
|
+
return HARNESS_NAMES[id] ?? id;
|
|
1081
|
+
}
|
|
1082
|
+
function sessionDisplayName(session) {
|
|
1083
|
+
const title = session.title?.trim();
|
|
1084
|
+
return title && title !== session.name ? title : session.name || "Untitled chat";
|
|
1085
|
+
}
|
|
1086
|
+
function sessionActivity(state, row) {
|
|
1087
|
+
if (row.activity && ACTIVITY_PRIORITY[row.activity] !== void 0) return row.activity;
|
|
1088
|
+
if (state.needsInput && row.active) return "needs-input";
|
|
1089
|
+
if (state.busy && row.active) return "working";
|
|
1090
|
+
if (row.runtimeStatus === "busy") return "working";
|
|
1091
|
+
const attention = state.attention.find((item) => item.key === row.key)?.kind;
|
|
1092
|
+
if (attention) return attention;
|
|
1093
|
+
if (row.runtimeStatus === "running") return "running";
|
|
1094
|
+
if (row.live || row.runtimeStatus === "idle") return "recent";
|
|
1095
|
+
return "idle";
|
|
1096
|
+
}
|
|
1097
|
+
var ACTIVITY_PRIORITY = Object.freeze({
|
|
1098
|
+
"needs-input": 70,
|
|
1099
|
+
failed: 60,
|
|
1100
|
+
working: 50,
|
|
1101
|
+
unseen: 40,
|
|
1102
|
+
finished: 30,
|
|
1103
|
+
running: 20,
|
|
1104
|
+
recent: 10,
|
|
1105
|
+
idle: 0
|
|
1106
|
+
});
|
|
1107
|
+
function activityDetail(activity, preview, pill) {
|
|
1108
|
+
if (preview) return preview;
|
|
1109
|
+
if (activity === "needs-input") return "Needs input";
|
|
1110
|
+
if (activity === "failed") return "Run failed";
|
|
1111
|
+
if (activity === "working") return "Working\u2026";
|
|
1112
|
+
if (activity === "finished") return "Finished";
|
|
1113
|
+
if (activity === "unseen") return "New reply";
|
|
1114
|
+
if (activity === "running") return "Session is running";
|
|
1115
|
+
return pill || "Agent chats";
|
|
1116
|
+
}
|
|
1117
|
+
function projectAgentActivity(value) {
|
|
1118
|
+
const state = normalizeUiState(value);
|
|
1119
|
+
const attentionByKey = new Map(state.attention.map((item) => [item.key, item]));
|
|
1120
|
+
const sessionsByKey = new Map(state.sessions.map((row) => [row.key, row]));
|
|
1121
|
+
const unreadCount = state.attention.reduce((total, item) => total + (item.unreadCount ?? 1), 0);
|
|
1122
|
+
const unreadTone = state.attention.length > 0 && state.attention.every((item) => sessionsByKey.get(item.key)?.writable) ? "attention" : "neutral";
|
|
1123
|
+
const ranked = state.sessions.map((row, index) => {
|
|
1124
|
+
const activity2 = sessionActivity(state, row);
|
|
1125
|
+
return {
|
|
1126
|
+
row,
|
|
1127
|
+
index,
|
|
1128
|
+
activity: activity2,
|
|
1129
|
+
priority: ACTIVITY_PRIORITY[activity2] ?? 0,
|
|
1130
|
+
active: row.active || row.key === state.attached?.key || row.key === state.owned?.key,
|
|
1131
|
+
updatedAt: row.previewUpdatedAt ?? row.updatedAt ?? 0
|
|
1132
|
+
};
|
|
1133
|
+
}).sort((left, right) => right.priority - left.priority || Number(right.active) - Number(left.active) || right.updatedAt - left.updatedAt || left.index - right.index);
|
|
1134
|
+
const selected = ranked[0];
|
|
1135
|
+
const fallback = state.attached ?? state.owned;
|
|
1136
|
+
const harness = selected?.row.harness ?? fallback?.harness ?? state.harness;
|
|
1137
|
+
const activity = selected?.activity ?? (state.needsInput ? "needs-input" : state.busy ? "working" : state.startup === "ready" ? "idle" : "recent");
|
|
1138
|
+
const attention = selected ? attentionByKey.get(selected.row.key) : null;
|
|
1139
|
+
const preview = selected?.row.preview || attention?.preview || "";
|
|
1140
|
+
return {
|
|
1141
|
+
harness,
|
|
1142
|
+
sessionKey: selected?.row.key ?? fallback?.key ?? null,
|
|
1143
|
+
title: selected ? sessionDisplayName(selected.row) : fallback ? sessionDisplayName(fallback) : "Agent chats",
|
|
1144
|
+
detail: activityDetail(activity, preview, state.pill.label),
|
|
1145
|
+
activity,
|
|
1146
|
+
unreadCount,
|
|
1147
|
+
unreadTone
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
function filterSessions(rows, query) {
|
|
1151
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
1152
|
+
if (!needle) return [...rows];
|
|
1153
|
+
return rows.filter((row) => [row.name, row.title, row.preview, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => typeof value === "string" && value.toLocaleLowerCase().includes(needle)));
|
|
1154
|
+
}
|
|
1155
|
+
function groupConversation(entries) {
|
|
1156
|
+
const blocks = [];
|
|
1157
|
+
for (const entry of entries) {
|
|
1158
|
+
if (entry.role !== "tool") {
|
|
1159
|
+
blocks.push({ kind: "entry", id: entry.id, entry });
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
const previous = blocks.at(-1);
|
|
1163
|
+
if (previous?.kind === "activity") previous.entries.push(entry);
|
|
1164
|
+
else blocks.push({ kind: "activity", id: `activity:${entry.id}`, entries: [entry] });
|
|
1165
|
+
}
|
|
1166
|
+
return blocks;
|
|
1167
|
+
}
|
|
1168
|
+
function toolCategory(entry) {
|
|
1169
|
+
if (TOOL_CATEGORIES.has(entry.presentation?.category)) return entry.presentation.category;
|
|
1170
|
+
const envelope = toolEnvelope(entry);
|
|
1171
|
+
const command = firstString(envelope.args, ["command", "cmd"]) || sourceString(envelope.source, ["command", "cmd"]);
|
|
1172
|
+
return classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
1173
|
+
}
|
|
1174
|
+
function toolTarget(argumentsText) {
|
|
1175
|
+
if (!argumentsText) return "";
|
|
1176
|
+
try {
|
|
1177
|
+
const args = JSON.parse(argumentsText);
|
|
1178
|
+
for (const key of ["file_path", "target_file", "path", "command", "cmd", "query", "pattern", "url"]) {
|
|
1179
|
+
if (typeof args?.[key] === "string") return args[key];
|
|
1180
|
+
}
|
|
1181
|
+
} catch {
|
|
1182
|
+
return argumentsText.length > 120 ? `${argumentsText.slice(0, 117)}\u2026` : argumentsText;
|
|
1183
|
+
}
|
|
1184
|
+
return "";
|
|
1185
|
+
}
|
|
1186
|
+
function compactToolTarget(target, workspace) {
|
|
1187
|
+
const prefix = workspace && !workspace.endsWith("/") ? `${workspace}/` : workspace;
|
|
1188
|
+
return prefix && target.startsWith(prefix) ? target.slice(prefix.length) : target;
|
|
1189
|
+
}
|
|
1190
|
+
function activitySummary(entries) {
|
|
1191
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1192
|
+
for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
|
|
1193
|
+
const failed = entries.filter((entry) => entry.status === "error").length;
|
|
1194
|
+
const pending = entries.filter((entry) => entry.status === "pending").length;
|
|
1195
|
+
if (pending) return `${entries.length} actions in progress`;
|
|
1196
|
+
if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
|
|
1197
|
+
if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
|
|
1198
|
+
const nouns = { read: ["read", "reads"], search: ["search", "searches"], edit: ["edit", "edits"], command: ["command", "commands"], test: ["test run", "test runs"], web: ["web action", "web actions"], agent: ["agent action", "agent actions"], plan: ["plan update", "plan updates"], other: ["action", "actions"] };
|
|
1199
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([category, count]) => `${count} ${nouns[category][count === 1 ? 0 : 1]}`).join(" \xB7 ");
|
|
1200
|
+
}
|
|
1201
|
+
function canContinueHere(state) {
|
|
1202
|
+
if (state.mode !== "mirror" || state.canSend) return false;
|
|
1203
|
+
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
1204
|
+
return Boolean(row) && state.canResume && row.runtimeStatus !== "running" && row.runtimeStatus !== "busy" && row.runtimeStatus !== "idle";
|
|
1205
|
+
}
|
|
1206
|
+
function operationLabel(operation) {
|
|
1207
|
+
if (!operation) return "";
|
|
1208
|
+
const labels = { discover: "Refreshing chats\u2026", observe: "Loading recent messages\u2026", attach: "Opening chat\u2026", start: "Starting new chat\u2026", resume: "Continuing here\u2026", join: "Joining live session\u2026", detach: "Detaching to read-only\u2026", branch: "Starting continuation\u2026", reduce: "Reducing context and verifying reversibility\u2026", terminal: "Preparing terminal handoff\u2026", export: "Exporting losslessly\u2026", steer: "Steering agent\u2026", interrupt: "Stopping agent\u2026", respond: "Sending response\u2026", configureHarness: "Updating harness settings\u2026", loadEarlier: "Loading earlier messages\u2026", loadSessions: "Loading more chats\u2026", refresh: "Retrying\u2026" };
|
|
1209
|
+
return labels[operation] ?? `${operation.replaceAll("_", " ")}\u2026`;
|
|
1210
|
+
}
|
|
1211
|
+
function terminalCommand(handoff) {
|
|
1212
|
+
const quote = (value) => /^[A-Za-z0-9_./:@%+=,-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
|
|
1213
|
+
return [handoff.program, ...handoff.arguments].map(quote).join(" ");
|
|
1214
|
+
}
|
|
1215
|
+
function isSendKey(event) {
|
|
1216
|
+
return event.key === "Enter" && !event.shiftKey && !event.isComposing;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
export {
|
|
1220
|
+
DEFAULT_LABELS,
|
|
1221
|
+
relativeAge,
|
|
1222
|
+
createToolPresentation,
|
|
1223
|
+
normalizeUiState,
|
|
1224
|
+
harnessDisplayName,
|
|
1225
|
+
sessionDisplayName,
|
|
1226
|
+
sessionActivity,
|
|
1227
|
+
projectAgentActivity,
|
|
1228
|
+
filterSessions,
|
|
1229
|
+
groupConversation,
|
|
1230
|
+
toolCategory,
|
|
1231
|
+
compactToolTarget,
|
|
1232
|
+
activitySummary,
|
|
1233
|
+
canContinueHere,
|
|
1234
|
+
operationLabel,
|
|
1235
|
+
terminalCommand,
|
|
1236
|
+
isSendKey
|
|
1237
|
+
};
|