@jmanuelcorral/openteam 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.es.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/certificates/graph-release-certificate.json +2 -2
  4. package/dist/certificates/graph-shadow-certificate.json +2 -2
  5. package/dist/cli/consoleServe.d.ts +1 -0
  6. package/dist/cli/consoleServe.d.ts.map +1 -1
  7. package/dist/cli.js +2120 -587
  8. package/dist/config/errors.d.ts.map +1 -1
  9. package/dist/config/historyEndpoint.d.ts +3 -0
  10. package/dist/config/historyEndpoint.d.ts.map +1 -0
  11. package/dist/config/schema.d.ts +12 -0
  12. package/dist/config/schema.d.ts.map +1 -1
  13. package/dist/console/assets.d.ts +3 -3
  14. package/dist/console/assets.d.ts.map +1 -1
  15. package/dist/console/conversation.d.ts +75 -0
  16. package/dist/console/conversation.d.ts.map +1 -0
  17. package/dist/console/historyBoundary.d.ts +6 -0
  18. package/dist/console/historyBoundary.d.ts.map +1 -0
  19. package/dist/console/inspector.d.ts +3 -0
  20. package/dist/console/inspector.d.ts.map +1 -0
  21. package/dist/console/labels.d.ts +12 -0
  22. package/dist/console/labels.d.ts.map +1 -0
  23. package/dist/console/opencodeClient.d.ts.map +1 -1
  24. package/dist/console/refresh.d.ts +3 -0
  25. package/dist/console/refresh.d.ts.map +1 -0
  26. package/dist/console/render.d.ts +7 -0
  27. package/dist/console/render.d.ts.map +1 -1
  28. package/dist/console/rootAssociation.d.ts +7 -0
  29. package/dist/console/rootAssociation.d.ts.map +1 -0
  30. package/dist/index.js +89 -7
  31. package/dist/messages/consoleDetail.d.ts +54 -0
  32. package/dist/messages/consoleDetail.d.ts.map +1 -0
  33. package/dist/messages/orchestration.d.ts +3 -0
  34. package/dist/messages/orchestration.d.ts.map +1 -1
  35. package/dist/plugin/orchestrateTool.d.ts.map +1 -1
  36. package/dist/web/configApi.d.ts +1 -1
  37. package/dist/web/configApi.d.ts.map +1 -1
  38. package/dist/web/console.d.ts.map +1 -1
  39. package/dist/web/conversationRoute.d.ts +16 -0
  40. package/dist/web/conversationRoute.d.ts.map +1 -0
  41. package/dist/web/server.d.ts +5 -0
  42. package/dist/web/server.d.ts.map +1 -1
  43. package/dist/web/start.d.ts +6 -0
  44. package/dist/web/start.d.ts.map +1 -1
  45. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { exec, execFile as execFile2 } from "node:child_process";
7
7
  import { randomUUID as randomUUID3 } from "node:crypto";
8
8
  import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
9
9
  import { createRequire as createRequire2 } from "node:module";
10
- import { dirname as dirname7, resolve as resolve9 } from "node:path";
10
+ import { dirname as dirname7, resolve as resolve10 } from "node:path";
11
11
  import { promisify as promisify2 } from "node:util";
12
12
  import {
13
13
  confirm as clackConfirm,
@@ -419,6 +419,72 @@ function migrateConfig(raw) {
419
419
  };
420
420
  }
421
421
 
422
+ // src/messages/consoleDetail.ts
423
+ var consoleDetailMessages = {
424
+ follow: "Follow new activity",
425
+ metadataOnly: "Lifecycle and telemetry stay metadata-only.",
426
+ filter: "Filter sessions",
427
+ incoming: "New activity available — show updates",
428
+ refreshError: "Live updates unavailable; retrying.",
429
+ inspectConversation: "Show messages and tool calls",
430
+ refresh: "Refresh conversation",
431
+ close: "Hide messages and tool calls",
432
+ title: "Recorded messages and tool calls",
433
+ orchestrator: "Orchestrator",
434
+ worker: "Worker",
435
+ session: "Session",
436
+ runStarted: "Run started",
437
+ sessionCreated: "Session created",
438
+ firstObserved: "First observed",
439
+ timeUnknown: "Time unknown",
440
+ utc: "UTC",
441
+ technicalID: "Technical ID",
442
+ currentMetadata: "Current opencode title; not historical metadata",
443
+ partialMetadata: "Some current session titles are unavailable or outside the bounded batch; fallback labels remain.",
444
+ rootCurrent: "Current whole orchestrator session; may contain multiple batches. Not a historical or batch-only transcript.",
445
+ recovered: "Read-only association verified from current opencode history; not an immutable lifecycle event.",
446
+ rootUnlinked: "Orchestrator session not recorded. Reveal to try a bounded, read-only relationship search.",
447
+ rootUnavailable: "Orchestrator session unavailable: no unique, verifiable relationship was found in local history.",
448
+ rootAmbiguous: "Orchestrator session unavailable: conflicting or copied relationships are ambiguous.",
449
+ searchIncomplete: "Orchestrator association search incomplete or exceeded its bounded budget. No session was guessed.",
450
+ prompt: "Received prompts",
451
+ assistant: "Visible agent responses",
452
+ tools: "Tool calls ({count})",
453
+ noPrompts: "No received prompt text retained.",
454
+ noOutput: "No visible agent response text retained.",
455
+ noTools: "No tool calls retained.",
456
+ arguments: "Arguments",
457
+ result: "Result",
458
+ loading: "Loading local conversation…",
459
+ current: "Present-day session, not a timeline reconstruction. May include later messages and tools. Refresh explicitly for updates.",
460
+ historical: "Historical cursor: conversation content is hidden to avoid showing future mutable text. Return to live before revealing this operation.",
461
+ disabled: "Content is disabled. Set console.sessionHistory.contentEnabled to true in .opencode/openteam.json and restart the Console. Then reveal content here.",
462
+ unavailable: "Conversation unavailable. Start an operator-owned local opencode serve against the same workspace and user history, configure console.sessionHistory.endpoint, then retry. No inference was requested.",
463
+ empty: "No readable user messages, assistant output or tool calls remain in this session.",
464
+ invalid: "This attempt has no recorded session in the selected run, or its history is incomplete.",
465
+ unauthorized: "Conversation access denied.",
466
+ pending: "Still streaming or unavailable.",
467
+ compacted: "Tool result was compacted by opencode.",
468
+ invalidEndpoint: "Expected a loopback HTTP origin without credentials, path, query or fragment.",
469
+ readFailed: "Local session history could not be read.",
470
+ oversized: "Conversation exceeds the local size limit (4 MiB). No content was loaded.",
471
+ truncated: "Conversation display is truncated by local safety limits; omitted content is not empty history.",
472
+ truncatedMarker: `
473
+ [truncated]`,
474
+ terminalGap: "Live collection was interrupted; events during the gap are unavailable. This is not complete session history.",
475
+ terminalTrimmed: "Older live output was discarded by the local display limit."
476
+ };
477
+
478
+ // src/config/historyEndpoint.ts
479
+ function isLocalHistoryEndpoint(value) {
480
+ try {
481
+ const url = new URL(value);
482
+ return url.protocol === "http:" && ["127.0.0.1", "[::1]"].includes(url.hostname) && !url.username && !url.password && url.pathname === "/" && !url.search && !url.hash;
483
+ } catch {
484
+ return false;
485
+ }
486
+ }
487
+
422
488
  // src/config/schema.ts
423
489
  var ModelRefSchema = z2.object({
424
490
  providerID: z2.string().min(1),
@@ -478,6 +544,10 @@ var ConsoleConfigSchema = z2.object({
478
544
  recentRoutes: z2.number().int().positive().default(50),
479
545
  openBrowser: z2.boolean().default(false),
480
546
  remoteStorage: z2.boolean().default(false),
547
+ sessionHistory: z2.object({
548
+ contentEnabled: z2.boolean().default(false),
549
+ endpoint: z2.string().refine(isLocalHistoryEndpoint, consoleDetailMessages.invalidEndpoint).optional()
550
+ }).strict().optional(),
481
551
  terminal: z2.object({
482
552
  enabled: z2.boolean().default(true),
483
553
  pty: z2.boolean().optional()
@@ -815,11 +885,638 @@ function resolveMemorySemantic(config) {
815
885
  return config.memory?.semantic ?? MemorySemanticSchema.parse(undefined);
816
886
  }
817
887
 
888
+ // src/console/conversation.ts
889
+ import { isAbsolute, normalize, parse, resolve, sep } from "node:path";
890
+ import { createOpencodeClient } from "@opencode-ai/sdk";
891
+ import { z as z4 } from "zod";
892
+
893
+ // src/console/historyBoundary.ts
894
+ function only(keys) {
895
+ return (value) => {
896
+ if (typeof value !== "object" || value === null || Array.isArray(value))
897
+ return value;
898
+ const record = value;
899
+ return Object.fromEntries(keys.filter((key) => Object.hasOwn(record, key)).map((key) => [key, record[key]]));
900
+ };
901
+ }
902
+
903
+ class AssociationError extends Error {
904
+ reason;
905
+ constructor(reason) {
906
+ super(reason === "ambiguous" ? consoleDetailMessages.rootAmbiguous : reason === "incomplete" ? consoleDetailMessages.searchIncomplete : consoleDetailMessages.rootUnavailable);
907
+ this.reason = reason;
908
+ }
909
+ }
910
+
911
+ // src/console/labels.ts
912
+ function labelFormatters(msg) {
913
+ function boundedTitle(value) {
914
+ if (typeof value !== "string")
915
+ return;
916
+ const title = value.replace(/\p{Cc}|[\u202a-\u202e\u2066-\u2069]/gu, " ").replace(/\s+/g, " ").trim().slice(0, 160);
917
+ return title || undefined;
918
+ }
919
+ function utcTime(value) {
920
+ if (typeof value !== "number" || !Number.isFinite(value))
921
+ return msg.timeUnknown;
922
+ const date = new Date(value);
923
+ return Number.isNaN(date.getTime()) ? msg.timeUnknown : `${date.toISOString().slice(0, -5).replace("T", " ")} ${msg.utc}`;
924
+ }
925
+ function runLabel(run, title) {
926
+ return `${boundedTitle(title) ?? (run.executionAuthority === "coordinator" ? msg.orchestrator : msg.worker)} · ${msg.runStarted}: ${utcTime(run.startedAt)} · ${run.runID}`;
927
+ }
928
+ return { boundedTitle, utcTime, runLabel };
929
+ }
930
+ var { boundedTitle, utcTime, runLabel } = labelFormatters(consoleDetailMessages);
931
+ var LABELS_CLIENT_JS = `
932
+ var consoleLabels=(function(){
933
+ var msg=${JSON.stringify(consoleDetailMessages)};
934
+ var formatters=(${labelFormatters.toString()})(msg);
935
+ var boundedTitle=formatters.boundedTitle,utcTime=formatters.utcTime,runLabel=formatters.runLabel;
936
+ var sessions=new Map(),roots=new Map(),request=null,lastRun=null,lastRead=0;
937
+ function update(data,run){
938
+ (data||[]).slice(0,64).forEach(function(session){
939
+ if(typeof session.id!=='string'||session.id.length>256){return}
940
+ sessions.delete(session.id);sessions.set(session.id,{id:session.id,title:boundedTitle(session.title),createdAt:session.createdAt});
941
+ if(sessions.size>128){sessions.delete(sessions.keys().next().value)}
942
+ if(run){roots.set(run,session.id);if(roots.size>128){roots.delete(roots.keys().next().value)}}
943
+ });
944
+ apply();
945
+ }
946
+ function apply(){
947
+ document.querySelectorAll('[data-session-name]').forEach(function(node){
948
+ var label=sessions.get(node.getAttribute('data-session-name'));
949
+ if(!node.hasAttribute('data-label-fallback')){node.setAttribute('data-label-fallback',node.textContent)}
950
+ if(label){var text=label.title||node.getAttribute('data-label-fallback');if(node.textContent!==text){node.textContent=text}if(node.title!==msg.currentMetadata){node.title=msg.currentMetadata}}
951
+ });
952
+ document.querySelectorAll('[data-session-time]').forEach(function(node){
953
+ var label=sessions.get(node.getAttribute('data-session-time'));
954
+ if(!node.hasAttribute('data-label-fallback')){node.setAttribute('data-label-fallback',node.textContent)}
955
+ if(label){var text=utcTime(label.createdAt)!==msg.timeUnknown?msg.sessionCreated+': '+utcTime(label.createdAt):node.getAttribute('data-label-fallback');if(node.textContent!==text){node.textContent=text}}
956
+ });
957
+ document.querySelectorAll('[data-run-name]').forEach(function(node){
958
+ var id=roots.get(node.getAttribute('data-run-name')),label=sessions.get(id);
959
+ if(label&&label.title){if(node.textContent!==label.title){node.textContent=label.title}if(node.title!==msg.currentMetadata){node.title=msg.currentMetadata}}
960
+ });
961
+ document.querySelectorAll('[data-lifecycle-run-select] option').forEach(function(option){
962
+ var session=sessions.get(option.getAttribute('data-run-session')||roots.get(option.value));
963
+ var raw=option.getAttribute('data-run-started');
964
+ var text=runLabel({runID:option.value,startedAt:raw?Number(raw):null,executionAuthority:option.getAttribute('data-run-authority')},session&&session.title);
965
+ if(option.textContent!==text){option.textContent=text}
966
+ });
967
+ }
968
+ function load(){
969
+ apply();
970
+ var mount=document.getElementById('lifecycle-timeline-mount');
971
+ if(!mount||mount.getAttribute('data-conversation-transition')==='1'||mount.getAttribute('data-conversation-cursor')){return}
972
+ var run=mount.getAttribute('data-lifecycle-run')||null;
973
+ if(lastRead&&lastRun===run&&Date.now()-lastRead<30000){return}
974
+ if(request){request.abort()}
975
+ lastRun=run;lastRead=Date.now();
976
+ var controller=new AbortController();request=controller;
977
+ var timeout=setTimeout(function(){controller.abort()},15000);
978
+ var query=new URLSearchParams({diagnostic:'1',token:document.documentElement.getAttribute('data-token')||''});
979
+ if(run){query.set('run',run)}
980
+ fetch('/api/graph/session-labels?'+query,{signal:controller.signal,cache:'no-store'}).then(function(r){return r.json()}).then(function(data){
981
+ if(request===controller&&data.kind==='labels'&&data.runID===run){update(data.sessions)}
982
+ }).catch(function(){}).finally(function(){clearTimeout(timeout);if(request===controller){request=null}});
983
+ }
984
+ document.addEventListener('conversation-tree-committed',load);
985
+ document.addEventListener('console-session-metadata',function(event){update([event.detail.session],event.detail.target==='root'?event.detail.runID:null)});
986
+ window.addEventListener('pagehide',function(){if(request){request.abort()}});
987
+ return {apply:apply,refresh:load,runLabel:runLabel,utcTime:utcTime};
988
+ })();
989
+ `;
990
+
991
+ // src/console/rootAssociation.ts
992
+ import { z as z3 } from "zod";
993
+ var Identity = z3.object({
994
+ id: z3.string().min(1).max(256),
995
+ sessionID: z3.string().min(1).max(256)
996
+ }).strict();
997
+ var ObjectField = z3.custom((value) => typeof value === "object" && value !== null && !Array.isArray(value));
998
+ var Row = z3.preprocess(only(["info", "parts"]), z3.object({
999
+ info: z3.preprocess(only(["id", "sessionID", "role"]), Identity.extend({ role: z3.enum(["user", "assistant"]) })),
1000
+ parts: z3.array(z3.unknown()).max(1000)
1001
+ }).strict());
1002
+ var ResultPart = z3.preprocess(only(["id", "sessionID", "messageID", "type", "tool", "callID", "state"]), Identity.extend({
1003
+ messageID: z3.string(),
1004
+ type: z3.literal("tool"),
1005
+ tool: z3.literal("openteam-orchestrate"),
1006
+ callID: z3.string().min(1),
1007
+ state: z3.preprocess(only(["status", "input", "output", "title", "metadata", "time"]), z3.object({
1008
+ status: z3.literal("completed"),
1009
+ input: ObjectField,
1010
+ output: z3.string().max(262144),
1011
+ title: z3.string(),
1012
+ metadata: ObjectField,
1013
+ time: z3.preprocess(only(["start", "end", "compacted"]), z3.object({
1014
+ start: z3.number().finite(),
1015
+ end: z3.number().finite(),
1016
+ compacted: z3.number().finite().optional()
1017
+ }).strict())
1018
+ }).strict())
1019
+ }));
1020
+ function references(raw, sessionID, expected) {
1021
+ const rows = z3.array(Row).max(2000).parse(raw);
1022
+ let matched = false;
1023
+ for (const row of rows) {
1024
+ if (row.info.sessionID !== sessionID)
1025
+ throw new AssociationError("incomplete");
1026
+ for (const rawPart of row.parts) {
1027
+ const part = z3.object({ type: z3.string() }).strict().parse(only(["type"])(rawPart));
1028
+ if (part.type !== "tool")
1029
+ continue;
1030
+ const identity = Identity.extend({
1031
+ messageID: z3.string(),
1032
+ tool: z3.string()
1033
+ }).parse(only(["id", "sessionID", "messageID", "tool"])(rawPart));
1034
+ if (identity.sessionID !== sessionID || identity.messageID !== row.info.id)
1035
+ throw new AssociationError("incomplete");
1036
+ if (row.info.role !== "assistant" || identity.tool !== "openteam-orchestrate")
1037
+ continue;
1038
+ const status = z3.object({
1039
+ state: z3.preprocess(only(["status"]), z3.object({
1040
+ status: z3.enum(["pending", "running", "completed", "error"])
1041
+ }).strict())
1042
+ }).strict().parse(only(["state"])(rawPart)).state.status;
1043
+ if (status !== "completed")
1044
+ continue;
1045
+ const parsed = ResultPart.safeParse(rawPart);
1046
+ if (!parsed.success || parsed.data.state.time?.compacted !== undefined)
1047
+ throw new AssociationError("incomplete");
1048
+ const lines = parsed.data.state.output.split(/\r?\n/);
1049
+ const heading = /^orchestration (?:completed|incomplete) \((\d+) role\(s\)\):$/.exec(lines[0] ?? "");
1050
+ if (!heading)
1051
+ continue;
1052
+ const count = Number(heading[1]);
1053
+ if (count < expected.length || count > 64)
1054
+ continue;
1055
+ const actual = lines.slice(1, 1 + count).map((line) => {
1056
+ const result = /^([A-Za-z0-9_-]+): (ok|failed) → (\S+)(?: \(session ([^\s()]+)\))?(?: \[report: [^\r\n]*\])?(?: — [^\r\n]*)?$/.exec(line);
1057
+ return !result ? undefined : result[4] ? `${result[1]}\x00${result[2]}\x00${result[3]}\x00${result[4]}` : null;
1058
+ });
1059
+ if (actual.length !== count || actual.some((row2) => row2 === undefined))
1060
+ continue;
1061
+ const sessionRows = actual.filter((row2) => row2 !== null);
1062
+ if (sessionRows.length === expected.length && expected.every((key) => sessionRows.filter((item) => item === key).length === 1))
1063
+ matched = true;
1064
+ }
1065
+ }
1066
+ return matched;
1067
+ }
1068
+ async function recoverRootSession(port, projection) {
1069
+ const workers = projection.operations.filter((op) => op.parentOperationID === projection.rootOperationID && op.kind === "role");
1070
+ const last = workers.flatMap((op) => {
1071
+ const attempt = op.attempts.at(-1);
1072
+ return attempt?.sessionID ? [{ op, attempt, sessionID: attempt.sessionID }] : [];
1073
+ });
1074
+ if (!last.length)
1075
+ throw new AssociationError("unavailable");
1076
+ if (last.length > 32)
1077
+ throw new AssociationError("incomplete");
1078
+ const children = [];
1079
+ for (const { sessionID } of last)
1080
+ children.push(await port.get(sessionID));
1081
+ const first = children[0];
1082
+ if (!first)
1083
+ throw new AssociationError("unavailable");
1084
+ const projectID = first.projectID;
1085
+ if (children.some((child) => child.projectID !== projectID))
1086
+ throw new AssociationError("ambiguous");
1087
+ const parents = new Set(children.flatMap((child) => child.parentID ? [child.parentID] : []));
1088
+ if (parents.size > 1)
1089
+ throw new AssociationError("ambiguous");
1090
+ if (first.parentID && children.every((child) => child.parentID)) {
1091
+ const session = await port.get(first.parentID);
1092
+ if (session.projectID !== projectID || children.some((child) => child.id === session.id))
1093
+ throw new AssociationError("ambiguous");
1094
+ return { session, association: "sdk-parent" };
1095
+ }
1096
+ const expected = last.map(({ op, attempt }) => {
1097
+ if (!attempt?.model || !["succeeded", "failed"].includes(attempt.state))
1098
+ throw new AssociationError("unavailable");
1099
+ return `${op.roleID}\x00${attempt.state === "succeeded" ? "ok" : "failed"}\x00${attempt.model.providerID}/${attempt.model.modelID}\x00${attempt.sessionID}`;
1100
+ });
1101
+ let match;
1102
+ try {
1103
+ const candidates = await port.primaries(projectID);
1104
+ for (const listed of candidates) {
1105
+ const session = await port.get(listed.id);
1106
+ if (session.projectID !== projectID || session.parentID !== listed.parentID)
1107
+ throw new AssociationError("incomplete");
1108
+ if (await references(await port.messages(session.id), session.id, expected)) {
1109
+ if (match)
1110
+ throw new AssociationError("ambiguous");
1111
+ match = session;
1112
+ }
1113
+ }
1114
+ } catch (error) {
1115
+ if (error instanceof AssociationError)
1116
+ throw error;
1117
+ throw new AssociationError("incomplete");
1118
+ }
1119
+ if (!match)
1120
+ throw new AssociationError("unavailable");
1121
+ if (parents.size && !parents.has(match.id))
1122
+ throw new AssociationError("ambiguous");
1123
+ return { session: match, association: "tool-result" };
1124
+ }
1125
+
1126
+ // src/console/conversation.ts
1127
+ var CONVERSATION_LIMITS = {
1128
+ bytes: 4 * 1024 * 1024,
1129
+ messages: 200,
1130
+ parts: 100,
1131
+ tools: 200,
1132
+ fieldChars: 16384,
1133
+ totalChars: 262144,
1134
+ argumentDepth: 8,
1135
+ argumentEntries: 512
1136
+ };
1137
+ var SESSION_HISTORY_LIMITS = {
1138
+ bytes: 32 * 1024 * 1024,
1139
+ timeoutMs: 1e4,
1140
+ labels: 64
1141
+ };
1142
+ var SESSION_LIST_WINDOW = 100;
1143
+
1144
+ class ConversationTooLargeError extends Error {
1145
+ constructor() {
1146
+ super(consoleDetailMessages.oversized);
1147
+ }
1148
+ }
1149
+ var Info = z4.preprocess(only(["id", "sessionID", "role", "time"]), z4.object({
1150
+ id: z4.string(),
1151
+ sessionID: z4.string(),
1152
+ role: z4.enum(["user", "assistant"]),
1153
+ time: z4.preprocess(only(["created", "completed"]), z4.object({
1154
+ created: z4.number().finite(),
1155
+ completed: z4.number().finite().optional()
1156
+ }).strict())
1157
+ }).strict());
1158
+ var PartIdentity = z4.object({
1159
+ id: z4.string(),
1160
+ messageID: z4.string(),
1161
+ sessionID: z4.string()
1162
+ }).strict();
1163
+ var Text = PartIdentity.extend({
1164
+ type: z4.literal("text"),
1165
+ text: z4.string(),
1166
+ ignored: z4.boolean().optional()
1167
+ });
1168
+ var Tool = PartIdentity.extend({
1169
+ type: z4.literal("tool"),
1170
+ callID: z4.string(),
1171
+ tool: z4.string(),
1172
+ state: z4.preprocess(only(["status", "input", "output", "error", "time"]), z4.object({
1173
+ status: z4.enum(["pending", "running", "completed", "error"]),
1174
+ input: z4.unknown().refine((value) => typeof value === "object" && value !== null && !Array.isArray(value)),
1175
+ output: z4.string().optional(),
1176
+ error: z4.string().optional(),
1177
+ time: z4.preprocess(only(["start", "end", "compacted"]), z4.object({
1178
+ start: z4.number().finite(),
1179
+ end: z4.number().finite().optional(),
1180
+ compacted: z4.number().finite().optional()
1181
+ }).strict()).optional()
1182
+ }).strict())
1183
+ });
1184
+ var Message = z4.preprocess(only(["info", "parts"]), z4.object({ info: Info, parts: z4.custom(Array.isArray) }).strict());
1185
+ function projectConversation(raw, sessionID) {
1186
+ if (!Array.isArray(raw))
1187
+ throw new Error(consoleDetailMessages.readFailed);
1188
+ const limits = CONVERSATION_LIMITS;
1189
+ let truncated = raw.length > limits.messages;
1190
+ let remaining = limits.totalChars;
1191
+ let toolsRemaining = limits.tools;
1192
+ function text(value) {
1193
+ const length = Math.min(value.length, limits.fieldChars, remaining);
1194
+ remaining -= length;
1195
+ if (length === value.length)
1196
+ return value;
1197
+ truncated = true;
1198
+ return value.slice(0, length) + consoleDetailMessages.truncatedMarker;
1199
+ }
1200
+ function argumentsText(input) {
1201
+ let entries = limits.argumentEntries;
1202
+ const seen = new Set;
1203
+ function bounded(value, depth) {
1204
+ if (typeof value === "string")
1205
+ return text(value);
1206
+ if (value === null || typeof value === "boolean" || typeof value === "number")
1207
+ return value;
1208
+ if (typeof value !== "object")
1209
+ return null;
1210
+ if (depth >= limits.argumentDepth || entries <= 0 || seen.has(value)) {
1211
+ truncated = true;
1212
+ return consoleDetailMessages.truncatedMarker;
1213
+ }
1214
+ seen.add(value);
1215
+ const result = Object.create(null);
1216
+ const array = [];
1217
+ for (const key in value) {
1218
+ if (!Object.hasOwn(value, key))
1219
+ continue;
1220
+ if (entries-- <= 0 || remaining <= 0) {
1221
+ truncated = true;
1222
+ break;
1223
+ }
1224
+ const child = bounded(value[key], depth + 1);
1225
+ if (Array.isArray(value))
1226
+ array.push(child);
1227
+ else
1228
+ result[text(key)] = child;
1229
+ }
1230
+ return Array.isArray(value) ? array : result;
1231
+ }
1232
+ return text(JSON.stringify(bounded(input, 0), null, 2));
1233
+ }
1234
+ const messages = [];
1235
+ for (const rawRow of raw.slice(0, limits.messages)) {
1236
+ if (remaining <= 0) {
1237
+ truncated = true;
1238
+ break;
1239
+ }
1240
+ const row = Message.parse(rawRow);
1241
+ if (row.info.sessionID !== sessionID)
1242
+ throw new Error(consoleDetailMessages.readFailed);
1243
+ const message = {
1244
+ id: text(row.info.id),
1245
+ role: row.info.role,
1246
+ createdAt: row.info.time.created,
1247
+ ...row.info.time.completed !== undefined ? { completedAt: row.info.time.completed } : {},
1248
+ text: [],
1249
+ tools: []
1250
+ };
1251
+ if (row.parts.length > limits.parts)
1252
+ truncated = true;
1253
+ for (const rawPart of row.parts.slice(0, limits.parts)) {
1254
+ if (remaining <= 0) {
1255
+ truncated = true;
1256
+ break;
1257
+ }
1258
+ const kind = rawPart?.type;
1259
+ if (kind !== "text" && kind !== "tool")
1260
+ continue;
1261
+ const part = kind === "text" ? Text.parse(only(["id", "messageID", "sessionID", "type", "text", "ignored"])(rawPart)) : Tool.parse(only([
1262
+ "id",
1263
+ "messageID",
1264
+ "sessionID",
1265
+ "type",
1266
+ "callID",
1267
+ "tool",
1268
+ "state"
1269
+ ])(rawPart));
1270
+ if (part.sessionID !== sessionID || part.messageID !== row.info.id)
1271
+ throw new Error(consoleDetailMessages.readFailed);
1272
+ if (part.type === "text") {
1273
+ if (!part.ignored)
1274
+ message.text.push(text(part.text));
1275
+ } else {
1276
+ if (toolsRemaining-- <= 0) {
1277
+ truncated = true;
1278
+ continue;
1279
+ }
1280
+ const state = part.state;
1281
+ message.tools.push({
1282
+ id: text(part.callID),
1283
+ name: text(part.tool),
1284
+ status: state.status,
1285
+ arguments: argumentsText(state.input),
1286
+ ...state.time !== undefined ? { startedAt: state.time.start } : {},
1287
+ ...state.time?.end !== undefined ? { endedAt: state.time.end } : {},
1288
+ ...state.time?.compacted !== undefined ? { result: consoleDetailMessages.compacted } : state.status === "completed" && state.output !== undefined ? { result: text(state.output) } : state.status === "error" && state.error !== undefined ? { result: text(state.error) } : {}
1289
+ });
1290
+ }
1291
+ }
1292
+ if (message.text.length || message.tools.length)
1293
+ messages.push(message);
1294
+ }
1295
+ return {
1296
+ ...truncated ? { truncated: true } : {},
1297
+ messages: messages.sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id))
1298
+ };
1299
+ }
1300
+ var SessionScope = z4.preprocess(only(["id", "directory", "projectID", "parentID", "title", "time"]), z4.object({
1301
+ id: z4.string().min(1).max(256),
1302
+ directory: z4.string().min(1),
1303
+ projectID: z4.string().min(1),
1304
+ parentID: z4.string().min(1).max(256).optional(),
1305
+ title: z4.unknown().optional(),
1306
+ time: z4.unknown().optional()
1307
+ }).strict());
1308
+ function workspaceKey(directory) {
1309
+ if (!isAbsolute(directory) || directory.includes("\x00"))
1310
+ throw new Error(consoleDetailMessages.readFailed);
1311
+ const normalized = normalize(directory);
1312
+ const root = parse(normalized).root;
1313
+ const key = normalized.length > root.length && normalized.endsWith(sep) ? normalized.slice(0, -1) : normalized;
1314
+ return process.platform === "win32" ? key.toLowerCase() : key;
1315
+ }
1316
+ async function boundedResponse(response, controller, budget) {
1317
+ const fail = async (error) => {
1318
+ await response.body?.cancel().catch(() => {});
1319
+ controller.abort();
1320
+ throw error;
1321
+ };
1322
+ if (!response.ok || !response.body) {
1323
+ await response.body?.cancel().catch(() => {});
1324
+ throw new Error(consoleDetailMessages.readFailed);
1325
+ }
1326
+ if (Number(response.headers.get("content-length")) > CONVERSATION_LIMITS.bytes)
1327
+ return fail(new ConversationTooLargeError);
1328
+ const reader = response.body.getReader();
1329
+ const cancel = () => {
1330
+ reader.cancel().catch(() => {});
1331
+ };
1332
+ controller.signal.addEventListener("abort", cancel, { once: true });
1333
+ const bytes = new Uint8Array(CONVERSATION_LIMITS.bytes);
1334
+ let length = 0;
1335
+ try {
1336
+ while (true) {
1337
+ controller.signal.throwIfAborted();
1338
+ const chunk = await reader.read();
1339
+ if (chunk.done)
1340
+ break;
1341
+ if (length + chunk.value.byteLength > CONVERSATION_LIMITS.bytes)
1342
+ throw new ConversationTooLargeError;
1343
+ budget.remaining -= chunk.value.byteLength;
1344
+ if (budget.remaining < 0)
1345
+ throw new AssociationError("incomplete");
1346
+ bytes.set(chunk.value, length);
1347
+ length += chunk.value.byteLength;
1348
+ }
1349
+ controller.signal.throwIfAborted();
1350
+ const headers = new Headers(response.headers);
1351
+ headers.delete("content-length");
1352
+ headers.delete("content-encoding");
1353
+ return new Response(bytes.subarray(0, length), {
1354
+ status: response.status,
1355
+ headers
1356
+ });
1357
+ } catch (error) {
1358
+ await reader.cancel().catch(() => {});
1359
+ controller.abort();
1360
+ throw error;
1361
+ } finally {
1362
+ controller.signal.removeEventListener("abort", cancel);
1363
+ reader.releaseLock();
1364
+ }
1365
+ }
1366
+ function createConversationReader(deps) {
1367
+ const directory = resolve(deps.directory);
1368
+ const labels = new Map;
1369
+ async function withHistory(endpoint, signal, work, options) {
1370
+ if (!isLocalHistoryEndpoint(endpoint))
1371
+ throw new Error(consoleDetailMessages.readFailed);
1372
+ const controller = new AbortController;
1373
+ const abort = () => controller.abort();
1374
+ signal?.addEventListener("abort", abort, { once: true });
1375
+ if (signal?.aborted)
1376
+ controller.abort();
1377
+ const timeout = setTimeout(() => controller.abort(), Math.min(options?.timeoutMs ?? SESSION_HISTORY_LIMITS.timeoutMs, SESSION_HISTORY_LIMITS.timeoutMs));
1378
+ const budget = options?.budget ?? {
1379
+ remaining: SESSION_HISTORY_LIMITS.bytes
1380
+ };
1381
+ try {
1382
+ let scoped = function(raw) {
1383
+ const session = SessionScope.parse(raw);
1384
+ if (workspaceKey(session.directory) !== workspaceKey(directory))
1385
+ throw new Error(consoleDetailMessages.readFailed);
1386
+ const time = z4.preprocess(only(["created"]), z4.object({ created: z4.number().finite().min(0).max(8640000000000000) }).strict()).safeParse(session.time);
1387
+ const title = boundedTitle(session.title);
1388
+ return {
1389
+ id: session.id,
1390
+ directory: session.directory,
1391
+ projectID: session.projectID,
1392
+ ...session.parentID === undefined ? {} : { parentID: session.parentID },
1393
+ label: {
1394
+ id: session.id,
1395
+ ...title ? { title } : {},
1396
+ ...time.success ? { createdAt: time.data.created } : {}
1397
+ }
1398
+ };
1399
+ };
1400
+ const client = createOpencodeClient({
1401
+ baseUrl: endpoint,
1402
+ directory,
1403
+ ...deps.password ? {
1404
+ headers: {
1405
+ authorization: `Basic ${Buffer.from(`opencode:${deps.password}`).toString("base64")}`
1406
+ }
1407
+ } : {},
1408
+ fetch: async (request) => {
1409
+ controller.signal.throwIfAborted();
1410
+ if (budget.remaining <= 0)
1411
+ throw new AssociationError("incomplete");
1412
+ const response = await (deps.fetch ?? fetch)(request, {
1413
+ signal: controller.signal,
1414
+ redirect: "error"
1415
+ });
1416
+ return boundedResponse(response, controller, budget);
1417
+ }
1418
+ });
1419
+ const verified = new Map;
1420
+ return await work({
1421
+ get: async (id) => {
1422
+ const result = await client.session.get({ path: { id } });
1423
+ if (!result.response.ok || result.error !== undefined)
1424
+ throw new Error(consoleDetailMessages.readFailed);
1425
+ const session = scoped(result.data);
1426
+ if (session.id !== id)
1427
+ throw new Error(consoleDetailMessages.readFailed);
1428
+ verified.set(id, session);
1429
+ const key = JSON.stringify([endpoint, id]);
1430
+ labels.delete(key);
1431
+ labels.set(key, { at: Date.now(), label: session.label });
1432
+ const oldest = labels.keys().next().value;
1433
+ if (labels.size > 128 && oldest !== undefined)
1434
+ labels.delete(oldest);
1435
+ return session;
1436
+ },
1437
+ messages: async (id) => {
1438
+ if (!verified.has(id))
1439
+ throw new Error(consoleDetailMessages.readFailed);
1440
+ const result = await client.session.messages({ path: { id } });
1441
+ if (!result.response.ok || result.error !== undefined)
1442
+ throw new Error(consoleDetailMessages.readFailed);
1443
+ return result.data;
1444
+ },
1445
+ primaries: async (projectID) => {
1446
+ const result = await client.session.list({ query: { directory } });
1447
+ if (!result.response.ok || result.error !== undefined || !Array.isArray(result.data) || result.data.length >= SESSION_LIST_WINDOW)
1448
+ throw new AssociationError("incomplete");
1449
+ const candidates = [];
1450
+ const ids = new Set;
1451
+ for (const raw of result.data) {
1452
+ const session = SessionScope.parse(raw);
1453
+ if (workspaceKey(session.directory) !== workspaceKey(directory) || session.projectID !== projectID || session.parentID)
1454
+ continue;
1455
+ if (ids.has(session.id))
1456
+ throw new AssociationError("ambiguous");
1457
+ ids.add(session.id);
1458
+ candidates.push(scoped(raw));
1459
+ }
1460
+ if (candidates.length > 64)
1461
+ throw new AssociationError("incomplete");
1462
+ return candidates;
1463
+ }
1464
+ }, controller.signal);
1465
+ } catch (error) {
1466
+ if (error instanceof ConversationTooLargeError || error instanceof AssociationError)
1467
+ throw error;
1468
+ throw new Error(consoleDetailMessages.readFailed);
1469
+ } finally {
1470
+ clearTimeout(timeout);
1471
+ signal?.removeEventListener("abort", abort);
1472
+ }
1473
+ }
1474
+ const read = async (endpoint, sessionID, signal) => withHistory(endpoint, signal, async (port) => {
1475
+ const session = await port.get(sessionID);
1476
+ return {
1477
+ ...projectConversation(await port.messages(sessionID), sessionID),
1478
+ session: session.label
1479
+ };
1480
+ });
1481
+ read.root = (endpoint, projection, signal) => withHistory(endpoint, signal, async (port) => {
1482
+ const recovered = await recoverRootSession(port, projection);
1483
+ return {
1484
+ ...projectConversation(await port.messages(recovered.session.id), recovered.session.id),
1485
+ session: recovered.session.label,
1486
+ association: recovered.association
1487
+ };
1488
+ });
1489
+ read.labels = (endpoint, ids, signal, options) => withHistory(endpoint, signal, async (port, historySignal) => {
1490
+ if (ids.length > SESSION_HISTORY_LIMITS.labels)
1491
+ throw new Error(consoleDetailMessages.readFailed);
1492
+ const result = [];
1493
+ for (const id of new Set(ids)) {
1494
+ controllerCheck(signal);
1495
+ if (historySignal.aborted)
1496
+ break;
1497
+ const cached = labels.get(JSON.stringify([endpoint, id]));
1498
+ if (cached && Date.now() - cached.at < 30000)
1499
+ result.push(cached.label);
1500
+ else {
1501
+ try {
1502
+ result.push((await port.get(id)).label);
1503
+ } catch {}
1504
+ }
1505
+ }
1506
+ controllerCheck(signal);
1507
+ return result;
1508
+ }, options);
1509
+ return read;
1510
+ }
1511
+ function controllerCheck(signal) {
1512
+ signal?.throwIfAborted();
1513
+ }
1514
+
818
1515
  // src/console/protocol.ts
819
- import { z as z7 } from "zod";
1516
+ import { z as z9 } from "zod";
820
1517
 
821
1518
  // src/orchestrator/coordinator.ts
822
- import { z as z6 } from "zod";
1519
+ import { z as z8 } from "zod";
823
1520
 
824
1521
  // src/context/redaction.ts
825
1522
  import { createHash } from "node:crypto";
@@ -919,41 +1616,41 @@ function splitVirtualPath(path) {
919
1616
  }
920
1617
 
921
1618
  // src/telemetry/events.ts
922
- import { z as z4 } from "zod";
1619
+ import { z as z6 } from "zod";
923
1620
 
924
1621
  // src/capabilities/types.ts
925
- import { z as z3 } from "zod";
926
- var CapabilityTierSchema = z3.union([
927
- z3.literal(0),
928
- z3.literal(1),
929
- z3.literal(2),
930
- z3.literal(3),
931
- z3.literal(4),
932
- z3.literal(5)
1622
+ import { z as z5 } from "zod";
1623
+ var CapabilityTierSchema = z5.union([
1624
+ z5.literal(0),
1625
+ z5.literal(1),
1626
+ z5.literal(2),
1627
+ z5.literal(3),
1628
+ z5.literal(4),
1629
+ z5.literal(5)
933
1630
  ]);
934
- var ComplexityTierSchema = z3.enum([
1631
+ var ComplexityTierSchema = z5.enum([
935
1632
  "trivial",
936
1633
  "simple",
937
1634
  "moderate",
938
1635
  "hard"
939
1636
  ]);
940
- var ModelCapabilityProfileSchema = z3.object({
941
- ref: z3.object({
942
- providerID: z3.string().min(1),
943
- modelID: z3.string().min(1)
1637
+ var ModelCapabilityProfileSchema = z5.object({
1638
+ ref: z5.object({
1639
+ providerID: z5.string().min(1),
1640
+ modelID: z5.string().min(1)
944
1641
  }).strict(),
945
- kind: z3.enum(["local", "frontier", "router"]),
946
- contextWindow: z3.number().int().positive(),
947
- maxOutputTokens: z3.number().int().positive(),
948
- supportsToolCalling: z3.boolean(),
949
- supportsVision: z3.boolean(),
1642
+ kind: z5.enum(["local", "frontier", "router"]),
1643
+ contextWindow: z5.number().int().positive(),
1644
+ maxOutputTokens: z5.number().int().positive(),
1645
+ supportsToolCalling: z5.boolean(),
1646
+ supportsVision: z5.boolean(),
950
1647
  reasoningTier: CapabilityTierSchema,
951
1648
  codeQualityTier: CapabilityTierSchema,
952
- costPer1M: z3.object({
953
- inputUSD: z3.number().min(0),
954
- outputUSD: z3.number().min(0)
1649
+ costPer1M: z5.object({
1650
+ inputUSD: z5.number().min(0),
1651
+ outputUSD: z5.number().min(0)
955
1652
  }).strict(),
956
- availability: z3.enum(["available", "degraded", "unavailable"])
1653
+ availability: z5.enum(["available", "degraded", "unavailable"])
957
1654
  }).strict();
958
1655
 
959
1656
  // src/telemetry/diagnostics.ts
@@ -1008,97 +1705,97 @@ function diagnosticDescription(code) {
1008
1705
 
1009
1706
  // src/telemetry/events.ts
1010
1707
  var EVENT_SCHEMA_VERSION = 1;
1011
- var EventBaseSchema = z4.object({
1012
- v: z4.literal(EVENT_SCHEMA_VERSION),
1013
- ts: z4.number().finite(),
1014
- sessionID: z4.string().min(1)
1708
+ var EventBaseSchema = z6.object({
1709
+ v: z6.literal(EVENT_SCHEMA_VERSION),
1710
+ ts: z6.number().finite(),
1711
+ sessionID: z6.string().min(1)
1015
1712
  }).strict();
1016
1713
  var RouteEventSchema = EventBaseSchema.extend({
1017
- type: z4.literal("route"),
1018
- promptHash: z4.string().min(1),
1019
- promptChars: z4.number().int().min(0),
1714
+ type: z6.literal("route"),
1715
+ promptHash: z6.string().min(1),
1716
+ promptChars: z6.number().int().min(0),
1020
1717
  tier: ComplexityTierSchema,
1021
- routeKind: z4.enum(["local", "frontier", "blocked"]),
1718
+ routeKind: z6.enum(["local", "frontier", "blocked"]),
1022
1719
  selected: ModelRefSchema,
1023
- rationale: z4.string(),
1024
- estimatedCostUSD: z4.number().finite().min(0).nullable(),
1025
- baselineCostUSD: z4.number().finite().min(0).nullable(),
1026
- estimatedSavingsUSD: z4.number().finite().nullable(),
1027
- budgetAction: z4.string().min(1),
1028
- tokensIn: z4.number().int().min(0).optional(),
1029
- tokensOut: z4.number().int().min(0).optional(),
1030
- decisionID: z4.string().min(1).optional(),
1031
- agent: z4.string().min(1).optional(),
1032
- success: z4.boolean().optional(),
1033
- batchID: z4.string().min(1).optional(),
1034
- taskID: z4.string().min(1).optional(),
1035
- failureReason: z4.string().min(1).optional(),
1036
- failureStage: z4.string().min(1).optional()
1720
+ rationale: z6.string(),
1721
+ estimatedCostUSD: z6.number().finite().min(0).nullable(),
1722
+ baselineCostUSD: z6.number().finite().min(0).nullable(),
1723
+ estimatedSavingsUSD: z6.number().finite().nullable(),
1724
+ budgetAction: z6.string().min(1),
1725
+ tokensIn: z6.number().int().min(0).optional(),
1726
+ tokensOut: z6.number().int().min(0).optional(),
1727
+ decisionID: z6.string().min(1).optional(),
1728
+ agent: z6.string().min(1).optional(),
1729
+ success: z6.boolean().optional(),
1730
+ batchID: z6.string().min(1).optional(),
1731
+ taskID: z6.string().min(1).optional(),
1732
+ failureReason: z6.string().min(1).optional(),
1733
+ failureStage: z6.string().min(1).optional()
1037
1734
  });
1038
1735
  var MessageEventSchema = EventBaseSchema.extend({
1039
- type: z4.literal("message"),
1040
- providerID: z4.string().min(1),
1041
- modelID: z4.string().min(1),
1042
- agent: z4.string().min(1).optional(),
1043
- mode: z4.string().min(1).optional(),
1044
- messageID: z4.string().min(1).optional(),
1045
- costUSD: z4.number().finite().min(0),
1046
- tokensIn: z4.number().int().min(0),
1047
- tokensOut: z4.number().int().min(0),
1048
- tokensReasoning: z4.number().int().min(0),
1049
- tokensCacheRead: z4.number().int().min(0),
1050
- tokensCacheWrite: z4.number().int().min(0),
1051
- durationMs: z4.number().int().min(0)
1736
+ type: z6.literal("message"),
1737
+ providerID: z6.string().min(1),
1738
+ modelID: z6.string().min(1),
1739
+ agent: z6.string().min(1).optional(),
1740
+ mode: z6.string().min(1).optional(),
1741
+ messageID: z6.string().min(1).optional(),
1742
+ costUSD: z6.number().finite().min(0),
1743
+ tokensIn: z6.number().int().min(0),
1744
+ tokensOut: z6.number().int().min(0),
1745
+ tokensReasoning: z6.number().int().min(0),
1746
+ tokensCacheRead: z6.number().int().min(0),
1747
+ tokensCacheWrite: z6.number().int().min(0),
1748
+ durationMs: z6.number().int().min(0)
1052
1749
  });
1053
1750
  var ToolcallEventSchema = EventBaseSchema.extend({
1054
- type: z4.literal("toolcall"),
1055
- tool: z4.string().min(1),
1056
- callID: z4.string().min(1),
1057
- agent: z4.string().min(1).optional(),
1058
- durationMs: z4.number().int().min(0),
1059
- ok: z4.boolean(),
1060
- title: z4.string().optional()
1751
+ type: z6.literal("toolcall"),
1752
+ tool: z6.string().min(1),
1753
+ callID: z6.string().min(1),
1754
+ agent: z6.string().min(1).optional(),
1755
+ durationMs: z6.number().int().min(0),
1756
+ ok: z6.boolean(),
1757
+ title: z6.string().optional()
1061
1758
  });
1062
1759
  var MeetingEventSchema = EventBaseSchema.extend({
1063
- type: z4.literal("meeting"),
1064
- batchID: z4.string().min(1),
1065
- purpose: z4.string().optional(),
1066
- roles: z4.array(z4.string().min(1)),
1067
- decisionIDs: z4.array(z4.string().min(1)).optional()
1760
+ type: z6.literal("meeting"),
1761
+ batchID: z6.string().min(1),
1762
+ purpose: z6.string().optional(),
1763
+ roles: z6.array(z6.string().min(1)),
1764
+ decisionIDs: z6.array(z6.string().min(1)).optional()
1068
1765
  });
1069
1766
  var QueueEventSchema = EventBaseSchema.extend({
1070
- type: z4.literal("queue"),
1071
- runtimeId: z4.string().min(1),
1072
- waitedMs: z4.number().finite().min(0),
1073
- activeCount: z4.number().int().min(0),
1074
- queuedCount: z4.number().int().min(0),
1075
- decisionID: z4.string().min(1).optional(),
1076
- agent: z4.string().min(1).optional(),
1077
- batchID: z4.string().min(1).optional()
1767
+ type: z6.literal("queue"),
1768
+ runtimeId: z6.string().min(1),
1769
+ waitedMs: z6.number().finite().min(0),
1770
+ activeCount: z6.number().int().min(0),
1771
+ queuedCount: z6.number().int().min(0),
1772
+ decisionID: z6.string().min(1).optional(),
1773
+ agent: z6.string().min(1).optional(),
1774
+ batchID: z6.string().min(1).optional()
1078
1775
  });
1079
1776
  var DecisionEventSchema = EventBaseSchema.extend({
1080
- type: z4.literal("decision"),
1081
- agent: z4.string().min(1).optional(),
1082
- summary: z4.string().min(1),
1083
- tags: z4.array(z4.string().min(1)).optional()
1777
+ type: z6.literal("decision"),
1778
+ agent: z6.string().min(1).optional(),
1779
+ summary: z6.string().min(1),
1780
+ tags: z6.array(z6.string().min(1)).optional()
1084
1781
  });
1085
1782
  var ActivityEventSchema = EventBaseSchema.extend({
1086
- type: z4.literal("activity"),
1087
- kind: z4.enum(["route", "agent", "decision", "commit"]),
1088
- agent: z4.string().min(1).optional(),
1089
- summary: z4.string().min(1)
1783
+ type: z6.literal("activity"),
1784
+ kind: z6.enum(["route", "agent", "decision", "commit"]),
1785
+ agent: z6.string().min(1).optional(),
1786
+ summary: z6.string().min(1)
1090
1787
  });
1091
1788
  var SessionEndpointEventSchema = EventBaseSchema.extend({
1092
- type: z4.literal("session-endpoint"),
1093
- url: z4.string().url(),
1094
- directory: z4.string().min(1).optional(),
1095
- worktree: z4.string().min(1).optional(),
1096
- title: z4.string().min(1).optional()
1789
+ type: z6.literal("session-endpoint"),
1790
+ url: z6.string().url(),
1791
+ directory: z6.string().min(1).optional(),
1792
+ worktree: z6.string().min(1).optional(),
1793
+ title: z6.string().min(1).optional()
1097
1794
  });
1098
1795
  var ShadowDiagnosticEventSchema = EventBaseSchema.extend({
1099
- type: z4.literal("shadow-diagnostic"),
1100
- batchID: z4.string().min(1),
1101
- failureClass: z4.enum([
1796
+ type: z6.literal("shadow-diagnostic"),
1797
+ batchID: z6.string().min(1),
1798
+ failureClass: z6.enum([
1102
1799
  "invalid-node-id",
1103
1800
  "journal-create-failed",
1104
1801
  "journal-append-failed",
@@ -1109,16 +1806,16 @@ var ShadowDiagnosticEventSchema = EventBaseSchema.extend({
1109
1806
  "unknown"
1110
1807
  ])
1111
1808
  });
1112
- var DiagnosticLevelSchema = z4.enum(["debug", "info", "warn", "error"]);
1113
- var DiagnosticCodeSchema = z4.enum(DIAGNOSTIC_CODES);
1809
+ var DiagnosticLevelSchema = z6.enum(["debug", "info", "warn", "error"]);
1810
+ var DiagnosticCodeSchema = z6.enum(DIAGNOSTIC_CODES);
1114
1811
  var DiagnosticEventSchema = EventBaseSchema.extend({
1115
- type: z4.literal("diagnostic"),
1812
+ type: z6.literal("diagnostic"),
1116
1813
  level: DiagnosticLevelSchema,
1117
1814
  code: DiagnosticCodeSchema,
1118
- roleID: z4.string().min(1).optional(),
1119
- passCount: z4.number().int().min(0).optional()
1815
+ roleID: z6.string().min(1).optional(),
1816
+ passCount: z6.number().int().min(0).optional()
1120
1817
  });
1121
- var OpenTeamEventSchema = z4.discriminatedUnion("type", [
1818
+ var OpenTeamEventSchema = z6.discriminatedUnion("type", [
1122
1819
  RouteEventSchema,
1123
1820
  MessageEventSchema,
1124
1821
  ToolcallEventSchema,
@@ -1227,22 +1924,22 @@ function createFsStorageProvider(root) {
1227
1924
  }
1228
1925
 
1229
1926
  // src/telemetry/types.ts
1230
- import { z as z5 } from "zod";
1231
- var CostRecordSchema = z5.object({
1232
- ts: z5.number().finite(),
1233
- sessionID: z5.string().min(1).optional(),
1234
- promptHash: z5.string().min(1),
1235
- promptChars: z5.number().int().min(0),
1927
+ import { z as z7 } from "zod";
1928
+ var CostRecordSchema = z7.object({
1929
+ ts: z7.number().finite(),
1930
+ sessionID: z7.string().min(1).optional(),
1931
+ promptHash: z7.string().min(1),
1932
+ promptChars: z7.number().int().min(0),
1236
1933
  tier: ComplexityTierSchema,
1237
- routeKind: z5.enum(["local", "frontier", "blocked"]),
1934
+ routeKind: z7.enum(["local", "frontier", "blocked"]),
1238
1935
  selected: ModelRefSchema,
1239
- rationale: z5.string(),
1240
- estimatedCostUSD: z5.number().finite().min(0).nullable(),
1241
- baselineCostUSD: z5.number().finite().min(0).nullable(),
1242
- estimatedSavingsUSD: z5.number().finite().nullable(),
1243
- budgetAction: z5.string().min(1),
1244
- tokensIn: z5.number().int().min(0).optional(),
1245
- tokensOut: z5.number().int().min(0).optional()
1936
+ rationale: z7.string(),
1937
+ estimatedCostUSD: z7.number().finite().min(0).nullable(),
1938
+ baselineCostUSD: z7.number().finite().min(0).nullable(),
1939
+ estimatedSavingsUSD: z7.number().finite().nullable(),
1940
+ budgetAction: z7.string().min(1),
1941
+ tokensIn: z7.number().int().min(0).optional(),
1942
+ tokensOut: z7.number().int().min(0).optional()
1246
1943
  }).strict();
1247
1944
 
1248
1945
  // src/telemetry/read.ts
@@ -1430,7 +2127,7 @@ function hashPrompt(prompt) {
1430
2127
  }
1431
2128
 
1432
2129
  // src/orchestrator/coordinator.ts
1433
- var TelemetryFailureClassSchema = z6.enum([
2130
+ var TelemetryFailureClassSchema = z8.enum([
1434
2131
  "create-rejected",
1435
2132
  "create-no-id",
1436
2133
  "prompt-rejected",
@@ -1581,8 +2278,8 @@ function redactFrameText(text) {
1581
2278
  return `[redacted · ${text.length} chars · ${hashPrompt(text)}]`;
1582
2279
  }
1583
2280
  var MAX_INPUT_CHARS = 1e5;
1584
- var SessionInputSchema = z7.object({
1585
- text: z7.string().min(1).max(MAX_INPUT_CHARS)
2281
+ var SessionInputSchema = z9.object({
2282
+ text: z9.string().min(1).max(MAX_INPUT_CHARS)
1586
2283
  }).strict();
1587
2284
  function parseSessionInput(raw) {
1588
2285
  const result = SessionInputSchema.safeParse(raw);
@@ -1768,13 +2465,20 @@ function createConsoleClient(deps) {
1768
2465
  await post(`/session/${encodeURIComponent(sessionID)}/permissions/${encodeURIComponent(permissionID)}`, { response });
1769
2466
  },
1770
2467
  async listMessages(sessionID, options) {
1771
- const res = await doFetch(`${base}/session/${encodeURIComponent(sessionID)}/message`, { headers: { accept: "application/json", ...authHeaders } });
2468
+ const res = await doFetch(`${base}/session/${encodeURIComponent(sessionID)}/message`, {
2469
+ headers: { accept: "application/json", ...authHeaders },
2470
+ signal: AbortSignal.timeout(1e4)
2471
+ });
2472
+ if (!res.ok)
2473
+ throw new Error(consoleDetailMessages.readFailed);
1772
2474
  let raw;
1773
2475
  try {
1774
2476
  raw = await res.json();
1775
2477
  } catch {
1776
- return [];
2478
+ throw new Error(consoleDetailMessages.readFailed);
1777
2479
  }
2480
+ if (!Array.isArray(raw))
2481
+ throw new Error(consoleDetailMessages.readFailed);
1778
2482
  return messagesToFrames(raw, sessionID, options ?? {});
1779
2483
  },
1780
2484
  async streamFrames(sessionID, onFrame, signal, options) {
@@ -2302,7 +3006,7 @@ async function buildSqliteIndexFromConfig(path, sessionsDir, deps) {
2302
3006
  }
2303
3007
 
2304
3008
  // src/config/errors.ts
2305
- import { z as z8 } from "zod";
3009
+ import { z as z10 } from "zod";
2306
3010
  var ROOT_PATH = "<root>";
2307
3011
  var MODEL_REF_KEYS = ["providerID", "modelID"];
2308
3012
  var KNOWN_CONFIG_KEYS_BY_PATH = new Map([
@@ -2377,11 +3081,13 @@ var KNOWN_CONFIG_KEYS_BY_PATH = new Map([
2377
3081
  "openBrowser",
2378
3082
  "remoteStorage",
2379
3083
  "terminal",
2380
- "graphView"
3084
+ "graphView",
3085
+ "sessionHistory"
2381
3086
  ]
2382
3087
  ],
2383
3088
  ["console.terminal", ["enabled", "pty"]],
2384
3089
  ["console.graphView", ["enabled"]],
3090
+ ["console.sessionHistory", ["contentEnabled", "endpoint"]],
2385
3091
  ["storage", ["sqliteIndex"]],
2386
3092
  ["storage.sqliteIndex", ["enabled", "path"]],
2387
3093
  ["memory", ["semantic"]],
@@ -2506,7 +3212,7 @@ function formatUnrecognizedKeys(issues, knownKeysByPath) {
2506
3212
  return messages;
2507
3213
  }
2508
3214
  function formatZodBoundaryError(error, options = {}) {
2509
- if (error instanceof z8.ZodError) {
3215
+ if (error instanceof z10.ZodError) {
2510
3216
  const unknownKeys = formatUnrecognizedKeys(error.issues, options.knownKeysByPath ?? KNOWN_CONFIG_KEYS_BY_PATH);
2511
3217
  const otherIssues = error.issues.filter((issue) => !isUnrecognizedKeysIssue(issue)).map((issue) => {
2512
3218
  const path = formatConfigPath(issue.path);
@@ -2656,17 +3362,17 @@ function compareRoleIDs([left], [right]) {
2656
3362
  return left === right ? 0 : left < right ? -1 : 1;
2657
3363
  }
2658
3364
  function policyModelReferences(policy, path) {
2659
- const references = [];
3365
+ const references2 = [];
2660
3366
  if (policy?.model !== undefined && policy.model !== "auto") {
2661
- references.push({ path: `${path}.model`, model: policy.model });
3367
+ references2.push({ path: `${path}.model`, model: policy.model });
2662
3368
  }
2663
3369
  for (const [index, fallback] of (policy?.fallbacks ?? []).entries()) {
2664
- references.push({
3370
+ references2.push({
2665
3371
  path: `${path}.fallbacks.${index}`,
2666
3372
  model: fallback
2667
3373
  });
2668
3374
  }
2669
- return references;
3375
+ return references2;
2670
3376
  }
2671
3377
  function configuredPolicies(config) {
2672
3378
  const policies = [
@@ -2829,7 +3535,7 @@ async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, stora
2829
3535
  }
2830
3536
 
2831
3537
  // src/config/runtime.ts
2832
- import { z as z9 } from "zod";
3538
+ import { z as z11 } from "zod";
2833
3539
  var CONFIG_KEYS = [
2834
3540
  "baseline",
2835
3541
  "router",
@@ -2845,18 +3551,18 @@ var CONFIG_KEYS = [
2845
3551
  ];
2846
3552
  var CONFIG_KEY_SET = new Set(CONFIG_KEYS);
2847
3553
  var TELEMETRY_PLUGIN_OPTION_KEY = "telemetry";
2848
- var configOptionSchemas = Object.fromEntries(CONFIG_KEYS.map((key) => [key, z9.unknown().optional()]));
2849
- var TelemetryPluginOptionsObjectSchema = z9.object({
2850
- enabled: z9.boolean().default(true),
2851
- path: z9.string().min(1).default(DEFAULT_TELEMETRY_PATH),
2852
- sessionsDir: z9.string().min(1).default(DEFAULT_SESSIONS_DIR)
3554
+ var configOptionSchemas = Object.fromEntries(CONFIG_KEYS.map((key) => [key, z11.unknown().optional()]));
3555
+ var TelemetryPluginOptionsObjectSchema = z11.object({
3556
+ enabled: z11.boolean().default(true),
3557
+ path: z11.string().min(1).default(DEFAULT_TELEMETRY_PATH),
3558
+ sessionsDir: z11.string().min(1).default(DEFAULT_SESSIONS_DIR)
2853
3559
  }).strict();
2854
3560
  var TelemetryPluginOptionsSchema = TelemetryPluginOptionsObjectSchema.default({
2855
3561
  enabled: true,
2856
3562
  path: DEFAULT_TELEMETRY_PATH,
2857
3563
  sessionsDir: DEFAULT_SESSIONS_DIR
2858
3564
  });
2859
- var PluginOptionsObjectSchema = z9.object({
3565
+ var PluginOptionsObjectSchema = z11.object({
2860
3566
  ...configOptionSchemas,
2861
3567
  [TELEMETRY_PLUGIN_OPTION_KEY]: TelemetryPluginOptionsObjectSchema.optional()
2862
3568
  }).strict();
@@ -2978,7 +3684,8 @@ function isJsonObject2(value) {
2978
3684
  var MACHINE_SPECIFIC_KEYS = [
2979
3685
  "local.runtimes",
2980
3686
  "console.host",
2981
- "console.port"
3687
+ "console.port",
3688
+ "console.sessionHistory"
2982
3689
  ];
2983
3690
  var HOT_RELOADABLE_KEYS = ["console.refreshMs"];
2984
3691
  var KNOWN_ENV_SECRETS = [
@@ -3531,10 +4238,411 @@ async function handleLifecycleHistoryRoute(request, response, url, deps) {
3531
4238
  return true;
3532
4239
  }
3533
4240
 
4241
+ // src/console/inspector.ts
4242
+ var CONVERSATION_CLIENT_JS = `
4243
+ function wireConversationInspector(){
4244
+ var mount=document.getElementById('lifecycle-timeline-mount');
4245
+ if(!mount){return}
4246
+ var msg=${JSON.stringify(consoleDetailMessages)};
4247
+ var limits=${JSON.stringify(CONVERSATION_LIMITS)};
4248
+ var panel=document.createElement('section');panel.className='lc-conversation';panel.hidden=true;panel.id='lc-attempt-conversation';
4249
+ panel.setAttribute('data-conversation-inspector','');
4250
+ panel.setAttribute('aria-labelledby','lc-conversation-heading');
4251
+ mount.appendChild(panel);
4252
+ var selection=null,request=null,epoch=0,retained=null;
4253
+ function element(tag,text){var e=document.createElement(tag);if(text!==undefined){e.textContent=text}return e}
4254
+ function selectedButton(){
4255
+ if(!selection||mount.getAttribute('data-conversation-transition')==='1'||
4256
+ mount.getAttribute('data-lifecycle-run')!==selection.run||
4257
+ (mount.getAttribute('data-conversation-cursor')||null)!==selection.cursor){return null}
4258
+ return Array.from(mount.querySelectorAll('[data-inspect-attempt],[data-inspect-root]')).find(function(button){
4259
+ var attempt=button.closest('[data-lifecycle-attempt-id]');
4260
+ var operation=button.closest('[data-lifecycle-operation-id]');
4261
+ var session=button.closest(selection.target==='root'?'[data-root-session-id]':'[data-lifecycle-session-id]');
4262
+ return !button.disabled&&operation&&session&&
4263
+ (selection.target==='root'?button.hasAttribute('data-inspect-root'):attempt&&attempt.getAttribute('data-lifecycle-attempt-id')===selection.attempt&&
4264
+ button.getAttribute('data-inspect-attempt')===selection.attempt)&&
4265
+ operation.getAttribute('data-lifecycle-operation-id')===selection.operation&&
4266
+ button.getAttribute('data-inspect-operation')===selection.operation&&
4267
+ session.getAttribute(selection.target==='root'?'data-root-session-id':'data-lifecycle-session-id')===selection.session;
4268
+ })||null;
4269
+ }
4270
+ function expanded(button,open){
4271
+ if(button.getAttribute('aria-expanded')!==String(open)){button.setAttribute('aria-expanded',String(open))}
4272
+ var label=open?msg.close:msg.inspectConversation;
4273
+ if(button.textContent!==label){button.textContent=label}
4274
+ }
4275
+ function cancel(){
4276
+ epoch++;if(request){request.abort();request=null}
4277
+ }
4278
+ function close(focus){
4279
+ var button=selectedButton();
4280
+ cancel();selection=null;retained=null;
4281
+ mount.querySelectorAll('[data-inspect-attempt],[data-inspect-root]').forEach(function(control){expanded(control,false)});
4282
+ panel.textContent='';panel.hidden=true;
4283
+ ['data-conversation-kind','data-conversation-run','data-conversation-operation','data-conversation-attempt','data-conversation-session','data-conversation-target','aria-busy'].forEach(function(name){panel.removeAttribute(name)});
4284
+ mount.appendChild(panel);
4285
+ if(focus===true&&button){button.focus({preventScroll:true})}
4286
+ }
4287
+ // The renderer replaces metadata, not retained content. Restore only after
4288
+ // the real run/cursor commits and the same attempt/session is still visible.
4289
+ function retain(){
4290
+ if(!selection||panel.hidden||!selectedButton()){return}
4291
+ var scrolls=[],ancestor=panel.parentElement;
4292
+ while(ancestor){scrolls.push([ancestor,ancestor.scrollTop,ancestor.scrollLeft]);ancestor=ancestor.parentElement}
4293
+ panel.querySelectorAll('pre,[data-conversation-tool-list]').forEach(function(node){scrolls.push([node,node.scrollTop,node.scrollLeft])});
4294
+ retained={scrolls:scrolls,top:panel.getBoundingClientRect().top,focus:panel.contains(document.activeElement)?document.activeElement:null};
4295
+ }
4296
+ function reanchor(){
4297
+ if(!selection){return}
4298
+ var button=selectedButton();
4299
+ if(!button){close();return}
4300
+ var attempt=selection.target==='root'?button.closest('.lct-operation-card'):button.closest('[data-lifecycle-attempt-id]');
4301
+ if(panel.parentElement!==attempt){attempt.appendChild(panel)}
4302
+ expanded(button,true);
4303
+ if(retained){
4304
+ retained.scrolls.forEach(function(item){if(item[0].isConnected){item[0].scrollTop=item[1];item[0].scrollLeft=item[2]}});
4305
+ var tree=mount.querySelector('[data-lifecycle-tree-mount]');
4306
+ if(tree){tree.scrollTop+=panel.getBoundingClientRect().top-retained.top}
4307
+ if(retained.focus){retained.focus.focus({preventScroll:true})}
4308
+ retained=null;
4309
+ }
4310
+ }
4311
+ function reset(){
4312
+ panel.textContent='';
4313
+ var header=element('header');header.className='lc-conversation-head';
4314
+ var heading=element('h3',msg.title);heading.id='lc-conversation-heading';heading.tabIndex=-1;header.appendChild(heading);
4315
+ var closeBtn=element('button',msg.close);closeBtn.type='button';
4316
+ closeBtn.setAttribute('data-conversation-close','');
4317
+ closeBtn.addEventListener('click',function(){close(true)});header.appendChild(closeBtn);panel.appendChild(header);
4318
+ }
4319
+ function showHeading(){
4320
+ var heading=panel.querySelector('h3');
4321
+ heading.focus({preventScroll:true});
4322
+ heading.scrollIntoView({block:'start',inline:'nearest'});
4323
+ }
4324
+ function load(reveal){
4325
+ if(!selectedButton()){return}
4326
+ cancel();var current=epoch,selected=selection;
4327
+ reset();
4328
+ panel.setAttribute('data-conversation-kind','loading');
4329
+ panel.setAttribute('aria-busy','true');
4330
+ var status=element('p',msg.loading);status.setAttribute('role','status');panel.appendChild(status);
4331
+ var opening=null;
4332
+ if(reveal===true){
4333
+ showHeading();
4334
+ opening={focus:document.activeElement,scrolls:[mount.querySelector('[data-lifecycle-tree-mount]'),mount.closest('.scroll')].filter(Boolean).map(function(node){return [node,node.scrollTop,node.scrollLeft]})};
4335
+ }
4336
+ var controller=new AbortController();request=controller;
4337
+ var query=new URLSearchParams({run:selected.run,operation:selected.operation,diagnostic:'1'});
4338
+ if(selected.target==='root'){query.set('target','root')}else{query.set('attempt',selected.attempt)}
4339
+ query.set('token',document.documentElement.getAttribute('data-token')||'');
4340
+ if(selected.cursor!==null){query.set('cursor',selected.cursor)}
4341
+ var timeout=setTimeout(function(){controller.abort()},15000);
4342
+ fetch('/api/graph/conversation?'+query.toString(),{signal:controller.signal,cache:'no-store'})
4343
+ .then(function(r){return r.json()}).then(function(data){
4344
+ if(epoch!==current||selection!==selected||!selectedButton()){return}
4345
+ var bringIntoView=opening&&document.activeElement===opening.focus&&opening.scrolls.every(function(item){return item[0].scrollTop===item[1]&&item[0].scrollLeft===item[2]});
4346
+ if((data.kind==='conversation'||data.kind==='empty')&&(data.runID!==selected.run||data.operationID!==selected.operation||
4347
+ (selected.target==='root'?(data.target!=='root'||data.attemptID!==undefined||!data.sessionID||(!selected.session&&!['sdk-parent','tool-result'].includes(data.association))):(data.target!=='attempt'||data.attemptID!==selected.attempt))||
4348
+ (selected.session&&data.sessionID!==selected.session))){
4349
+ data={kind:'unavailable',message:msg.unavailable};
4350
+ }
4351
+ status.textContent=data.message||msg.unavailable;
4352
+ panel.setAttribute('data-conversation-kind',data.kind||'unavailable');
4353
+ if(data.kind==='conversation'||data.kind==='empty'){
4354
+ panel.setAttribute('data-conversation-session',data.sessionID);
4355
+ var source=element('p');source.appendChild(element('strong',data.session&&data.session.title|| (selected.target==='root'?msg.orchestrator:msg.session)));
4356
+ var created=consoleLabels.utcTime(data.session&&data.session.createdAt);
4357
+ source.appendChild(element('small',' · '+(created===msg.timeUnknown?msg.timeUnknown:msg.sessionCreated+': '+created)));
4358
+ source.appendChild(element('code',' · '+data.sessionID));panel.appendChild(source);
4359
+ if(data.session&&data.session.id===data.sessionID){document.dispatchEvent(new CustomEvent('console-session-metadata',{detail:{session:data.session,runID:data.runID,target:selected.target}}))}
4360
+ }
4361
+ if(data.kind==='conversation'){
4362
+ renderMessages(data.messages||[]);
4363
+ }else if(data.kind==='empty'){
4364
+ renderMessages([]);
4365
+ }
4366
+ // The short loading card may not have enough scroll range. Complete
4367
+ // the explicit reveal after layout grows, unless the reader moved on.
4368
+ if(bringIntoView){panel.querySelector('h3').scrollIntoView({block:'start',inline:'nearest'})}
4369
+ }).catch(function(){
4370
+ if(epoch===current){status.textContent=msg.unavailable;panel.setAttribute('data-conversation-kind','unavailable')}
4371
+ }).finally(function(){
4372
+ clearTimeout(timeout);
4373
+ if(epoch!==current){return}
4374
+ request=null;
4375
+ panel.setAttribute('aria-busy','false');
4376
+ var refresh=element('button',msg.refresh);refresh.type='button';refresh.setAttribute('data-conversation-refresh','');
4377
+ refresh.addEventListener('click',load);panel.appendChild(refresh);
4378
+ });
4379
+ }
4380
+ function renderMessages(messages){
4381
+ var truncated=messages.length>limits.messages,remaining=limits.totalChars,toolCount=0;
4382
+ messages=messages.slice(0,limits.messages);
4383
+ var tools=element('details');tools.setAttribute('data-conversation-tools','');tools.open=true;
4384
+ var count=messages.reduce(function(total,m){return total+(m.tools||[]).length},0);
4385
+ tools.appendChild(element('summary',msg.tools.replace('{count}',String(count))));
4386
+ var calls=element('div');calls.setAttribute('data-conversation-tool-list','');tools.appendChild(calls);
4387
+ panel.appendChild(tools);
4388
+ function text(value){
4389
+ value=String(value);
4390
+ var size=Math.min(value.length,limits.fieldChars+msg.truncatedMarker.length,remaining);
4391
+ remaining-=size;
4392
+ if(size<value.length){truncated=true}
4393
+ return value.slice(0,size);
4394
+ }
4395
+ ['user','assistant'].forEach(function(role){
4396
+ var section=element('section');section.setAttribute('data-conversation-role',role);
4397
+ section.appendChild(element('h4',role==='user'?msg.prompt:msg.assistant));
4398
+ var hasText=false;
4399
+ messages.filter(function(m){return m.role===role}).forEach(function(m){
4400
+ var item=element('article');item.appendChild(element('time',consoleLabels.utcTime(m.createdAt)));
4401
+ if((m.text||[]).length>limits.parts){truncated=true}
4402
+ (m.text||[]).slice(0,limits.parts).forEach(function(value){
4403
+ if(!value){return}
4404
+ hasText=true;
4405
+ if(remaining>0){item.appendChild(element('pre',text(value)))}else{truncated=true}
4406
+ });
4407
+ if(item.querySelector('pre')){section.appendChild(item)}
4408
+ });panel.appendChild(section);
4409
+ if(!hasText){section.appendChild(element('p',role==='user'?msg.noPrompts:msg.noOutput))}
4410
+ });
4411
+ messages.forEach(function(m){
4412
+ if((m.tools||[]).length>limits.parts){truncated=true}
4413
+ (m.tools||[]).slice(0,limits.parts).forEach(function(tool){
4414
+ if(toolCount++>=limits.tools||remaining<=0){truncated=true;return}
4415
+ var call=element('details');call.setAttribute('data-tool-call',tool.id);
4416
+ call.appendChild(element('summary',text(tool.name)+' · '+text(tool.status)));
4417
+ if(tool.startedAt!==undefined){call.appendChild(element('time',consoleLabels.utcTime(tool.startedAt)))}
4418
+ call.appendChild(element('h5',msg.arguments));call.appendChild(element('pre',text(tool.arguments)));
4419
+ call.appendChild(element('h5',msg.result));call.appendChild(element('pre',text(tool.result===undefined?msg.pending:tool.result)));
4420
+ calls.appendChild(call);
4421
+ });
4422
+ });
4423
+ if(count===0){calls.appendChild(element('p',msg.noTools))}
4424
+ if(truncated){panel.appendChild(element('p',msg.truncated))}
4425
+ }
4426
+ mount.addEventListener('click',function(event){
4427
+ var button=event.target.closest('[data-inspect-attempt],[data-inspect-root]');
4428
+ if(!button||button.disabled||mount.getAttribute('data-conversation-transition')==='1'){return}
4429
+ if(button===selectedButton()){close(true);return}
4430
+ close();
4431
+ var root=button.hasAttribute('data-inspect-root');
4432
+ var session=button.closest(root?'[data-root-session-id]':'[data-lifecycle-session-id]');
4433
+ if(!session){return}
4434
+ selection={
4435
+ run:mount.getAttribute('data-lifecycle-run'),
4436
+ operation:button.getAttribute('data-inspect-operation'),
4437
+ attempt:button.getAttribute('data-inspect-attempt'),
4438
+ target:root?'root':'attempt',
4439
+ session:session.getAttribute(root?'data-root-session-id':'data-lifecycle-session-id'),
4440
+ cursor:mount.getAttribute('data-conversation-cursor')||null
4441
+ };
4442
+ if(!selectedButton()){close();return}
4443
+ panel.setAttribute('data-conversation-run',selection.run);
4444
+ panel.setAttribute('data-conversation-operation',selection.operation);
4445
+ if(selection.attempt){panel.setAttribute('data-conversation-attempt',selection.attempt)}
4446
+ panel.setAttribute('data-conversation-target',selection.target);
4447
+ panel.setAttribute('data-conversation-session',selection.session);
4448
+ reanchor();
4449
+ panel.hidden=false;
4450
+ if(selection.cursor!==null){reset();panel.setAttribute('data-conversation-kind','historical');panel.appendChild(element('p',msg.historical));showHeading()}
4451
+ else{load(true)}
4452
+ });
4453
+ document.addEventListener('conversation-selection',close);
4454
+ document.addEventListener('conversation-tree-replacing',retain);
4455
+ document.addEventListener('conversation-tree-committed',reanchor);
4456
+ window.addEventListener('pagehide',close);
4457
+ }
4458
+ `;
4459
+ var CONVERSATION_STYLE = `
4460
+ .lc-conversation{margin-top:12px;padding:12px;min-width:0;border:1px solid var(--cp-border);border-radius:16px;background:var(--cp-surface);color:var(--cp-text);overflow-anchor:none}
4461
+ .lc-conversation[hidden]{display:none}
4462
+ .lc-conversation-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}
4463
+ .lc-conversation h3,.lc-conversation h4,.lc-conversation p{margin:8px 0}
4464
+ .lc-conversation h3{scroll-margin-top:12px}
4465
+ .lc-conversation pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:400px;overflow:auto;background:var(--cp-surface-soft);padding:12px;font-family:Consolas,"Courier New",Courier,monospace}
4466
+ .lc-conversation [data-conversation-role="user"] pre{max-height:180px}
4467
+ .lc-conversation [data-conversation-tool-list]{max-height:160px;overflow:auto}
4468
+ .lc-conversation details{margin-top:12px;padding:8px;border:1px solid var(--cp-border);border-radius:.625rem}
4469
+ .lc-conversation summary{cursor:pointer;color:var(--cp-accent)}
4470
+ .lc-conversation time{font-size:11px;color:var(--cp-text-muted)}
4471
+ .lc-conversation button,[data-inspect-attempt],[data-inspect-root]{padding:6px 10px;margin:6px;border:1px solid var(--cp-border);border-radius:.625rem;background:var(--cp-surface);color:var(--cp-accent)}
4472
+ .lct-operation-name{display:block;font-size:16px}
4473
+ .lct-operation-head details,.lct-session details{font-size:11px;color:var(--cp-text-muted)}
4474
+ .lct-session small,.session-btn small{display:block;color:var(--cp-text-muted)}
4475
+ .lc-run-select{max-width:650px}
4476
+ `;
4477
+
4478
+ // src/console/refresh.ts
4479
+ var CONSOLE_REFRESH_JS = `
4480
+ var viewRevision='',viewRequest=null,viewPending=false,viewStopped=false,latestView=null;
4481
+ var appliedRouting='',appliedLogs='',appliedTree='';
4482
+ function protectedContent(element){
4483
+ var active=document.activeElement;
4484
+ if(active&&element.contains(active)&&/^(INPUT|TEXTAREA|SELECT)$/.test(active.tagName)){return true}
4485
+ var selection=window.getSelection&&window.getSelection();
4486
+ return !!(selection&&!selection.isCollapsed&&element.contains(selection.anchorNode));
4487
+ }
4488
+ function nodeKey(node){
4489
+ if(node.nodeType!==1){return ''}
4490
+ return (node.hasAttribute('data-session-target')?'session-target:'+node.getAttribute('data-session-target'):
4491
+ node.hasAttribute('data-session-view')?'session-view:'+node.getAttribute('data-session-view'):node.id)||
4492
+ ((node.tagName==='LI'||node.tagName==='TR')?node.outerHTML:'');
4493
+ }
4494
+ function patchNode(old,next){
4495
+ if(old.isEqualNode(next)){return}
4496
+ if(old.nodeType!==next.nodeType||old.nodeName!==next.nodeName){
4497
+ old.replaceWith(next.cloneNode(true));return;
4498
+ }
4499
+ if(old.nodeType===3){old.nodeValue=next.nodeValue;return}
4500
+ if(old.nodeType!==1){return}
4501
+ if(old.matches('[data-session-name],[data-session-time]')){
4502
+ if(old.getAttribute('data-label-fallback')!==next.textContent){old.setAttribute('data-label-fallback',next.textContent)}
4503
+ return;
4504
+ }
4505
+ if(old.matches('input,textarea,select,.term,.pty,.graph-drill,[data-config-mount]')){return}
4506
+ Array.from(old.attributes).forEach(function(a){
4507
+ if(a.name!=='open'&&a.name!=='hidden'&&a.name!=='aria-selected'&&!next.hasAttribute(a.name)){old.removeAttribute(a.name)}
4508
+ });
4509
+ Array.from(next.attributes).forEach(function(a){
4510
+ if(a.name!=='open'&&a.name!=='hidden'&&a.name!=='aria-selected'&&old.getAttribute(a.name)!==a.value){old.setAttribute(a.name,a.value)}
4511
+ });
4512
+ var originals=Array.from(old.childNodes),used=new Set();
4513
+ Array.from(next.childNodes).forEach(function(child,index){
4514
+ var key=nodeKey(child),match;
4515
+ if(key){match=originals.find(function(n){return !used.has(n)&&nodeKey(n)===key})}
4516
+ else{match=originals.find(function(n){return !used.has(n)&&!nodeKey(n)&&n.nodeName===child.nodeName})}
4517
+ if(match){used.add(match);patchNode(match,child)}
4518
+ else{match=child.cloneNode(true)}
4519
+ if(old.childNodes[index]!==match){
4520
+ var scrolls=match.nodeType===1?[match].concat(Array.from(match.querySelectorAll('*'))).map(function(n){return [n,n.scrollTop,n.scrollLeft]}):[];
4521
+ old.insertBefore(match,old.childNodes[index]||null);
4522
+ scrolls.forEach(function(s){s[0].scrollTop=s[1];s[0].scrollLeft=s[2]});
4523
+ }
4524
+ });
4525
+ originals.forEach(function(n){
4526
+ if(!used.has(n)&&n.parentNode===old){
4527
+ if(n.nodeType===1){
4528
+ disconnectTerminal(n);
4529
+ n.querySelectorAll('[data-session-view]').forEach(disconnectTerminal);
4530
+ }
4531
+ old.removeChild(n);
4532
+ }
4533
+ });
4534
+ }
4535
+ function patchHtml(element,html){
4536
+ var next=document.createElement('div');
4537
+ next.innerHTML=html;
4538
+ var shell=element.cloneNode(false);
4539
+ while(next.firstChild){shell.appendChild(next.firstChild)}
4540
+ patchNode(element,shell);
4541
+ }
4542
+ function applyView(forceLogs){
4543
+ if(!latestView){return}
4544
+ var tree=document.querySelector('#screen-tree > .graph-panel');
4545
+ if(tree&&latestView.tree&&latestView.tree!==appliedTree&&!protectedContent(tree)){
4546
+ var graph=document.createElement('div');graph.innerHTML=latestView.tree;
4547
+ if(graph.firstElementChild){patchNode(tree,graph.firstElementChild)}
4548
+ appliedTree=latestView.tree;
4549
+ }
4550
+ var routing=document.querySelector('#screen-routing > .screen-grid');
4551
+ if(routing&&latestView.routing!==appliedRouting&&!protectedContent(routing)){
4552
+ var next=document.createElement('div');next.innerHTML=latestView.routing;
4553
+ if(next.firstElementChild){patchNode(routing,next.firstElementChild)}
4554
+ appliedRouting=latestView.routing;
4555
+ }
4556
+ var logs=document.getElementById('screen-logs');
4557
+ var content=logs&&logs.querySelector('[data-log-content]');
4558
+ var follow=logs&&logs.querySelector('[data-log-follow]');
4559
+ var incoming=logs&&logs.querySelector('[data-log-incoming]');
4560
+ var scroll=document.querySelector('.scroll');
4561
+ if(content&&latestView.logs!==appliedLogs){
4562
+ if(appliedLogs===''&&content.innerHTML===latestView.logs){appliedLogs=latestView.logs}
4563
+ else{
4564
+ var atBottom=!scroll||scroll.scrollHeight-scroll.scrollTop-scroll.clientHeight<40;
4565
+ var safe=logs.hidden||(follow&&follow.checked&&atBottom);
4566
+ if((forceLogs||safe)&&!protectedContent(content)){
4567
+ var top=scroll&&scroll.scrollTop;
4568
+ patchHtml(content,latestView.logs);
4569
+ appliedLogs=latestView.logs;
4570
+ wireLogsScreen(logs);
4571
+ if(scroll&&!logs.hidden){scroll.scrollTop=follow&&follow.checked?scroll.scrollHeight:top}
4572
+ }
4573
+ }
4574
+ if(incoming){incoming.hidden=latestView.logs===appliedLogs&&!Array.from(content.querySelectorAll('.termlog')).some(function(log){return log.__incoming})}
4575
+ }
4576
+ var count=document.querySelector('[data-screen="logs"] .count');
4577
+ if(count&&count.textContent!==String(latestView.sessionCount)){count.textContent=String(latestView.sessionCount)}
4578
+ if(typeof consoleLabels!=='undefined'){consoleLabels.refresh()}
4579
+ }
4580
+ function refreshView(){
4581
+ if(viewStopped){return}
4582
+ applyView(false);
4583
+ if(viewRequest){viewPending=true;return}
4584
+ viewPending=false;
4585
+ var controller=new AbortController();
4586
+ viewRequest=controller;
4587
+ var timeout=setTimeout(function(){controller.abort()},15000);
4588
+ fetch('/api/view'+authTok,{headers:viewRevision?{'If-None-Match':viewRevision}:{},signal:controller.signal})
4589
+ .then(function(r){
4590
+ var error=document.querySelector('[data-refresh-error]');
4591
+ if(error){error.hidden=r.ok||r.status===304}
4592
+ if(r.status===304){return null}
4593
+ if(!r.ok){throw new Error()}
4594
+ var revision=r.headers.get('etag')||'';
4595
+ return r.json().then(function(d){return {data:d,revision:revision}});
4596
+ }).then(function(result){
4597
+ if(viewStopped||viewRequest!==controller||!result){return}
4598
+ if(typeof result.data.routing!=='string'||typeof result.data.logs!=='string'){return}
4599
+ latestView=result.data;viewRevision=result.revision;
4600
+ var updated=document.querySelector('.token-chip b');
4601
+ if(updated&&typeof latestView.updatedAt==='string'){updated.textContent=latestView.updatedAt}
4602
+ if(Number.isInteger(latestView.refreshMs)&&latestView.refreshMs>=250&&latestView.refreshMs!==ms){
4603
+ ms=latestView.refreshMs;document.documentElement.setAttribute('data-refresh',String(ms));
4604
+ clearInterval(refreshTimer);refreshTimer=null;startRefresh();
4605
+ document.dispatchEvent(new CustomEvent('console-refresh-changed',{detail:ms}));
4606
+ }
4607
+ applyView(false);
4608
+ }).catch(function(){
4609
+ var error=document.querySelector('[data-refresh-error]');
4610
+ if(error&&!viewStopped){error.hidden=false}
4611
+ }).finally(function(){
4612
+ clearTimeout(timeout);
4613
+ if(viewRequest!==controller){return}
4614
+ viewRequest=null;
4615
+ if(viewPending&&!viewStopped){refreshView()}
4616
+ });
4617
+ }
4618
+ var refreshTimer=null;
4619
+ function startRefresh(){
4620
+ if(refreshTimer!==null){return}
4621
+ viewStopped=false;
4622
+ refreshTimer=setInterval(refreshView,isNaN(ms)?2000:Math.max(250,ms));
4623
+ }
4624
+ window.addEventListener('pagehide',function(){
4625
+ viewStopped=true;clearInterval(refreshTimer);refreshTimer=null;
4626
+ if(viewRequest){viewRequest.abort();viewRequest=null}
4627
+ if(es){es.close();es=null}
4628
+ document.querySelectorAll('[data-session-view]').forEach(disconnectTerminal);
4629
+ });
4630
+ window.addEventListener('pageshow',function(e){
4631
+ if(e.persisted){
4632
+ startRefresh();openStateStream();refreshView();
4633
+ var logs=document.getElementById('screen-logs');
4634
+ if(logs&&!logs.hidden){wireLogsScreen(logs)}
4635
+ }
4636
+ });
4637
+ `;
4638
+
3534
4639
  // src/console/assets.ts
3535
4640
  var CONSOLE_STYLE = `
3536
4641
  :root{color-scheme:dark;--bg:#0f0f0f;--surface:#17181b;--surface-2:#1e2024;--panel:var(--surface);--fg:#eceef1;--muted:#a2a8b2;--faint:#6b7079;--border:rgba(255,255,255,.08);--border-strong:rgba(255,255,255,.16);--line:var(--border);--accent:#35c07a;--accent-bg:rgba(53,192,122,.12);--accent-fg:#57d492;--good:var(--accent-fg);--local:#6aa6f5;--frontier:#e0a53a;--warn:#e0a53a;--warn-bg:rgba(224,165,58,.12);--danger:#f0687f;--danger-bg:rgba(240,104,127,.12);--info:#6aa6f5;--info-bg:rgba(106,166,245,.12);--font-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;--font-mono:"JetBrains Mono","IBM Plex Mono",ui-monospace,"SFMono-Regular",Consolas,monospace;--shadow-pop:0 8px 28px rgba(0,0,0,.5);--sidebar-w:248px}
3537
4642
  *{box-sizing:border-box;margin:0;padding:0}
4643
+ [data-log-controls]{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:16px}
4644
+ [data-log-controls] input,[data-log-controls] button{padding:6px;border:1px solid var(--cp-border);border-radius:.625rem;background:var(--cp-surface);color:var(--cp-text)}
4645
+ [data-session-target][hidden]{display:none}
3538
4646
  html,body{height:100%}
3539
4647
  body{background:var(--bg);color:var(--fg);font:14px/1.55 var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-variant-numeric:tabular-nums}
3540
4648
  .mono,code,.hash{font-family:var(--font-mono);font-variant-numeric:tabular-nums}
@@ -3609,25 +4717,21 @@ svg.graph{display:block}
3609
4717
  `;
3610
4718
  var CONSOLE_CLIENT_JS = `
3611
4719
  (function(){
4720
+ var detailMsg=${JSON.stringify(consoleDetailMessages)};
4721
+ var terminalCollectors=[];
3612
4722
  var authTok='';
3613
4723
  try{
3614
4724
  var qp=new URLSearchParams(window.location.search).get('token');
3615
4725
  if(qp){authTok='?token='+encodeURIComponent(qp)}
3616
4726
  }catch(e){/* ignore */}
3617
- function reloadIfChanged(prev){
3618
- fetch('/api/state'+authTok).then(function(r){return r.json()}).then(function(s){
3619
- if(s.generatedAt!==prev&&!configActive()&&!lifecycleActive()){location.reload()}
3620
- }).catch(function(){});
3621
- }
3622
- var current=document.documentElement.getAttribute('data-generated')||'';
4727
+ ${CONSOLE_REFRESH_JS}
4728
+ var es=null;
4729
+ function openStateStream(){
3623
4730
  if('EventSource' in window){
3624
4731
  try{
3625
- var es=new EventSource('/events'+authTok);
4732
+ es=new EventSource('/events'+authTok);
3626
4733
  es.addEventListener('state',function(ev){
3627
- try{
3628
- var d=JSON.parse(ev.data||'{}');
3629
- if(d.generatedAt&&d.generatedAt!==current&&!configActive()&&!lifecycleActive()){location.reload()}
3630
- }catch(e){}
4734
+ refreshView();
3631
4735
  });
3632
4736
  es.addEventListener('graph-append',function(ev){
3633
4737
  try{
@@ -3638,26 +4742,22 @@ var CONSOLE_CLIENT_JS = `
3638
4742
  es.onerror=function(){/* fallback below */};
3639
4743
  }catch(e){/* ignore */}
3640
4744
  }
4745
+ }
3641
4746
  var ms=parseInt(document.documentElement.getAttribute('data-refresh')||'2000',10);
3642
- setInterval(function(){reloadIfChanged(current)},isNaN(ms)?2000:Math.max(250,ms));
4747
+ startRefresh();
4748
+ openStateStream();
3643
4749
 
3644
- function configActive(){
3645
- var s=document.getElementById('screen-config');
3646
- return !!(s&&!s.hidden);
3647
- }
3648
- // Only the visible timeline owns incremental refresh. Other screens still
3649
- // need state reloads; their navigation preserves the timeline URL selection.
3650
- function lifecycleActive(){
3651
- var mount=document.getElementById('lifecycle-timeline-mount');
3652
- var screen=mount&&mount.closest('.screen');
3653
- return !!(screen&&!screen.hidden);
3654
- }
3655
4750
  function wireLogsScreen(screen){
3656
- if(screen.__logsWired){return}
3657
- screen.__logsWired=true;
3658
- var buttons=screen.querySelectorAll('[data-session-target]');
3659
- var cards=screen.querySelectorAll('[data-session-view]');
4751
+ function filterSessions(){
4752
+ var filter=screen.querySelector('[data-log-filter]');
4753
+ var value=filter?filter.value.toLowerCase():'';
4754
+ var buttons=screen.querySelectorAll('[data-session-target]');
4755
+ for(var i=0;i<buttons.length;i++){buttons[i].hidden=buttons[i].getAttribute('data-session-target').toLowerCase().indexOf(value)===-1}
4756
+ }
3660
4757
  function showSession(id){
4758
+ var buttons=screen.querySelectorAll('[data-session-target]');
4759
+ var cards=screen.querySelectorAll('[data-session-view]');
4760
+ screen.__selectedSession=id;
3661
4761
  var matched=false;
3662
4762
  for(var i=0;i<buttons.length;i++){
3663
4763
  var on=buttons[i].getAttribute('data-session-target')===id;
@@ -3667,19 +4767,41 @@ var CONSOLE_CLIENT_JS = `
3667
4767
  for(var j=0;j<cards.length;j++){
3668
4768
  var show=cards[j].getAttribute('data-session-view')===id;
3669
4769
  cards[j].hidden=!show;
3670
- if(show){matched=true;connectTerminal(cards[j],id)}
4770
+ if(show){matched=true;if(!screen.hidden){connectTerminal(cards[j],id)}}
3671
4771
  }
4772
+ updateTerminalLeases();
3672
4773
  return matched;
3673
4774
  }
3674
- for(var k=0;k<buttons.length;k++){
3675
- buttons[k].addEventListener('click',function(e){
3676
- var id=e.currentTarget.getAttribute('data-session-target');
3677
- if(id){showSession(id)}
4775
+ if(!screen.__logsWired){
4776
+ screen.__logsWired=true;
4777
+ screen.addEventListener('click',function(e){
4778
+ var button=e.target.closest('[data-session-target]');
4779
+ if(button){showSession(button.getAttribute('data-session-target'))}
4780
+ if(e.target.closest('[data-log-incoming]')){applyView(true);followTerminalOutput(screen)}
3678
4781
  });
4782
+ var follow=screen.querySelector('[data-log-follow]');
4783
+ if(follow){follow.addEventListener('change',function(){
4784
+ if(follow.checked){
4785
+ applyView(true);followTerminalOutput(screen);
4786
+ var viewport=document.querySelector('.scroll');if(viewport){viewport.scrollTop=viewport.scrollHeight}
4787
+ }
4788
+ })}
4789
+ var filter=screen.querySelector('[data-log-filter]');
4790
+ if(filter){filter.addEventListener('input',filterSessions)}
4791
+ var scroll=document.querySelector('.scroll');
4792
+ if(scroll&&follow){
4793
+ scroll.addEventListener('scroll',function(){if(!screen.hidden&&scroll.scrollHeight-scroll.scrollTop-scroll.clientHeight>40){follow.checked=false}});
4794
+ screen.addEventListener('scroll',function(e){
4795
+ var target=e.target;
4796
+ if(target.scrollHeight-target.scrollTop-target.clientHeight>40){follow.checked=false}
4797
+ },true);
4798
+ }
3679
4799
  }
4800
+ var buttons=screen.querySelectorAll('[data-session-target]');
3680
4801
  if(buttons.length>0){
3681
- showSession(buttons[0].getAttribute('data-session-target'));
4802
+ if(!showSession(screen.__selectedSession)){showSession(buttons[0].getAttribute('data-session-target'))}
3682
4803
  }
4804
+ filterSessions();
3683
4805
  }
3684
4806
  function selectScreen(name){
3685
4807
  var screens=document.querySelectorAll('.screen');
@@ -3707,6 +4829,7 @@ var CONSOLE_CLIENT_JS = `
3707
4829
  if(title){title.textContent=titleText}
3708
4830
  if(name==='config'&&activeScreen){loadConfig(activeScreen)}
3709
4831
  if(name==='logs'&&activeScreen){wireLogsScreen(activeScreen)}
4832
+ updateTerminalLeases();
3710
4833
  try{localStorage.setItem('openteam.screen',name)}catch(e){}
3711
4834
  document.body.classList.remove('nav-open');
3712
4835
  return true;
@@ -3754,28 +4877,74 @@ var CONSOLE_CLIENT_JS = `
3754
4877
  .catch(function(){if(btn){btn.disabled=false}out.innerHTML='<div class="config-summary"><p class="config-err">Save failed.</p></div>'});
3755
4878
  });
3756
4879
  }
4880
+ function disconnectTerminal(view){
4881
+ clearTimeout(view.__lease);view.__lease=null;
4882
+ terminalCollectors=terminalCollectors.filter(function(item){return item!==view});
4883
+ if(view.__stream){
4884
+ view.__stream.close();view.__stream=null;
4885
+ if(view.__append){view.__append('status',detailMsg.terminalGap)}
4886
+ }
4887
+ }
4888
+ function updateTerminalLeases(){
4889
+ terminalCollectors.forEach(function(view){
4890
+ var screen=view.closest('.screen');
4891
+ if(!view.hidden&&screen&&!screen.hidden){clearTimeout(view.__lease);view.__lease=null}
4892
+ else if(!view.__lease){view.__lease=setTimeout(function(){disconnectTerminal(view)},300000)}
4893
+ });
4894
+ }
4895
+ function followTerminalOutput(screen){
4896
+ screen.querySelectorAll('.termlog').forEach(function(log){
4897
+ log.scrollTop=log.scrollHeight;log.__incoming=false;
4898
+ });
4899
+ var incoming=screen.querySelector('[data-log-incoming]');
4900
+ if(incoming&&(!latestView||latestView.logs===appliedLogs)){incoming.hidden=true}
4901
+ }
3757
4902
  function connectTerminal(view,id){
3758
- if(view.__wired){return}
3759
4903
  var root=document.documentElement;
3760
4904
  var token=root.getAttribute('data-token');
3761
4905
  if(root.getAttribute('data-terminal')!=='1'||!token){return}
3762
4906
  var log=view.querySelector('.termlog');
3763
4907
  if(!log){return}
3764
- view.__wired=true;
3765
4908
  function append(cls,text){
4909
+ var atBottom=log.scrollHeight-log.scrollTop-log.clientHeight<40;
4910
+ var screen=view.closest('.screen');
4911
+ var follow=screen&&screen.querySelector('[data-log-follow]');
3766
4912
  var line=document.createElement('div');
3767
- line.className='tl '+cls;line.textContent=text;
3768
- log.appendChild(line);log.scrollTop=log.scrollHeight;
4913
+ line.className='tl '+cls;line.textContent=String(text).slice(0,16384);
4914
+ log.appendChild(line);
4915
+ var removed=false;
4916
+ while(log.children.length>1000||log.textContent.length>262144){log.removeChild(log.firstChild);removed=true}
4917
+ if(removed){
4918
+ var notice=view.querySelector('[data-terminal-truncated]');
4919
+ if(!notice){notice=document.createElement('p');notice.setAttribute('data-terminal-truncated','');log.before(notice)}
4920
+ notice.textContent=detailMsg.terminalTrimmed;
4921
+ }
4922
+ if(cls==='input'||(atBottom&&follow&&follow.checked)){log.scrollTop=log.scrollHeight}
4923
+ else{
4924
+ log.__incoming=true;
4925
+ var incoming=screen&&screen.querySelector('[data-log-incoming]');
4926
+ if(incoming){incoming.hidden=false}
4927
+ }
3769
4928
  }
3770
4929
  var q='/console/session/'+encodeURIComponent(id);
3771
4930
  var tk='token='+encodeURIComponent(token);
3772
- if('EventSource' in window){
4931
+ view.__append=append;
4932
+ if(!view.__stream&&'EventSource' in window){
3773
4933
  try{
4934
+ while(terminalCollectors.length>=2){disconnectTerminal(terminalCollectors[0])}
3774
4935
  var es=new EventSource(q+'/stream?'+tk);
3775
- es.addEventListener('frame',function(e){try{var f=JSON.parse(e.data);append(f.kind,f.text)}catch(_){}});
3776
- es.onerror=function(){/* reconnects on its own */};
4936
+ view.__stream=es;
4937
+ terminalCollectors.push(view);
4938
+ es.addEventListener('frame',function(e){if(view.__stream!==es){return}try{var f=JSON.parse(e.data);append(f.kind,f.text)}catch(_){}});
4939
+ es.onerror=function(){if(view.__stream===es){append('status',detailMsg.terminalGap)}};
3777
4940
  }catch(_){/* ignore */}
3778
4941
  }
4942
+ // Two recently selected sessions collect bounded output across tabs; hidden
4943
+ // collectors expire after five minutes and never occupy unbounded sockets.
4944
+ if(view.__stream){terminalCollectors=terminalCollectors.filter(function(item){return item!==view}).concat(view)}
4945
+ updateTerminalLeases();
4946
+ if(view.__wired){return}
4947
+ view.__wired=true;
3779
4948
  var form=view.querySelector('form.terminput');
3780
4949
  if(form){
3781
4950
  form.addEventListener('submit',function(e){
@@ -3847,29 +5016,41 @@ var CONSOLE_CLIENT_JS = `
3847
5016
  var title=drill.querySelector('.drill-title');
3848
5017
  if(!log){return}
3849
5018
  var es=null;
5019
+ var epoch=0,request=null;
5020
+ function closeDrill(){
5021
+ epoch++;
5022
+ if(es){es.close();es=null}
5023
+ if(request){request.abort();request=null}
5024
+ }
5025
+ window.addEventListener('pagehide',closeDrill);
5026
+ document.addEventListener('conversation-selection',function(){closeDrill();log.textContent='';drill.hidden=true});
3850
5027
  function append(cls,text){
3851
5028
  var line=document.createElement('div');
3852
5029
  line.className='tl '+cls;line.textContent=text;
3853
5030
  log.appendChild(line);log.scrollTop=log.scrollHeight;
3854
5031
  }
3855
5032
  function open(id){
3856
- if(es){try{es.close()}catch(_){}}
5033
+ closeDrill();
5034
+ var current=epoch;
5035
+ request=new AbortController();
3857
5036
  log.textContent='';drill.hidden=false;
3858
5037
  if(title){title.textContent='Conversation · '+id}
3859
5038
  var tk='token='+encodeURIComponent(token);
3860
5039
  var base='/console/session/'+encodeURIComponent(id);
3861
- fetch(base+'/messages?'+tk).then(function(r){return r.ok?r.json():Promise.reject(r.status)})
3862
- .then(function(d){(d&&d.frames||[]).forEach(function(f){append(f.kind,f.text)})})
3863
- .catch(function(s){append('error','✖ could not load conversation ('+s+')')});
5040
+ fetch(base+'/messages?'+tk,{signal:request.signal}).then(function(r){return r.ok?r.json():Promise.reject(r.status)})
5041
+ .then(function(d){if(epoch===current){(d&&d.frames||[]).forEach(function(f){append(f.kind,f.text)})}})
5042
+ .catch(function(s){if(epoch===current){append('error','✖ could not load conversation ('+s+')')}});
3864
5043
  if('EventSource' in window){
3865
5044
  try{
3866
5045
  es=new EventSource(base+'/stream?'+tk);
3867
- es.addEventListener('frame',function(e){try{var f=JSON.parse(e.data);append(f.kind,f.text)}catch(_){}});
5046
+ es.addEventListener('frame',function(e){if(epoch!==current){return}try{var f=JSON.parse(e.data);append(f.kind,f.text)}catch(_){}});
3868
5047
  es.onerror=function(){/* reconnects on its own */};
3869
5048
  }catch(_){/* ignore */}
3870
5049
  }
3871
5050
  }
3872
5051
  gview.addEventListener('click',function(e){
5052
+ var timeline=document.getElementById('lifecycle-timeline-mount');
5053
+ if(timeline&&timeline.getAttribute('data-conversation-transition')==='1'){return}
3873
5054
  var t=e.target;
3874
5055
  while(t&&t!==gview&&!(t.getAttribute&&t.getAttribute('data-session'))){t=t.parentNode}
3875
5056
  if(t&&t.getAttribute&&t.getAttribute('data-session')){open(t.getAttribute('data-session'))}
@@ -3891,7 +5072,8 @@ var CONSOLE_CLIENT_JS = `
3891
5072
  try{saved=localStorage.getItem('openteam.screen')||'tree'}catch(e){}
3892
5073
  if(!selectScreen(saved)){selectScreen('tree')}
3893
5074
  wireGraphDrill();
3894
- wireLifecycleTimeline();
5075
+ if(typeof wireLifecycleTimeline==='function'){wireLifecycleTimeline()}
5076
+ if(typeof wireConversationInspector==='function'){wireConversationInspector()}
3895
5077
  })();
3896
5078
  `;
3897
5079
  var LIFECYCLE_STYLE = `
@@ -4049,6 +5231,8 @@ var LIFECYCLE_THEME_BOOT = `
4049
5231
  })();
4050
5232
  `;
4051
5233
  var LIFECYCLE_CLIENT_JS = `
5234
+ ${LABELS_CLIENT_JS}
5235
+ ${CONVERSATION_CLIENT_JS}
4052
5236
  function wireLifecycleTimeline(){
4053
5237
  var mount=document.getElementById('lifecycle-timeline-mount');
4054
5238
  if(!mount){return}
@@ -4087,6 +5271,28 @@ function wireLifecycleTimeline(){
4087
5271
  lastSseHead:new Map()
4088
5272
  };
4089
5273
  var projectionKey='';
5274
+ var committedRun=mount.getAttribute('data-lifecycle-run')||null,committedCursor=urlCursor();
5275
+
5276
+ function invalidateConversation(){
5277
+ mount.setAttribute('data-conversation-transition','1');
5278
+ if(treeMountEl){
5279
+ treeMountEl.setAttribute('inert','');
5280
+ treeMountEl.querySelectorAll('[data-inspect-attempt],[data-inspect-root]').forEach(function(button){button.disabled=true});
5281
+ }
5282
+ document.dispatchEvent(new CustomEvent('conversation-selection'));
5283
+ }
5284
+ function commitConversation(run,cursor){
5285
+ cursor=cursor===null?null:String(cursor);
5286
+ if(run!==committedRun||cursor!==committedCursor){invalidateConversation()}
5287
+ committedRun=run;committedCursor=cursor;
5288
+ mount.setAttribute('data-conversation-cursor',cursor===null?'':String(cursor));
5289
+ mount.removeAttribute('data-conversation-transition');
5290
+ if(treeMountEl){
5291
+ treeMountEl.removeAttribute('inert');
5292
+ treeMountEl.querySelectorAll('[data-inspect-attempt],[data-inspect-root]').forEach(function(button){button.disabled=false});
5293
+ }
5294
+ document.dispatchEvent(new CustomEvent('conversation-tree-committed'));
5295
+ }
4090
5296
 
4091
5297
  function urlCursor(){
4092
5298
  try{
@@ -4168,6 +5374,7 @@ function wireLifecycleTimeline(){
4168
5374
  }
4169
5375
 
4170
5376
  function navigateFromUrl(initial){
5377
+ invalidateConversation();
4171
5378
  state.generation++;
4172
5379
  cancelRequest();
4173
5380
  state.pending=false;
@@ -4181,6 +5388,9 @@ function wireLifecycleTimeline(){
4181
5388
  }
4182
5389
 
4183
5390
  function handleResponse(d,requestedCursor){
5391
+ if(!d||(d.kind!=='view'&&d.kind!=='legacy')||(d.selection&&(d.selection.runID!==committedRun||(requestedCursor===null?null:String(requestedCursor))!==committedCursor))){
5392
+ invalidateConversation();
5393
+ }
4184
5394
  if(!d||d.version!==1){showError();return}
4185
5395
  if(d.kind==='error'){showApiError(d.error);return}
4186
5396
  if(d.kind==='disabled'){showDisabled(d);return}
@@ -4385,6 +5595,7 @@ function wireLifecycleTimeline(){
4385
5595
  mount.setAttribute('data-lifecycle-state', state.followLive?'live':'paused');
4386
5596
  mount.setAttribute('data-lifecycle-run', d.selection.runID||'');
4387
5597
  mount.setAttribute('data-lifecycle-head', String(state.head));
5598
+ commitConversation(d.selection.runID,requestedCursor);
4388
5599
  }
4389
5600
 
4390
5601
  function syncRunOptions(runs,selectedID){
@@ -4399,12 +5610,16 @@ function wireLifecycleTimeline(){
4399
5610
  for(var i=0;i<runs.length;i++){
4400
5611
  var opt=document.createElement('option');
4401
5612
  opt.value=runs[i].runID;
4402
- var label=runs[i].runID.slice(0,16)+(runs[i].source==='legacy-graph'?' (legacy)':'');
4403
- opt.textContent=label;
5613
+ opt.textContent=consoleLabels.runLabel(runs[i]);
4404
5614
  runSelect.appendChild(opt);
4405
5615
  }
4406
5616
  }
5617
+ runs.forEach(function(run){
5618
+ var opt=Array.from(runSelect.options).find(function(option){return option.value===run.runID});
5619
+ if(opt){opt.title=run.runID;opt.setAttribute('data-run-started',run.startedAt===null?'':String(run.startedAt));opt.setAttribute('data-run-authority',run.executionAuthority);opt.setAttribute('data-run-session',run.rootSessionID||'')}
5620
+ });
4407
5621
  runSelect.value=selectedID;
5622
+ var technical=mount.querySelector('[data-lifecycle-run-id]');if(technical&&technical.textContent!==selectedID){technical.textContent=selectedID}
4408
5623
  }
4409
5624
 
4410
5625
  function renderLegacy(d){
@@ -4441,14 +5656,17 @@ function wireLifecycleTimeline(){
4441
5656
  mount.setAttribute('data-lifecycle-state','legacy');
4442
5657
  mount.setAttribute('data-lifecycle-run',d.selection.runID||'');
4443
5658
  mount.setAttribute('data-lifecycle-head','0');
5659
+ commitConversation(d.selection.runID,null);
4444
5660
  }
4445
5661
 
4446
5662
  function renderProjection(proj,recording){
4447
5663
  if(!proj||!treeMountEl){return}
4448
5664
  var degraded=recording&&recording.state==='degraded';
4449
- var key=JSON.stringify([proj.runID,proj.cursor,proj.rootOperationID,proj.operations,degraded]);
5665
+ var option=runSelect&&Array.from(runSelect.options).find(function(o){return o.value===proj.runID});
5666
+ var key=JSON.stringify([proj.runID,proj.cursor,proj.rootOperationID,proj.operations,degraded,option&&option.getAttribute('data-run-session')]);
4450
5667
  if(key===projectionKey){return}
4451
5668
  projectionKey=key;
5669
+ document.dispatchEvent(new CustomEvent('conversation-tree-replacing'));
4452
5670
  treeMountEl.textContent='';
4453
5671
  if(degraded){
4454
5672
  var note=makeElement('div','lc-partial-note',message('partial-tail'));
@@ -4507,7 +5725,7 @@ function wireLifecycleTimeline(){
4507
5725
  parent.appendChild(box);
4508
5726
  }
4509
5727
 
4510
- function appendSession(parent,attempt){
5728
+ function appendSession(parent,attempt,role){
4511
5729
  if(!attempt.sessionID){
4512
5730
  parent.appendChild(makeElement('div','lct-session-empty',message('no-session')));
4513
5731
  return;
@@ -4515,7 +5733,16 @@ function wireLifecycleTimeline(){
4515
5733
  var session=makeElement('div','lct-session');
4516
5734
  session.setAttribute('data-lifecycle-session-id',attempt.sessionID);
4517
5735
  session.appendChild(makeElement('span','',message('session')));
4518
- session.appendChild(makeElement('code','',attempt.sessionID));
5736
+ var name=makeElement('span','',role);name.setAttribute('data-session-name',attempt.sessionID);session.appendChild(name);
5737
+ var time=makeElement('small','',${JSON.stringify(consoleDetailMessages.timeUnknown)});time.setAttribute('data-session-time',attempt.sessionID);session.appendChild(time);
5738
+ var technical=makeElement('details','');technical.appendChild(makeElement('summary','',${JSON.stringify(consoleDetailMessages.technicalID)}));technical.appendChild(makeElement('code','',attempt.sessionID));session.appendChild(technical);
5739
+ var inspect=makeElement('button','',message('inspect'));
5740
+ inspect.type='button';
5741
+ inspect.setAttribute('aria-expanded','false');
5742
+ inspect.setAttribute('aria-controls','lc-attempt-conversation');
5743
+ inspect.setAttribute('data-inspect-attempt',attempt.attemptID);
5744
+ inspect.setAttribute('data-inspect-operation',attempt.operationID);
5745
+ session.appendChild(inspect);
4519
5746
  if(attempt.parentSessionID){
4520
5747
  var parentSession=makeElement('span','lct-parent-session',message('parent-session')+' ');
4521
5748
  parentSession.appendChild(makeElement('code','',attempt.parentSessionID));
@@ -4524,7 +5751,7 @@ function wireLifecycleTimeline(){
4524
5751
  parent.appendChild(session);
4525
5752
  }
4526
5753
 
4527
- function buildAttempt(attempt){
5754
+ function buildAttempt(attempt,role){
4528
5755
  var article=makeElement('article','lct-attempt');
4529
5756
  article.setAttribute('data-lifecycle-attempt-id',attempt.attemptID);
4530
5757
  article.setAttribute('data-lifecycle-attempt-state',attempt.state);
@@ -4557,7 +5784,7 @@ function wireLifecycleTimeline(){
4557
5784
  model.appendChild(makeElement('code','',identity));
4558
5785
  article.appendChild(model);
4559
5786
  }
4560
- appendSession(article,attempt);
5787
+ appendSession(article,attempt,role);
4561
5788
  return article;
4562
5789
  }
4563
5790
 
@@ -4604,7 +5831,9 @@ function wireLifecycleTimeline(){
4604
5831
  var header=makeElement('header','lct-operation-head');
4605
5832
  var identity=makeElement('div','');
4606
5833
  identity.appendChild(makeElement('span','lct-operation-label',message('operation')));
4607
- identity.appendChild(makeElement('code','lct-operation-id',op.operationID));
5834
+ var name=makeElement('strong','lct-operation-name',op.agentID||op.roleID);
5835
+ identity.appendChild(name);
5836
+ var technical=makeElement('details','');technical.appendChild(makeElement('summary','',${JSON.stringify(consoleDetailMessages.technicalID)}));technical.appendChild(makeElement('code','lct-operation-id',op.operationID));identity.appendChild(technical);
4608
5837
  header.appendChild(identity);
4609
5838
  header.appendChild(stateBadge(op.state));
4610
5839
  card.appendChild(header);
@@ -4624,7 +5853,7 @@ function wireLifecycleTimeline(){
4624
5853
  if(attemptList.length===0){
4625
5854
  attempts.appendChild(makeElement('div','lct-no-attempts',message('no-attempts')));
4626
5855
  }else{
4627
- attemptList.forEach(function(attempt){attempts.appendChild(buildAttempt(attempt))});
5856
+ attemptList.forEach(function(attempt){attempts.appendChild(buildAttempt(attempt,op.agentID||op.roleID))});
4628
5857
  }
4629
5858
  card.appendChild(attempts);
4630
5859
  article.appendChild(card);
@@ -4652,6 +5881,21 @@ function wireLifecycleTimeline(){
4652
5881
  if(visited.has(op.operationID)){return null}
4653
5882
  visited.add(op.operationID);
4654
5883
  var article=buildOperation(op,known,depth);
5884
+ if(op.operationID===proj.rootOperationID&&op.kind==='coordinator'){
5885
+ var option=runSelect&&Array.from(runSelect.options).find(function(o){return o.value===proj.runID});
5886
+ var rootID=option&&option.getAttribute('data-run-session')||'';
5887
+ var card=article.querySelector('.lct-operation-card'),name=card.querySelector('.lct-operation-name');
5888
+ name.setAttribute('data-run-name',proj.runID);
5889
+ if(rootID){name.setAttribute('data-session-name',rootID)}
5890
+ var rootSession=makeElement('div','lct-session');rootSession.setAttribute('data-root-session-id',rootID);
5891
+ if(rootID){
5892
+ var rootName=makeElement('span','',${JSON.stringify(consoleDetailMessages.orchestrator)});rootName.setAttribute('data-session-name',rootID);rootSession.appendChild(rootName);
5893
+ var time=makeElement('small','',${JSON.stringify(consoleDetailMessages.timeUnknown)});time.setAttribute('data-session-time',rootID);rootSession.appendChild(time);
5894
+ var id=makeElement('code','',rootID);rootSession.appendChild(id);
5895
+ }else{rootSession.appendChild(makeElement('span','',${JSON.stringify(consoleDetailMessages.rootUnlinked)}))}
5896
+ var inspect=makeElement('button','',message('inspect'));inspect.type='button';inspect.setAttribute('data-inspect-root','');inspect.setAttribute('data-inspect-operation',op.operationID);inspect.setAttribute('aria-expanded','false');inspect.setAttribute('aria-controls','lc-attempt-conversation');rootSession.appendChild(inspect);
5897
+ card.insertBefore(rootSession,card.querySelector('.lct-attempts'));
5898
+ }
4655
5899
  var children=childrenByParent.get(op.operationID)||[];
4656
5900
  var childNodes=[];
4657
5901
  children.forEach(function(child){
@@ -4761,6 +6005,7 @@ function wireLifecycleTimeline(){
4761
6005
  }
4762
6006
 
4763
6007
  function showError(){
6008
+ invalidateConversation();
4764
6009
  projectionKey='';
4765
6010
  mount.setAttribute('data-lifecycle-state','error');
4766
6011
  updateScreenCopy('unavailable',false,null);
@@ -4873,6 +6118,11 @@ function wireLifecycleTimeline(){
4873
6118
  var lcRefreshMs=parseInt(document.documentElement.getAttribute('data-refresh')||'2000',10);
4874
6119
  if(isNaN(lcRefreshMs)||lcRefreshMs<500){lcRefreshMs=2000;}
4875
6120
  var pollTimer=setInterval(fetchHistory,lcRefreshMs);
6121
+ document.addEventListener('console-refresh-changed',function(e){
6122
+ lcRefreshMs=e.detail;
6123
+ clearInterval(pollTimer);
6124
+ if(!state.stopped){pollTimer=setInterval(fetchHistory,lcRefreshMs)}
6125
+ });
4876
6126
  window.addEventListener('pagehide',function(){
4877
6127
  state.stopped=true;
4878
6128
  state.generation++;
@@ -4920,8 +6170,7 @@ function agentModel(agent) {
4920
6170
  return agent.model === undefined ? "inherits default" : `${agent.model.providerID}/${agent.model.modelID}`;
4921
6171
  }
4922
6172
  function domIdPart(value) {
4923
- const cleaned = value.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
4924
- return cleaned.length === 0 ? "session" : cleaned;
6173
+ return Array.from({ length: value.length }, (_, index) => value.charCodeAt(index).toString(16).padStart(4, "0")).join("");
4925
6174
  }
4926
6175
  function panelId(base, idSuffix) {
4927
6176
  return idSuffix === undefined ? base : `${base}-${idSuffix}`;
@@ -5065,11 +6314,20 @@ function totalsPanel(totals) {
5065
6314
  "</section>"
5066
6315
  ].join("");
5067
6316
  }
6317
+ function sessionName(session) {
6318
+ return boundedTitle(session.endpoint?.title) ?? boundedTitle(session.agents.join(", ")) ?? consoleDetailMessages.session;
6319
+ }
6320
+ function sessionNameHtml(id, fallback) {
6321
+ return `<span data-session-name="${escapeHtml(id)}">${escapeHtml(fallback)}</span>`;
6322
+ }
6323
+ function observedTimeHtml(session) {
6324
+ return `<small data-session-time="${escapeHtml(session.sessionID)}">${escapeHtml(consoleDetailMessages.firstObserved)}: ${escapeHtml(utcTime(session.firstTs))}</small>`;
6325
+ }
5068
6326
  function sessionRow(session) {
5069
6327
  const models = session.models.map(escapeHtml).join("<br>") || "—";
5070
6328
  return [
5071
6329
  "<tr>",
5072
- `<td class="hash">${escapeHtml(session.sessionID)}</td>`,
6330
+ `<td>${sessionNameHtml(session.sessionID, sessionName(session))}<br>${observedTimeHtml(session)}<br><code>${escapeHtml(session.sessionID)}</code></td>`,
5073
6331
  `<td>${models}</td>`,
5074
6332
  `<td><span class="local">${session.localCount}</span>/<span class="frontier">${session.frontierCount}</span></td>`,
5075
6333
  `<td>${usd(session.realCostUSD)}</td>`,
@@ -5181,7 +6439,7 @@ function sidebarNav(liveCount, logCount) {
5181
6439
  "</nav>",
5182
6440
  '<div class="sidebar-foot">',
5183
6441
  '<div class="host-row"><span class="dot live"></span><span>loopback console</span></div>',
5184
- '<div class="host-row faint"><span>prompts stay redacted by hash</span></div>',
6442
+ `<div class="host-row faint"><span>${escapeHtml(consoleDetailMessages.metadataOnly)}</span></div>`,
5185
6443
  "</div>",
5186
6444
  "</aside>"
5187
6445
  ].join("");
@@ -5199,11 +6457,13 @@ function screenSection(screen, label, heading, description, body, active = false
5199
6457
  function sessionHeaderPanel(tab) {
5200
6458
  const endpoint = tab.endpoint === undefined ? '<span class="muted">endpoint not announced</span>' : `<code>${escapeHtml(tab.endpoint.url)}</code>`;
5201
6459
  const dir = tab.endpoint?.directory === undefined ? "" : `<div class="stat"><span class="k">Directory</span><span class="v mono">${escapeHtml(tab.endpoint.directory)}</span></div>`;
5202
- const title = tab.endpoint?.title === undefined ? "" : `<div class="stat"><span class="k">Title</span><span class="v">${escapeHtml(tab.endpoint.title)}</span></div>`;
6460
+ const title = tab.endpoint?.title === undefined ? "" : `<div class="stat"><span class="k">Title</span><span class="v">${escapeHtml(boundedTitle(tab.endpoint.title) ?? consoleDetailMessages.session)}</span></div>`;
5203
6461
  const s = tab.summary;
5204
6462
  return [
5205
6463
  '<section class="panel">',
5206
- `<h2>Session ${escapeHtml(shortSessionID(tab.sessionID))} ${statusBadge(tab.status)}</h2>`,
6464
+ `<h2>${sessionNameHtml(tab.sessionID, sessionName(s))} ${statusBadge(tab.status)}</h2>`,
6465
+ observedTimeHtml(s),
6466
+ `<div>${escapeHtml(consoleDetailMessages.technicalID)}: <code>${escapeHtml(tab.sessionID)}</code></div>`,
5207
6467
  '<div class="grid">',
5208
6468
  `<div class="stat"><span class="k">Endpoint</span><span class="v">${endpoint}</span></div>`,
5209
6469
  dir,
@@ -5241,8 +6501,8 @@ function ptyPanel(tab) {
5241
6501
  "</section>"
5242
6502
  ].join("");
5243
6503
  }
5244
- function sessionDetailCard(tab, terminalEnabled, ptyEnabled, visible, index) {
5245
- const idSuffix = `${index}-${domIdPart(tab.sessionID)}`;
6504
+ function sessionDetailCard(tab, terminalEnabled, ptyEnabled, visible) {
6505
+ const idSuffix = domIdPart(tab.sessionID);
5246
6506
  const body = [
5247
6507
  sessionHeaderPanel(tab),
5248
6508
  terminalEnabled ? terminalPanel(tab) : "",
@@ -5484,6 +6744,7 @@ function lcDataAttrs() {
5484
6744
  ["data-msg-selection", lifecycleMessages.selectionLabel],
5485
6745
  ["data-msg-runtime", lifecycleMessages.runtimeLabel],
5486
6746
  ["data-msg-session", lifecycleMessages.sessionLabel],
6747
+ ["data-msg-inspect", consoleDetailMessages.inspectConversation],
5487
6748
  ["data-msg-no-session", lifecycleMessages.noSession],
5488
6749
  ["data-msg-parent-session", lifecycleMessages.parentSessionLabel],
5489
6750
  ["data-msg-depends-on", lifecycleMessages.dependsOnLabel],
@@ -5509,9 +6770,9 @@ function lcRunOptions(runs, selectedID) {
5509
6770
  if (runs.length === 0)
5510
6771
  return "";
5511
6772
  return runs.map((r) => {
5512
- const label = r.runID.slice(0, 16) + (r.source === "legacy-graph" ? " (legacy)" : "");
6773
+ const label = runLabel(r);
5513
6774
  const sel = r.runID === selectedID ? " selected" : "";
5514
- return `<option value="${escapeHtml(r.runID)}"${sel}>${escapeHtml(label)}</option>`;
6775
+ return `<option value="${escapeHtml(r.runID)}" title="${escapeHtml(r.runID)}" data-run-started="${r.startedAt ?? ""}" data-run-authority="${r.executionAuthority}" data-run-session="${escapeHtml(r.rootSessionID ?? "")}"${sel}>${escapeHtml(label)}</option>`;
5515
6776
  }).join("");
5516
6777
  }
5517
6778
  function lcActivityBadge(activity) {
@@ -5550,6 +6811,7 @@ function lcControls(runs, selectedID, followLive, activity, liveDisabled = false
5550
6811
  "</button>",
5551
6812
  lcActivityBadge(activity),
5552
6813
  `<span class="lc-incoming-badge" data-lifecycle-incoming hidden></span>`,
6814
+ `<details><summary>${escapeHtml(consoleDetailMessages.technicalID)}</summary><code data-lifecycle-run-id>${escapeHtml(selectedID ?? "")}</code></details>`,
5553
6815
  "</div>"
5554
6816
  ].join("");
5555
6817
  }
@@ -5618,19 +6880,22 @@ function lcFailureHtml(failure) {
5618
6880
  "</div>"
5619
6881
  ].join("");
5620
6882
  }
5621
- function lcSessionHtml(attempt) {
6883
+ function lcSessionHtml(attempt, role) {
5622
6884
  if (attempt.sessionID === undefined) {
5623
6885
  return `<div class="lct-session-empty">${escapeHtml(lifecycleMessages.noSession)}</div>`;
5624
6886
  }
5625
6887
  return [
5626
6888
  `<div class="lct-session" data-lifecycle-session-id="${escapeHtml(attempt.sessionID)}">`,
5627
6889
  `<span>${escapeHtml(lifecycleMessages.sessionLabel)}</span>`,
5628
- `<code>${escapeHtml(attempt.sessionID)}</code>`,
6890
+ sessionNameHtml(attempt.sessionID, role),
6891
+ `<small data-session-time="${escapeHtml(attempt.sessionID)}">${escapeHtml(consoleDetailMessages.timeUnknown)}</small>`,
6892
+ `<details><summary>${escapeHtml(consoleDetailMessages.technicalID)}</summary><code>${escapeHtml(attempt.sessionID)}</code></details>`,
6893
+ `<button type="button" aria-expanded="false" aria-controls="lc-attempt-conversation" data-inspect-operation="${escapeHtml(attempt.operationID)}" data-inspect-attempt="${escapeHtml(attempt.attemptID)}">${escapeHtml(consoleDetailMessages.inspectConversation)}</button>`,
5629
6894
  attempt.parentSessionID === undefined ? "" : `<span class="lct-parent-session">${escapeHtml(lifecycleMessages.parentSessionLabel)} <code>${escapeHtml(attempt.parentSessionID)}</code></span>`,
5630
6895
  "</div>"
5631
6896
  ].join("");
5632
6897
  }
5633
- function lcAttemptHtml(attempt) {
6898
+ function lcAttemptHtml(attempt, role) {
5634
6899
  const model = attempt.model === undefined ? undefined : `${attempt.model.providerID}/${attempt.model.modelID}`;
5635
6900
  const route = attempt.routeKind ?? lifecycleMessages.noRoute;
5636
6901
  return [
@@ -5659,7 +6924,7 @@ function lcAttemptHtml(attempt) {
5659
6924
  `<code>${escapeHtml(model)}</code>`,
5660
6925
  "</div>"
5661
6926
  ].join(""),
5662
- lcSessionHtml(attempt),
6927
+ lcSessionHtml(attempt, role),
5663
6928
  "</article>"
5664
6929
  ].join("");
5665
6930
  }
@@ -5687,16 +6952,17 @@ function lcParentReferenceHtml(operation, operationIDs) {
5687
6952
  "</div>"
5688
6953
  ].join("");
5689
6954
  }
5690
- function lcOperationHtml(operation, operationIDs, childrenHtml, depth) {
6955
+ function lcOperationHtml(operation, operationIDs, childrenHtml, depth, rootSessionID, isRoot = false) {
5691
6956
  const parentAttr = operation.parentOperationID === undefined ? "" : ` data-lifecycle-parent-operation-id="${escapeHtml(operation.parentOperationID)}"`;
5692
- const attempts = operation.attempts.length === 0 ? `<div class="lct-no-attempts">${escapeHtml(lifecycleMessages.noAttempts)}</div>` : operation.attempts.map(lcAttemptHtml).join("");
6957
+ const attempts = operation.attempts.length === 0 ? `<div class="lct-no-attempts">${escapeHtml(lifecycleMessages.noAttempts)}</div>` : operation.attempts.map((attempt) => lcAttemptHtml(attempt, operation.agentID ?? operation.roleID)).join("");
5693
6958
  return [
5694
6959
  `<article class="lct-operation" role="treeitem" aria-level="${depth}" data-lifecycle-operation-id="${escapeHtml(operation.operationID)}"${parentAttr} data-lifecycle-operation-state="${escapeHtml(operation.state)}" data-op-id="${escapeHtml(operation.operationID)}" data-op-state="${escapeHtml(operation.state)}">`,
5695
6960
  '<div class="lct-operation-card">',
5696
6961
  '<header class="lct-operation-head">',
5697
6962
  "<div>",
5698
6963
  `<span class="lct-operation-label">${escapeHtml(lifecycleMessages.operationLabel)}</span>`,
5699
- `<code class="lct-operation-id">${escapeHtml(operation.operationID)}</code>`,
6964
+ `<strong class="lct-operation-name">${rootSessionID ? sessionNameHtml(rootSessionID, operation.agentID ?? operation.roleID) : escapeHtml(operation.agentID ?? operation.roleID)}</strong>`,
6965
+ `<details><summary>${escapeHtml(consoleDetailMessages.technicalID)}</summary><code class="lct-operation-id">${escapeHtml(operation.operationID)}</code></details>`,
5700
6966
  "</div>",
5701
6967
  `<span class="lct-state" data-state="${escapeHtml(operation.state)}"><span class="sr-only">${escapeHtml(lifecycleMessages.stateLabel)}: </span>${escapeHtml(operation.state)}</span>`,
5702
6968
  "</header>",
@@ -5708,13 +6974,19 @@ function lcOperationHtml(operation, operationIDs, childrenHtml, depth) {
5708
6974
  "</dl>",
5709
6975
  lcParentReferenceHtml(operation, operationIDs),
5710
6976
  lcDependenciesHtml(operation, operationIDs),
6977
+ isRoot && operation.kind === "coordinator" ? [
6978
+ `<div class="lct-session" data-root-session-id="${escapeHtml(rootSessionID ?? "")}">`,
6979
+ rootSessionID ? `${sessionNameHtml(rootSessionID, consoleDetailMessages.orchestrator)} <small data-session-time="${escapeHtml(rootSessionID)}">${escapeHtml(consoleDetailMessages.timeUnknown)}</small><details><summary>${escapeHtml(consoleDetailMessages.technicalID)}</summary><code>${escapeHtml(rootSessionID)}</code></details>` : `<span>${escapeHtml(consoleDetailMessages.rootUnlinked)}</span>`,
6980
+ `<button type="button" data-inspect-root data-inspect-operation="${escapeHtml(operation.operationID)}" aria-expanded="false" aria-controls="lc-attempt-conversation">${escapeHtml(consoleDetailMessages.inspectConversation)}</button>`,
6981
+ "</div>"
6982
+ ].join("") : "",
5711
6983
  `<section class="lct-attempts" aria-label="${escapeHtml(lifecycleMessages.attemptsLabel)}">${attempts}</section>`,
5712
6984
  "</div>",
5713
6985
  childrenHtml === "" ? "" : `<div class="lct-operation-children" role="group">${childrenHtml}</div>`,
5714
6986
  "</article>"
5715
6987
  ].join("");
5716
6988
  }
5717
- function renderLifecycleOperationTree(projection) {
6989
+ function renderLifecycleOperationTree(projection, rootSessionID) {
5718
6990
  if (projection.operations.length === 0) {
5719
6991
  return `<div class="lc-empty" role="status">${escapeHtml(lifecycleMessages.noOperationsAtCursor)}</div>`;
5720
6992
  }
@@ -5738,7 +7010,8 @@ function renderLifecycleOperationTree(projection) {
5738
7010
  return "";
5739
7011
  visited.add(operation.operationID);
5740
7012
  const childHtml = (childrenByParent.get(operation.operationID) ?? []).map((child) => renderBranch(child, depth + 1)).join("");
5741
- return lcOperationHtml(operation, operationIDs, childHtml, depth);
7013
+ const isRoot = operation.operationID === projection.rootOperationID;
7014
+ return lcOperationHtml(operation, operationIDs, childHtml, depth, isRoot ? rootSessionID : undefined, isRoot);
5742
7015
  };
5743
7016
  const root = byID.get(projection.rootOperationID);
5744
7017
  const rootHtml = root === undefined ? "" : renderBranch(root, 1);
@@ -5854,7 +7127,7 @@ function renderLifecycleTimelinePanel(lifecycleView) {
5854
7127
  const followLive = selection.followLive;
5855
7128
  const cursor = selection.cursor;
5856
7129
  const head = selection.head;
5857
- const projectionHtml = renderLifecycleOperationTree(projection);
7130
+ const projectionHtml = renderLifecycleOperationTree(projection, runs.find((run) => run.runID === selection.runID)?.rootSessionID);
5858
7131
  const stateAttr = followLive ? "live" : "paused";
5859
7132
  return [
5860
7133
  `<div id="lifecycle-timeline-mount" class="lc-host" role="region" aria-label="${escapeHtml(lifecycleMessages.timelineRegionLabel)}" ${mountAttrs} data-lifecycle-state="${stateAttr}" data-lifecycle-run="${escapeHtml(selection.runID)}" data-lifecycle-head="${head}">`,
@@ -6026,7 +7299,7 @@ function sessionList(sessions) {
6026
7299
  return [
6027
7300
  `<button type="button" class="session-btn${selected ? " sel" : ""}" role="tab" aria-selected="${selected ? "true" : "false"}" data-session-target="${escapeHtml(tab.sessionID)}">`,
6028
7301
  `<span class="dot status-${tab.status}"></span>`,
6029
- `<span class="sid">${escapeHtml(shortSessionID(tab.sessionID))}</span>`,
7302
+ `<span class="sid">${sessionNameHtml(tab.sessionID, sessionName(tab.summary))}<br>${observedTimeHtml(tab.summary)}<br><small class="mono">${escapeHtml(tab.sessionID)}</small></span>`,
6030
7303
  `<span class="n">${tab.summary.messageCount}</span>`,
6031
7304
  "</button>"
6032
7305
  ].join("");
@@ -6044,7 +7317,7 @@ function sessionDetailList(sessions, terminalEnabled, ptyEnabled) {
6044
7317
  if (sessions.length === 0) {
6045
7318
  return '<div class="card empty-state">No session activity recorded yet.</div>';
6046
7319
  }
6047
- return sessions.map((tab, index) => sessionDetailCard(tab, terminalEnabled, ptyEnabled, index === 0, index)).join("");
7320
+ return sessions.map((tab, index) => sessionDetailCard(tab, terminalEnabled, ptyEnabled, index === 0)).join("");
6048
7321
  }
6049
7322
  function logsScreenBody(state, terminalEnabled, ptyEnabled) {
6050
7323
  return [
@@ -6083,11 +7356,11 @@ function renderConsoleHtml(state, options = {}) {
6083
7356
  const body = [
6084
7357
  screenSection("tree", treeCopy.label, treeCopy.heading, treeCopy.description, treeBody, true),
6085
7358
  screenSection("routing", "Routing and telemetry", "Routing + telemetry", "Aggregate routing and cost telemetry from <code>GET /api/state</code> across all sessions.", routingScreenBody(state)),
6086
- screenSection("logs", "Logs and session activity", "Logs / activity", "Per-session activity. Prompts are referenced by hash only and never rendered in clear text.", logsScreenBody(state, terminalEnabled, ptyEnabled)),
7359
+ screenSection("logs", "Logs and session activity", "Logs / activity", "Per-session activity. Prompts are referenced by hash only and never rendered in clear text.", `<div data-log-controls><label>${escapeHtml(consoleDetailMessages.filter)} <input type="search" data-log-filter></label> <label><input type="checkbox" data-log-follow> ${escapeHtml(consoleDetailMessages.follow)}</label> <button type="button" data-log-incoming hidden>${escapeHtml(consoleDetailMessages.incoming)}</button></div><div data-log-content>${logsScreenBody(state, terminalEnabled, ptyEnabled)}</div>`),
6087
7360
  screenSection("config", "Editable configuration", 'Configuration <span class="pill warn">editable</span>', "Edit the whole openteam JSON configuration. Roles are editable inside the JSON when present; unsupported surfaces are not shown.", configScreenBody(options.configEditor?.hasToken === true))
6088
7361
  ].join("");
6089
7362
  const session = state.session.id === undefined ? "" : ` · session ${escapeHtml(state.session.id)}`;
6090
- const tokenAttr = (terminalEnabled || graphDrilldown || configEnabled) && options.consoleToken !== undefined ? ` data-token="${escapeHtml(options.consoleToken)}"${terminalEnabled ? ' data-terminal="1"' : ""}${ptyEnabled ? ' data-pty="1"' : ""}${graphDrilldown ? ' data-drilldown="1"' : ""}${configEnabled ? ' data-config="1"' : ""}` : "";
7363
+ const tokenAttr = (terminalEnabled || graphDrilldown || configEnabled || lifecycleEnabled) && options.consoleToken !== undefined ? ` data-token="${escapeHtml(options.consoleToken)}"${terminalEnabled ? ' data-terminal="1"' : ""}${ptyEnabled ? ' data-pty="1"' : ""}${graphDrilldown ? ' data-drilldown="1"' : ""}${configEnabled ? ' data-config="1"' : ""}` : "";
6091
7364
  return [
6092
7365
  "<!doctype html>",
6093
7366
  `<html lang="en" data-generated="${escapeHtml(state.generatedAt)}" data-refresh="${refreshMs}"${tokenAttr}>`,
@@ -6096,7 +7369,7 @@ function renderConsoleHtml(state, options = {}) {
6096
7369
  '<meta name="viewport" content="width=device-width,initial-scale=1">',
6097
7370
  "<title>openteam console</title>",
6098
7371
  lifecycleEnabled ? `<script>${LIFECYCLE_THEME_BOOT}</script>` : "",
6099
- `<style>${CONSOLE_STYLE}${graphOptionProvided ? GRAPH_STYLE : ""}${lifecycleEnabled ? LIFECYCLE_STYLE : ""}</style>`,
7372
+ `<style>${CONSOLE_STYLE}${graphOptionProvided ? GRAPH_STYLE : ""}${lifecycleEnabled ? LIFECYCLE_STYLE + CONVERSATION_STYLE : ""}</style>`,
6100
7373
  "</head>",
6101
7374
  "<body>",
6102
7375
  '<div class="app">',
@@ -6107,6 +7380,7 @@ function renderConsoleHtml(state, options = {}) {
6107
7380
  '<button type="button" class="icon-btn menu-btn" data-toggle-nav aria-label="Open navigation"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 6h16M4 12h16M4 18h16"></path></svg></button>',
6108
7381
  '<h1 id="screen-title">Agent tree</h1>',
6109
7382
  `<span class="refresh" title="SSE + polling"><span class="beat"></span> ${refreshMs} ms · SSE</span>`,
7383
+ `<span data-refresh-error role="status" hidden>${escapeHtml(consoleDetailMessages.refreshError)}</span>`,
6110
7384
  '<div class="spacer"></div>',
6111
7385
  `<span class="token-chip" title="Page status"><span class="lbl">updated</span> <b class="mono">${escapeHtml(state.generatedAt)}${session}</b></span>`,
6112
7386
  "</header>",
@@ -6120,6 +7394,16 @@ function renderConsoleHtml(state, options = {}) {
6120
7394
  "</html>"
6121
7395
  ].join("");
6122
7396
  }
7397
+ function renderConsoleUpdate(state, options = {}) {
7398
+ return {
7399
+ routing: routingScreenBody(state),
7400
+ logs: logsScreenBody(state, options.terminalEnabled === true, options.ptyEnabled === true),
7401
+ sessionCount: state.sessionsDetail.length,
7402
+ ...options.graphView ? {
7403
+ tree: treeGraphPanel(options.graphView.projection, options.drilldownEnabled === true, false, options.graphView.mode ?? "active")
7404
+ } : {}
7405
+ };
7406
+ }
6123
7407
 
6124
7408
  // src/console/configView.ts
6125
7409
  var OVERLAY_PATH = ".opencode/openteam-local/config.local.json";
@@ -6268,7 +7552,7 @@ function isCrossOriginMutation(request) {
6268
7552
  }
6269
7553
  }
6270
7554
  async function readJsonBody(request, limit) {
6271
- return new Promise((resolve) => {
7555
+ return new Promise((resolve2) => {
6272
7556
  let raw = "";
6273
7557
  let aborted = false;
6274
7558
  request.on("data", (chunk) => {
@@ -6278,7 +7562,7 @@ async function readJsonBody(request, limit) {
6278
7562
  raw += chunk.toString("utf8");
6279
7563
  if (raw.length > limit) {
6280
7564
  aborted = true;
6281
- resolve({ ok: false });
7565
+ resolve2({ ok: false });
6282
7566
  }
6283
7567
  });
6284
7568
  request.on("end", () => {
@@ -6286,12 +7570,12 @@ async function readJsonBody(request, limit) {
6286
7570
  return;
6287
7571
  }
6288
7572
  try {
6289
- resolve({ ok: true, value: JSON.parse(raw) });
7573
+ resolve2({ ok: true, value: JSON.parse(raw) });
6290
7574
  } catch {
6291
- resolve({ ok: false });
7575
+ resolve2({ ok: false });
6292
7576
  }
6293
7577
  });
6294
- request.on("error", () => resolve({ ok: false }));
7578
+ request.on("error", () => resolve2({ ok: false }));
6295
7579
  });
6296
7580
  }
6297
7581
  async function handleConfigRoute(request, response, url, deps) {
@@ -6361,6 +7645,7 @@ var DEFAULT_BACKLOG_PATH = ".opencode/openteam/backlog.md";
6361
7645
  var DEFAULT_DECISIONS_PATH = ".opencode/openteam/decisions.md";
6362
7646
 
6363
7647
  // src/web/server.ts
7648
+ import { createHash as createHash2 } from "node:crypto";
6364
7649
  import {
6365
7650
  createServer as createHttpServer
6366
7651
  } from "node:http";
@@ -6671,7 +7956,7 @@ function authorized2(request, query, token) {
6671
7956
  return provided !== undefined && safeEqualToken(provided, token);
6672
7957
  }
6673
7958
  async function readJsonBody2(request, limit) {
6674
- return new Promise((resolve) => {
7959
+ return new Promise((resolve2) => {
6675
7960
  let raw = "";
6676
7961
  let aborted = false;
6677
7962
  request.on("data", (chunk) => {
@@ -6681,7 +7966,7 @@ async function readJsonBody2(request, limit) {
6681
7966
  raw += chunk.toString("utf8");
6682
7967
  if (raw.length > limit) {
6683
7968
  aborted = true;
6684
- resolve(undefined);
7969
+ resolve2(undefined);
6685
7970
  }
6686
7971
  });
6687
7972
  request.on("end", () => {
@@ -6689,12 +7974,12 @@ async function readJsonBody2(request, limit) {
6689
7974
  return;
6690
7975
  }
6691
7976
  try {
6692
- resolve(JSON.parse(raw));
7977
+ resolve2(JSON.parse(raw));
6693
7978
  } catch {
6694
- resolve(undefined);
7979
+ resolve2(undefined);
6695
7980
  }
6696
7981
  });
6697
- request.on("error", () => resolve(undefined));
7982
+ request.on("error", () => resolve2(undefined));
6698
7983
  });
6699
7984
  }
6700
7985
  function parseConsolePath(path) {
@@ -6734,8 +8019,12 @@ async function handleMessages(_request, response, sessionID, deps, diagnostic) {
6734
8019
  response.writeHead(404, JSON_HEADERS3).end(JSON.stringify({ error: "no endpoint" }));
6735
8020
  return;
6736
8021
  }
6737
- const frames = await deps.createClient(endpoint).listMessages(sessionID, { diagnostic });
6738
- response.writeHead(200, JSON_HEADERS3).end(JSON.stringify({ frames }));
8022
+ try {
8023
+ const frames = await deps.createClient(endpoint).listMessages(sessionID, { diagnostic });
8024
+ response.writeHead(200, { ...JSON_HEADERS3, "cache-control": "no-store" }).end(JSON.stringify({ frames }));
8025
+ } catch {
8026
+ response.writeHead(503, JSON_HEADERS3).end(JSON.stringify({ error: consoleDetailMessages.readFailed }));
8027
+ }
6739
8028
  }
6740
8029
  async function handleInput(request, response, sessionID, deps) {
6741
8030
  const endpoint = await deps.resolveEndpoint(sessionID);
@@ -6839,6 +8128,201 @@ async function handleConsoleRoute(request, response, url, deps) {
6839
8128
  return true;
6840
8129
  }
6841
8130
 
8131
+ // src/web/conversationRoute.ts
8132
+ async function untilAborted(read, signal) {
8133
+ let cancel = () => {};
8134
+ const aborted = new Promise((_resolve, reject) => {
8135
+ cancel = () => reject(signal.reason);
8136
+ if (signal.aborted)
8137
+ cancel();
8138
+ else
8139
+ signal.addEventListener("abort", cancel, { once: true });
8140
+ });
8141
+ try {
8142
+ return await Promise.race([read, aborted]);
8143
+ } finally {
8144
+ signal.removeEventListener("abort", cancel);
8145
+ }
8146
+ }
8147
+ async function handleConversationRoute(request, response, url, deps) {
8148
+ const labelsOnly = url.pathname === "/api/graph/session-labels";
8149
+ if (url.pathname !== "/api/graph/conversation" && !labelsOnly)
8150
+ return false;
8151
+ const send = (status, kind, message, extra = {}) => {
8152
+ response.writeHead(status, {
8153
+ "content-type": "application/json",
8154
+ "cache-control": "no-store",
8155
+ "referrer-policy": "no-referrer"
8156
+ }).end(JSON.stringify({ version: 1, kind, message, ...extra }));
8157
+ };
8158
+ const authorization = request.headers.authorization;
8159
+ const bearer = authorization?.startsWith("Bearer ") ? authorization.slice(7) : undefined;
8160
+ const token = url.searchParams.get("token") ?? bearer;
8161
+ if (!token || !safeEqualToken(token, deps.token)) {
8162
+ send(401, "unauthorized", consoleDetailMessages.unauthorized);
8163
+ return true;
8164
+ }
8165
+ if (request.method !== "GET") {
8166
+ send(405, "unavailable", consoleDetailMessages.unauthorized);
8167
+ return true;
8168
+ }
8169
+ if (!deps.enabled || !deps.contentEnabled || url.searchParams.get("diagnostic") !== "1") {
8170
+ send(403, "disabled", consoleDetailMessages.disabled);
8171
+ return true;
8172
+ }
8173
+ const params = url.searchParams;
8174
+ const rootTarget = params.get("target") === "root";
8175
+ if ((labelsOnly ? params.has("run") ? ["run"] : [] : rootTarget ? ["run", "operation"] : ["run", "operation", "attempt"]).some((key) => params.getAll(key).length !== 1 || !params.get(key)) || params.has("session") || params.getAll("target").length > 1 || params.has("target") && !rootTarget && params.get("target") !== "attempt" || rootTarget && params.has("attempt") || labelsOnly && (params.has("operation") || params.has("attempt") || params.has("target"))) {
8176
+ send(400, "invalid", consoleDetailMessages.invalid);
8177
+ return true;
8178
+ }
8179
+ if (labelsOnly) {
8180
+ const selected = params.has("run") ? await readLifecycleHistoryQuery(deps.reader, params) : undefined;
8181
+ if (selected && (selected.kind !== "view" || selected.selection.runID !== params.get("run"))) {
8182
+ send(409, "invalid", consoleDetailMessages.invalid);
8183
+ return true;
8184
+ }
8185
+ if (params.has("cursor")) {
8186
+ send(409, "historical", consoleDetailMessages.historical);
8187
+ return true;
8188
+ }
8189
+ const controller2 = new AbortController;
8190
+ const cancel2 = () => controller2.abort();
8191
+ response.on("close", cancel2);
8192
+ request.on("aborted", cancel2);
8193
+ request.socket.on("close", cancel2);
8194
+ if (request.aborted || request.socket.destroyed)
8195
+ cancel2();
8196
+ const deadline = Date.now() + SESSION_HISTORY_LIMITS.timeoutMs;
8197
+ const timeout = setTimeout(cancel2, SESSION_HISTORY_LIMITS.timeoutMs);
8198
+ try {
8199
+ const history2 = selected?.kind === "view" ? selected : undefined;
8200
+ const selectedRoot = history2?.runs.find((run) => run.runID === history2.selection.runID)?.rootSessionID;
8201
+ const eligibleIDs = [
8202
+ ...new Set([
8203
+ ...selectedRoot ? [selectedRoot] : [],
8204
+ ...history2?.projection.operations.flatMap((op) => op.attempts.flatMap((attempt2) => attempt2.sessionID ? [attempt2.sessionID] : [])) ?? [],
8205
+ ...history2?.runs.flatMap((run) => run.rootSessionID ? [run.rootSessionID] : []) ?? [],
8206
+ ...deps.observedSessionIDs ? await untilAborted(deps.observedSessionIDs(), controller2.signal) : []
8207
+ ])
8208
+ ];
8209
+ const ids = eligibleIDs.slice(0, SESSION_HISTORY_LIMITS.labels);
8210
+ const groups = new Map;
8211
+ for (const id of ids) {
8212
+ if (controller2.signal.aborted)
8213
+ break;
8214
+ try {
8215
+ const endpoint = await untilAborted(deps.resolveEndpoint(id), controller2.signal);
8216
+ if (!endpoint)
8217
+ continue;
8218
+ const group = groups.get(endpoint) ?? [];
8219
+ group.push(id);
8220
+ groups.set(endpoint, group);
8221
+ } catch {}
8222
+ }
8223
+ const sessions = [];
8224
+ const budget = { remaining: SESSION_HISTORY_LIMITS.bytes };
8225
+ let groupsLeft = groups.size;
8226
+ for (const [endpoint, group] of groups) {
8227
+ if (controller2.signal.aborted || !deps.readConversation.labels)
8228
+ break;
8229
+ try {
8230
+ sessions.push(...await untilAborted(deps.readConversation.labels(endpoint, group, controller2.signal, {
8231
+ budget,
8232
+ timeoutMs: Math.max(1, Math.floor((deadline - Date.now()) / groupsLeft))
8233
+ }), controller2.signal));
8234
+ } catch {}
8235
+ groupsLeft--;
8236
+ }
8237
+ const found = new Set(sessions.map((session) => session.id));
8238
+ const unavailableSessionIDs = ids.filter((id) => !found.has(id));
8239
+ const truncated = eligibleIDs.length > ids.length;
8240
+ const partial = truncated || unavailableSessionIDs.length > 0;
8241
+ if (response.destroyed || request.socket.destroyed)
8242
+ return true;
8243
+ if (ids.length && !sessions.length) {
8244
+ send(503, "unavailable", consoleDetailMessages.readFailed, {
8245
+ completeness: "partial",
8246
+ unavailableSessionIDs,
8247
+ ...truncated ? { truncated: true } : {}
8248
+ });
8249
+ return true;
8250
+ }
8251
+ send(200, "labels", partial ? `${consoleDetailMessages.currentMetadata}
8252
+ ${consoleDetailMessages.partialMetadata}` : consoleDetailMessages.currentMetadata, {
8253
+ runID: history2?.selection.runID ?? null,
8254
+ sessions,
8255
+ completeness: partial ? "partial" : "complete",
8256
+ unavailableSessionIDs,
8257
+ ...truncated ? { truncated: true } : {}
8258
+ });
8259
+ } catch {
8260
+ if (!response.destroyed && !request.socket.destroyed)
8261
+ send(503, "unavailable", consoleDetailMessages.unavailable);
8262
+ } finally {
8263
+ clearTimeout(timeout);
8264
+ response.off("close", cancel2);
8265
+ request.off("aborted", cancel2);
8266
+ request.socket.off("close", cancel2);
8267
+ }
8268
+ return true;
8269
+ }
8270
+ const history = await readLifecycleHistoryQuery(deps.reader, params);
8271
+ if (history.kind !== "view" || history.selection.runID !== params.get("run")) {
8272
+ send(409, "invalid", consoleDetailMessages.invalid);
8273
+ return true;
8274
+ }
8275
+ const operation = history.projection.operations.find((item) => item.operationID === params.get("operation"));
8276
+ const attempt = operation?.attempts.find((item) => item.attemptID === params.get("attempt"));
8277
+ if (!labelsOnly && (rootTarget ? !operation || operation.operationID !== history.projection.rootOperationID || operation.kind !== "coordinator" : !attempt?.sessionID)) {
8278
+ send(404, "invalid", consoleDetailMessages.invalid);
8279
+ return true;
8280
+ }
8281
+ if (params.has("cursor") || !history.selection.followLive) {
8282
+ send(409, "historical", consoleDetailMessages.historical);
8283
+ return true;
8284
+ }
8285
+ const controller = new AbortController;
8286
+ const cancel = () => controller.abort();
8287
+ response.on("close", cancel);
8288
+ try {
8289
+ const run = history.runs.find((item) => item.runID === history.selection.runID);
8290
+ const recordedRoot = run?.rootSessionID;
8291
+ const sessionID = rootTarget ? recordedRoot : attempt?.sessionID;
8292
+ const endpointID = sessionID ?? history.projection.operations.flatMap((op) => op.attempts).filter((item) => item.sessionID).at(-1)?.sessionID ?? "";
8293
+ const endpoint = await deps.resolveEndpoint(endpointID);
8294
+ if (!endpoint) {
8295
+ send(503, "unavailable", consoleDetailMessages.unavailable);
8296
+ return true;
8297
+ }
8298
+ const recovered = !sessionID && rootTarget && deps.readConversation.root ? await deps.readConversation.root(endpoint, history.projection, controller.signal) : undefined;
8299
+ const resolvedID = sessionID ?? recovered?.session.id;
8300
+ if (!resolvedID)
8301
+ throw new AssociationError("unavailable");
8302
+ const conversation = recovered ?? await deps.readConversation(endpoint, resolvedID, controller.signal);
8303
+ const current = rootTarget ? `${consoleDetailMessages.rootCurrent}
8304
+ ${consoleDetailMessages.current}${recovered ? `
8305
+ ${consoleDetailMessages.recovered}` : ""}` : consoleDetailMessages.current;
8306
+ send(200, conversation.messages.length || conversation.truncated ? "conversation" : "empty", conversation.truncated ? `${current}
8307
+ ${consoleDetailMessages.truncated}` : conversation.messages.length ? current : `${current}
8308
+ ${consoleDetailMessages.empty}`, {
8309
+ scope: "present-day-session",
8310
+ runID: history.selection.runID,
8311
+ operationID: operation?.operationID,
8312
+ target: rootTarget ? "root" : "attempt",
8313
+ ...rootTarget ? {} : { attemptID: attempt?.attemptID },
8314
+ sessionID: resolvedID,
8315
+ ...conversation
8316
+ });
8317
+ } catch (error) {
8318
+ if (!controller.signal.aborted)
8319
+ send(error instanceof ConversationTooLargeError ? 413 : 503, error instanceof ConversationTooLargeError ? "oversized" : "unavailable", error instanceof AssociationError ? error.message : error instanceof ConversationTooLargeError ? consoleDetailMessages.oversized : consoleDetailMessages.unavailable);
8320
+ } finally {
8321
+ response.off("close", cancel);
8322
+ }
8323
+ return true;
8324
+ }
8325
+
6842
8326
  // src/web/storageRoute.ts
6843
8327
  var JSON_HEADERS4 = { "content-type": "application/json" };
6844
8328
  var READ_OPS = new Set(["read", "exists", "list", "isDirectory", "stat"]);
@@ -6868,7 +8352,7 @@ function pathAllowed(path, allowPrefixes) {
6868
8352
  });
6869
8353
  }
6870
8354
  async function readJsonBody3(request, limit) {
6871
- return new Promise((resolve) => {
8355
+ return new Promise((resolve2) => {
6872
8356
  let raw = "";
6873
8357
  let aborted = false;
6874
8358
  request.on("data", (chunk) => {
@@ -6878,19 +8362,19 @@ async function readJsonBody3(request, limit) {
6878
8362
  raw += chunk.toString("utf8");
6879
8363
  if (raw.length > limit) {
6880
8364
  aborted = true;
6881
- resolve(undefined);
8365
+ resolve2(undefined);
6882
8366
  }
6883
8367
  });
6884
8368
  request.on("end", () => {
6885
8369
  if (!aborted) {
6886
8370
  try {
6887
- resolve(JSON.parse(raw));
8371
+ resolve2(JSON.parse(raw));
6888
8372
  } catch {
6889
- resolve(undefined);
8373
+ resolve2(undefined);
6890
8374
  }
6891
8375
  }
6892
8376
  });
6893
- request.on("error", () => resolve(undefined));
8377
+ request.on("error", () => resolve2(undefined));
6894
8378
  });
6895
8379
  }
6896
8380
  function sendJson(response, status, body) {
@@ -7068,18 +8552,18 @@ data: ${json}
7068
8552
  `;
7069
8553
  }
7070
8554
  function tryListen(server, host, port) {
7071
- return new Promise((resolve, reject) => {
8555
+ return new Promise((resolve2, reject) => {
7072
8556
  const onError = (error) => {
7073
8557
  server.removeListener("listening", onListening);
7074
8558
  if (isAddressInUse(error)) {
7075
- resolve(false);
8559
+ resolve2(false);
7076
8560
  } else {
7077
8561
  reject(error);
7078
8562
  }
7079
8563
  };
7080
8564
  const onListening = () => {
7081
8565
  server.removeListener("error", onError);
7082
- resolve(true);
8566
+ resolve2(true);
7083
8567
  };
7084
8568
  server.once("error", onError);
7085
8569
  server.once("listening", onListening);
@@ -7114,6 +8598,20 @@ async function createConsoleServer(deps) {
7114
8598
  };
7115
8599
  const handle = async (request, response) => {
7116
8600
  const url2 = new URL(request.url ?? "/", "http://localhost");
8601
+ if (["/api/graph/conversation", "/api/graph/session-labels"].includes(url2.pathname) && deps.storageApi && !readAuthorized2(request, url2, deps.storageApi.token)) {
8602
+ response.writeHead(401, { ...JSON_HEADERS5, "cache-control": "no-store" }).end(JSON.stringify({ version: 1, kind: "unauthorized" }));
8603
+ return;
8604
+ }
8605
+ if (deps.console?.readConversation && deps.lifecycleHistoryApi && await handleConversationRoute(request, response, url2, {
8606
+ token: deps.console.token,
8607
+ enabled: deps.config.graphView?.enabled === true,
8608
+ contentEnabled: deps.console.conversationContentEnabled === true,
8609
+ reader: deps.lifecycleHistoryApi.reader,
8610
+ resolveEndpoint: async (id) => deps.console?.historyEndpoint ?? await resolveEndpoint(id),
8611
+ observedSessionIDs: async () => buildConsoleState(await deps.readSnapshot()).sessions.map((session) => session.sessionID),
8612
+ readConversation: deps.console.readConversation
8613
+ }))
8614
+ return;
7117
8615
  if (consoleDeps !== undefined && await handleConsoleRoute(request, response, url2, consoleDeps)) {
7118
8616
  return;
7119
8617
  }
@@ -7143,7 +8641,7 @@ async function createConsoleServer(deps) {
7143
8641
  }
7144
8642
  const path = url2.pathname;
7145
8643
  const remoteToken = deps.storageApi?.token;
7146
- if (remoteToken !== undefined && (path === "/" || path === "/index.html" || path === "/api/state" || path === "/events") && !readAuthorized2(request, url2, remoteToken)) {
8644
+ if (remoteToken !== undefined && (path === "/" || path === "/index.html" || path === "/api/state" || path === "/api/view" || path === "/events") && !readAuthorized2(request, url2, remoteToken)) {
7147
8645
  response.writeHead(401, JSON_HEADERS5).end(JSON.stringify({ error: "unauthorized" }));
7148
8646
  return;
7149
8647
  }
@@ -7155,6 +8653,34 @@ async function createConsoleServer(deps) {
7155
8653
  response.writeHead(200, JSON_HEADERS5).end(await stateJson(deps));
7156
8654
  return;
7157
8655
  }
8656
+ if (path === "/api/view") {
8657
+ const state = buildConsoleState(await deps.readSnapshot());
8658
+ const view = {
8659
+ ...renderConsoleUpdate(state, {
8660
+ ...deps.console,
8661
+ ...deps.graphApi && !deps.lifecycleHistoryApi ? {
8662
+ graphView: {
8663
+ projection: await deps.graphApi.readView(),
8664
+ mode: deps.graphMode ?? "active"
8665
+ }
8666
+ } : {}
8667
+ }),
8668
+ refreshMs: (deps.getConsoleConfig?.() ?? deps.config).refreshMs
8669
+ };
8670
+ const json = JSON.stringify(view);
8671
+ const revision = `"${createHash2("sha256").update(json).digest("hex")}"`;
8672
+ const headers = {
8673
+ ...JSON_HEADERS5,
8674
+ etag: revision,
8675
+ "cache-control": "no-store"
8676
+ };
8677
+ if (request.headers["if-none-match"] === revision) {
8678
+ response.writeHead(304, headers).end();
8679
+ } else {
8680
+ response.writeHead(200, headers).end(JSON.stringify({ ...view, updatedAt: state.generatedAt }));
8681
+ }
8682
+ return;
8683
+ }
7158
8684
  if (path === "/healthz") {
7159
8685
  response.writeHead(200, JSON_HEADERS5).end(JSON.stringify({ ok: true }));
7160
8686
  return;
@@ -7719,19 +9245,19 @@ import { readdirSync, readFileSync } from "node:fs";
7719
9245
  import { join as join2 } from "node:path";
7720
9246
 
7721
9247
  // src/storage/lifecycle/codec.ts
7722
- import { z as z11 } from "zod";
9248
+ import { z as z13 } from "zod";
7723
9249
 
7724
9250
  // src/lifecycle/schema.ts
7725
- import { z as z10 } from "zod";
7726
- var nonEmptyString = z10.string().min(1);
7727
- var nonNegativeInteger = z10.number().int().nonnegative();
7728
- var positiveInteger = z10.number().int().positive();
7729
- var modelSelectionSchema2 = z10.object({
9251
+ import { z as z12 } from "zod";
9252
+ var nonEmptyString = z12.string().min(1);
9253
+ var nonNegativeInteger = z12.number().int().nonnegative();
9254
+ var positiveInteger = z12.number().int().positive();
9255
+ var modelSelectionSchema2 = z12.object({
7730
9256
  providerID: nonEmptyString,
7731
9257
  modelID: nonEmptyString
7732
9258
  }).strict();
7733
- var lifecycleFailureSchema = z10.object({
7734
- class: z10.enum([
9259
+ var lifecycleFailureSchema = z12.object({
9260
+ class: z12.enum([
7735
9261
  "routing-blocked",
7736
9262
  "create-rejected",
7737
9263
  "create-no-id",
@@ -7753,25 +9279,25 @@ var lifecycleFailureSchema = z10.object({
7753
9279
  "interrupted",
7754
9280
  "unknown"
7755
9281
  ]),
7756
- statusCode: z10.number().int().min(100).max(599).optional(),
7757
- retryable: z10.boolean().optional()
9282
+ statusCode: z12.number().int().min(100).max(599).optional(),
9283
+ retryable: z12.boolean().optional()
7758
9284
  }).strict();
7759
- var lifecycleRootOperationSchema = z10.object({
9285
+ var lifecycleRootOperationSchema = z12.object({
7760
9286
  operationID: nonEmptyString,
7761
9287
  taskID: nonEmptyString,
7762
- kind: z10.enum(["coordinator", "graph-node"]),
9288
+ kind: z12.enum(["coordinator", "graph-node"]),
7763
9289
  roleID: nonEmptyString,
7764
9290
  agentID: nonEmptyString.optional(),
7765
9291
  sessionID: nonEmptyString.optional()
7766
9292
  }).strict();
7767
- var lifecycleRunStartInputSchema = z10.object({
9293
+ var lifecycleRunStartInputSchema = z12.object({
7768
9294
  runID: nonEmptyString,
7769
- source: z10.enum(["plugin", "cli"]),
7770
- executionAuthority: z10.enum(["coordinator", "graph"]),
9295
+ source: z12.enum(["plugin", "cli"]),
9296
+ executionAuthority: z12.enum(["coordinator", "graph"]),
7771
9297
  root: lifecycleRootOperationSchema
7772
9298
  }).strict();
7773
9299
  var LifecycleRunMetadataSchema = lifecycleRunStartInputSchema.extend({
7774
- version: z10.literal(1),
9300
+ version: z12.literal(1),
7775
9301
  createdAt: nonNegativeInteger
7776
9302
  }).strict();
7777
9303
  var attemptRefShape = {
@@ -7783,34 +9309,34 @@ var attemptRefShape = {
7783
9309
  retryIndex: nonNegativeInteger
7784
9310
  };
7785
9311
  var eventEnvelopeShape = {
7786
- v: z10.literal(1),
9312
+ v: z12.literal(1),
7787
9313
  seq: nonNegativeInteger,
7788
9314
  runID: nonEmptyString,
7789
9315
  at: nonNegativeInteger
7790
9316
  };
7791
9317
  var runStartedBodyShape = {
7792
- type: z10.literal("run.started"),
7793
- source: z10.enum(["plugin", "cli"]),
7794
- executionAuthority: z10.enum(["coordinator", "graph"]),
9318
+ type: z12.literal("run.started"),
9319
+ source: z12.enum(["plugin", "cli"]),
9320
+ executionAuthority: z12.enum(["coordinator", "graph"]),
7795
9321
  root: lifecycleRootOperationSchema
7796
9322
  };
7797
9323
  var operationQueuedBodyShape = {
7798
- type: z10.literal("operation.queued"),
9324
+ type: z12.literal("operation.queued"),
7799
9325
  operationID: nonEmptyString,
7800
9326
  taskID: nonEmptyString,
7801
- kind: z10.enum(["role", "graph-node"]),
9327
+ kind: z12.enum(["role", "graph-node"]),
7802
9328
  roleID: nonEmptyString,
7803
9329
  agentID: nonEmptyString.optional(),
7804
9330
  parentOperationID: nonEmptyString,
7805
- dependsOnOperationIDs: z10.array(nonEmptyString).readonly()
9331
+ dependsOnOperationIDs: z12.array(nonEmptyString).readonly()
7806
9332
  };
7807
9333
  var modelSelectedBodyShape = {
7808
- type: z10.literal("attempt.model-selected"),
9334
+ type: z12.literal("attempt.model-selected"),
7809
9335
  ...attemptRefShape,
7810
9336
  decisionID: nonEmptyString,
7811
9337
  model: modelSelectionSchema2,
7812
- routeKind: z10.enum(["local", "frontier"]),
7813
- selectionCause: z10.enum([
9338
+ routeKind: z12.enum(["local", "frontier"]),
9339
+ selectionCause: z12.enum([
7814
9340
  "initial",
7815
9341
  "retry-incomplete",
7816
9342
  "retry-transport",
@@ -7820,31 +9346,31 @@ var modelSelectedBodyShape = {
7820
9346
  runtimeID: nonEmptyString.optional()
7821
9347
  };
7822
9348
  var attemptQueuedBodyShape = {
7823
- type: z10.literal("attempt.queued"),
9349
+ type: z12.literal("attempt.queued"),
7824
9350
  ...attemptRefShape,
7825
9351
  runtimeID: nonEmptyString.optional()
7826
9352
  };
7827
9353
  var attemptStartedBodyShape = {
7828
- type: z10.literal("attempt.started"),
9354
+ type: z12.literal("attempt.started"),
7829
9355
  ...attemptRefShape
7830
9356
  };
7831
9357
  var sessionCreatedBodyShape = {
7832
- type: z10.literal("session.created"),
9358
+ type: z12.literal("session.created"),
7833
9359
  ...attemptRefShape,
7834
9360
  sessionID: nonEmptyString,
7835
9361
  parentSessionID: nonEmptyString.optional()
7836
9362
  };
7837
9363
  var attemptTerminalBodyShape = {
7838
- type: z10.literal("attempt.terminal"),
9364
+ type: z12.literal("attempt.terminal"),
7839
9365
  ...attemptRefShape,
7840
- outcome: z10.enum([
9366
+ outcome: z12.enum([
7841
9367
  "succeeded",
7842
9368
  "failed",
7843
9369
  "cancelled",
7844
9370
  "interrupted",
7845
9371
  "unknown"
7846
9372
  ]),
7847
- continuation: z10.enum([
9373
+ continuation: z12.enum([
7848
9374
  "none",
7849
9375
  "retry-same-model",
7850
9376
  "fallback-next-model",
@@ -7854,10 +9380,10 @@ var attemptTerminalBodyShape = {
7854
9380
  failure: lifecycleFailureSchema.optional()
7855
9381
  };
7856
9382
  var operationTerminalBodyShape = {
7857
- type: z10.literal("operation.terminal"),
9383
+ type: z12.literal("operation.terminal"),
7858
9384
  operationID: nonEmptyString,
7859
9385
  taskID: nonEmptyString,
7860
- outcome: z10.enum([
9386
+ outcome: z12.enum([
7861
9387
  "succeeded",
7862
9388
  "failed",
7863
9389
  "cancelled",
@@ -7870,8 +9396,8 @@ var operationTerminalBodyShape = {
7870
9396
  failure: lifecycleFailureSchema.optional()
7871
9397
  };
7872
9398
  var runTerminalBodyShape = {
7873
- type: z10.literal("run.terminal"),
7874
- outcome: z10.enum([
9399
+ type: z12.literal("run.terminal"),
9400
+ outcome: z12.enum([
7875
9401
  "succeeded",
7876
9402
  "failed",
7877
9403
  "cancelled",
@@ -7882,39 +9408,39 @@ var runTerminalBodyShape = {
7882
9408
  failure: lifecycleFailureSchema.optional()
7883
9409
  };
7884
9410
  var bodySchemas = [
7885
- z10.object(runStartedBodyShape).strict(),
7886
- z10.object(operationQueuedBodyShape).strict(),
7887
- z10.object(modelSelectedBodyShape).strict(),
7888
- z10.object(attemptQueuedBodyShape).strict(),
7889
- z10.object(attemptStartedBodyShape).strict(),
7890
- z10.object(sessionCreatedBodyShape).strict(),
7891
- z10.object(attemptTerminalBodyShape).strict(),
7892
- z10.object(operationTerminalBodyShape).strict(),
7893
- z10.object(runTerminalBodyShape).strict()
9411
+ z12.object(runStartedBodyShape).strict(),
9412
+ z12.object(operationQueuedBodyShape).strict(),
9413
+ z12.object(modelSelectedBodyShape).strict(),
9414
+ z12.object(attemptQueuedBodyShape).strict(),
9415
+ z12.object(attemptStartedBodyShape).strict(),
9416
+ z12.object(sessionCreatedBodyShape).strict(),
9417
+ z12.object(attemptTerminalBodyShape).strict(),
9418
+ z12.object(operationTerminalBodyShape).strict(),
9419
+ z12.object(runTerminalBodyShape).strict()
7894
9420
  ];
7895
9421
  var appendBodySchemas = bodySchemas.slice(1);
7896
- var LifecycleAppendEventSchema = z10.discriminatedUnion("type", appendBodySchemas);
7897
- var LifecycleEventSchema = z10.discriminatedUnion("type", [
7898
- z10.object({ ...eventEnvelopeShape, ...runStartedBodyShape }).strict(),
7899
- z10.object({ ...eventEnvelopeShape, ...operationQueuedBodyShape }).strict(),
7900
- z10.object({ ...eventEnvelopeShape, ...modelSelectedBodyShape }).strict(),
7901
- z10.object({ ...eventEnvelopeShape, ...attemptQueuedBodyShape }).strict(),
7902
- z10.object({ ...eventEnvelopeShape, ...attemptStartedBodyShape }).strict(),
7903
- z10.object({ ...eventEnvelopeShape, ...sessionCreatedBodyShape }).strict(),
7904
- z10.object({ ...eventEnvelopeShape, ...attemptTerminalBodyShape }).strict(),
7905
- z10.object({ ...eventEnvelopeShape, ...operationTerminalBodyShape }).strict(),
7906
- z10.object({ ...eventEnvelopeShape, ...runTerminalBodyShape }).strict()
9422
+ var LifecycleAppendEventSchema = z12.discriminatedUnion("type", appendBodySchemas);
9423
+ var LifecycleEventSchema = z12.discriminatedUnion("type", [
9424
+ z12.object({ ...eventEnvelopeShape, ...runStartedBodyShape }).strict(),
9425
+ z12.object({ ...eventEnvelopeShape, ...operationQueuedBodyShape }).strict(),
9426
+ z12.object({ ...eventEnvelopeShape, ...modelSelectedBodyShape }).strict(),
9427
+ z12.object({ ...eventEnvelopeShape, ...attemptQueuedBodyShape }).strict(),
9428
+ z12.object({ ...eventEnvelopeShape, ...attemptStartedBodyShape }).strict(),
9429
+ z12.object({ ...eventEnvelopeShape, ...sessionCreatedBodyShape }).strict(),
9430
+ z12.object({ ...eventEnvelopeShape, ...attemptTerminalBodyShape }).strict(),
9431
+ z12.object({ ...eventEnvelopeShape, ...operationTerminalBodyShape }).strict(),
9432
+ z12.object({ ...eventEnvelopeShape, ...runTerminalBodyShape }).strict()
7907
9433
  ]);
7908
- var LifecycleWriterLeaseInputSchema = z10.object({
7909
- writer: z10.object({
9434
+ var LifecycleWriterLeaseInputSchema = z12.object({
9435
+ writer: z12.object({
7910
9436
  processID: positiveInteger,
7911
9437
  processInstanceID: nonEmptyString
7912
9438
  }).strict(),
7913
9439
  now: nonNegativeInteger,
7914
9440
  leaseDurationMs: positiveInteger
7915
9441
  }).strict();
7916
- var LifecycleWriterLeaseSchema = z10.object({
7917
- version: z10.literal(1),
9442
+ var LifecycleWriterLeaseSchema = z12.object({
9443
+ version: z12.literal(1),
7918
9444
  runID: nonEmptyString,
7919
9445
  writerToken: nonEmptyString,
7920
9446
  processID: positiveInteger,
@@ -7990,12 +9516,12 @@ var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1"
7990
9516
  var NUL2 = "\x00";
7991
9517
  var NEWLINE = `
7992
9518
  `;
7993
- var frameSchema = z11.object({
7994
- v: z11.literal(LIFECYCLE_CODEC_VERSION),
7995
- seq: z11.number().int().nonnegative(),
7996
- prev: z11.string().min(1),
7997
- sum: z11.string().min(1),
7998
- event: z11.unknown()
9519
+ var frameSchema = z13.object({
9520
+ v: z13.literal(LIFECYCLE_CODEC_VERSION),
9521
+ seq: z13.number().int().nonnegative(),
9522
+ prev: z13.string().min(1),
9523
+ sum: z13.string().min(1),
9524
+ event: z13.unknown()
7999
9525
  }).strict();
8000
9526
  function canonical(value) {
8001
9527
  if (Array.isArray(value)) {
@@ -8513,94 +10039,94 @@ function replay(spec, events) {
8513
10039
  }
8514
10040
 
8515
10041
  // src/graph/schema.ts
8516
- import { z as z13 } from "zod";
10042
+ import { z as z15 } from "zod";
8517
10043
 
8518
10044
  // src/context/schema.ts
8519
- import { z as z12 } from "zod";
8520
- var PrivacyClassSchema = z12.enum(["public", "internal", "sensitive"]);
8521
- var Sha256Schema = z12.string().regex(/^[0-9a-f]{64}$/, "expected lowercase hex sha-256");
8522
- var IdentifierSchema = z12.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/, "invalid identifier");
8523
- var TaskAnchorSchema = z12.object({
10045
+ import { z as z14 } from "zod";
10046
+ var PrivacyClassSchema = z14.enum(["public", "internal", "sensitive"]);
10047
+ var Sha256Schema = z14.string().regex(/^[0-9a-f]{64}$/, "expected lowercase hex sha-256");
10048
+ var IdentifierSchema = z14.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/, "invalid identifier");
10049
+ var TaskAnchorSchema = z14.object({
8524
10050
  taskID: IdentifierSchema,
8525
10051
  specDigest: Sha256Schema
8526
10052
  }).strict();
8527
- var ContextRefSchema = z12.object({
8528
- uri: z12.string().min(1).max(1024),
10053
+ var ContextRefSchema = z14.object({
10054
+ uri: z14.string().min(1).max(1024),
8529
10055
  sha256: Sha256Schema,
8530
- bytes: z12.number().int().nonnegative(),
8531
- mediaType: z12.string().min(1).max(128).optional()
10056
+ bytes: z14.number().int().nonnegative(),
10057
+ mediaType: z14.string().min(1).max(128).optional()
8532
10058
  }).strict();
8533
- var ManifestEntrySchema = z12.object({
10059
+ var ManifestEntrySchema = z14.object({
8534
10060
  label: IdentifierSchema,
8535
10061
  sha256: Sha256Schema,
8536
- bytes: z12.number().int().nonnegative(),
10062
+ bytes: z14.number().int().nonnegative(),
8537
10063
  ref: ContextRefSchema.optional()
8538
10064
  }).strict();
8539
- var ArtifactManifestSchema = z12.object({
8540
- version: z12.literal(1),
10065
+ var ArtifactManifestSchema = z14.object({
10066
+ version: z14.literal(1),
8541
10067
  taskID: IdentifierSchema,
8542
10068
  privacyClass: PrivacyClassSchema,
8543
- entries: z12.array(ManifestEntrySchema)
10069
+ entries: z14.array(ManifestEntrySchema)
8544
10070
  }).strict();
8545
- var NodeContextContractSchema = z12.object({
8546
- version: z12.literal(1),
8547
- refs: z12.array(ContextRefSchema),
10071
+ var NodeContextContractSchema = z14.object({
10072
+ version: z14.literal(1),
10073
+ refs: z14.array(ContextRefSchema),
8548
10074
  privacyClass: PrivacyClassSchema,
8549
- maxInputTokens: z12.number().int().positive().optional()
10075
+ maxInputTokens: z14.number().int().positive().optional()
8550
10076
  }).strict();
8551
10077
 
8552
10078
  // src/graph/schema.ts
8553
10079
  var GRAPH_SPEC_VERSION = 1;
8554
10080
  var GRAPH_EVENT_VERSION = 1;
8555
- var NodeIDSchema = z13.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "invalid node id");
8556
- var NodeRoleSchema = z13.enum(["implementer", "reviewer"]);
8557
- var OperationIDSchema = z13.string().regex(/^[0-9a-f]{8,64}$/, "invalid operation id");
8558
- var AttemptIDSchema = z13.string().regex(/^[0-9a-f]{8,64}$/, "invalid attempt id");
8559
- var ErrorClassSchema = z13.enum([
10081
+ var NodeIDSchema = z15.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "invalid node id");
10082
+ var NodeRoleSchema = z15.enum(["implementer", "reviewer"]);
10083
+ var OperationIDSchema = z15.string().regex(/^[0-9a-f]{8,64}$/, "invalid operation id");
10084
+ var AttemptIDSchema = z15.string().regex(/^[0-9a-f]{8,64}$/, "invalid attempt id");
10085
+ var ErrorClassSchema = z15.enum([
8560
10086
  "transient",
8561
10087
  "permanent",
8562
10088
  "timeout",
8563
10089
  "cancelled",
8564
10090
  "unknown"
8565
10091
  ]);
8566
- var GraphNodeSchema = z13.object({
10092
+ var GraphNodeSchema = z15.object({
8567
10093
  id: NodeIDSchema,
8568
10094
  role: NodeRoleSchema,
8569
- dependsOn: z13.array(NodeIDSchema).default([]),
10095
+ dependsOn: z15.array(NodeIDSchema).default([]),
8570
10096
  anchor: TaskAnchorSchema,
8571
10097
  reviews: NodeIDSchema.optional()
8572
10098
  }).strict();
8573
- var GraphSpecV1Schema = z13.object({
8574
- version: z13.literal(GRAPH_SPEC_VERSION),
10099
+ var GraphSpecV1Schema = z15.object({
10100
+ version: z15.literal(GRAPH_SPEC_VERSION),
8575
10101
  runID: NodeIDSchema,
8576
- nodes: z13.array(GraphNodeSchema).min(1)
10102
+ nodes: z15.array(GraphNodeSchema).min(1)
8577
10103
  }).strict();
8578
10104
  var eventEnvelope = {
8579
- v: z13.literal(GRAPH_EVENT_VERSION),
8580
- seq: z13.number().int().nonnegative(),
10105
+ v: z15.literal(GRAPH_EVENT_VERSION),
10106
+ seq: z15.number().int().nonnegative(),
8581
10107
  runID: NodeIDSchema
8582
10108
  };
8583
- var RunStartedEventSchema = z13.object({
10109
+ var RunStartedEventSchema = z15.object({
8584
10110
  ...eventEnvelope,
8585
- type: z13.literal("run.started"),
10111
+ type: z15.literal("run.started"),
8586
10112
  specDigest: Sha256Schema
8587
10113
  }).strict();
8588
- var NodeDispatchedEventSchema = z13.object({
10114
+ var NodeDispatchedEventSchema = z15.object({
8589
10115
  ...eventEnvelope,
8590
- type: z13.literal("node.dispatched"),
10116
+ type: z15.literal("node.dispatched"),
8591
10117
  nodeID: NodeIDSchema,
8592
10118
  operationID: OperationIDSchema,
8593
10119
  attemptID: AttemptIDSchema
8594
10120
  }).strict();
8595
- var NodeSucceededEventSchema = z13.object({
10121
+ var NodeSucceededEventSchema = z15.object({
8596
10122
  ...eventEnvelope,
8597
- type: z13.literal("node.succeeded"),
10123
+ type: z15.literal("node.succeeded"),
8598
10124
  nodeID: NodeIDSchema,
8599
10125
  operationID: OperationIDSchema,
8600
10126
  attemptID: AttemptIDSchema,
8601
10127
  artifact: ContextRefSchema
8602
10128
  }).strict();
8603
- var NodeFailureClassSchema = z13.enum([
10129
+ var NodeFailureClassSchema = z15.enum([
8604
10130
  "create-rejected",
8605
10131
  "create-no-id",
8606
10132
  "prompt-rejected",
@@ -8614,24 +10140,24 @@ var NodeFailureClassSchema = z13.enum([
8614
10140
  "prompt-server",
8615
10141
  "unknown"
8616
10142
  ]);
8617
- var NodeFailedEventSchema = z13.object({
10143
+ var NodeFailedEventSchema = z15.object({
8618
10144
  ...eventEnvelope,
8619
- type: z13.literal("node.failed"),
10145
+ type: z15.literal("node.failed"),
8620
10146
  nodeID: NodeIDSchema,
8621
10147
  operationID: OperationIDSchema,
8622
10148
  attemptID: AttemptIDSchema,
8623
10149
  errorClass: ErrorClassSchema,
8624
10150
  failureClass: NodeFailureClassSchema.optional()
8625
10151
  }).strict();
8626
- var NodeCancelledEventSchema = z13.object({
10152
+ var NodeCancelledEventSchema = z15.object({
8627
10153
  ...eventEnvelope,
8628
- type: z13.literal("node.cancelled"),
10154
+ type: z15.literal("node.cancelled"),
8629
10155
  nodeID: NodeIDSchema
8630
10156
  }).strict();
8631
- var RunCompletedEventSchema = z13.object({ ...eventEnvelope, type: z13.literal("run.completed") }).strict();
8632
- var RunFailedEventSchema = z13.object({ ...eventEnvelope, type: z13.literal("run.failed") }).strict();
8633
- var RunCancelledEventSchema = z13.object({ ...eventEnvelope, type: z13.literal("run.cancelled") }).strict();
8634
- var GraphEventV1Schema = z13.discriminatedUnion("type", [
10157
+ var RunCompletedEventSchema = z15.object({ ...eventEnvelope, type: z15.literal("run.completed") }).strict();
10158
+ var RunFailedEventSchema = z15.object({ ...eventEnvelope, type: z15.literal("run.failed") }).strict();
10159
+ var RunCancelledEventSchema = z15.object({ ...eventEnvelope, type: z15.literal("run.cancelled") }).strict();
10160
+ var GraphEventV1Schema = z15.discriminatedUnion("type", [
8635
10161
  RunStartedEventSchema,
8636
10162
  NodeDispatchedEventSchema,
8637
10163
  NodeSucceededEventSchema,
@@ -8781,7 +10307,7 @@ import {
8781
10307
  realpathSync,
8782
10308
  writeSync
8783
10309
  } from "node:fs";
8784
- import { basename, dirname as dirname2, join as join3, parse, resolve } from "node:path";
10310
+ import { basename, dirname as dirname2, join as join3, parse as parse2, resolve as resolve2 } from "node:path";
8785
10311
  function ensureDir(dir) {
8786
10312
  mkdirSync(dir, { recursive: true });
8787
10313
  }
@@ -8820,8 +10346,8 @@ function tryRealPath(path) {
8820
10346
  }
8821
10347
  }
8822
10348
  function realPathDeep(target) {
8823
- const absolute = resolve(target);
8824
- const root = parse(absolute).root;
10349
+ const absolute = resolve2(target);
10350
+ const root = parse2(absolute).root;
8825
10351
  let current = absolute;
8826
10352
  let suffix = "";
8827
10353
  while (current !== root) {
@@ -9279,6 +10805,13 @@ async function runConsoleServe(deps, options) {
9279
10805
  terminalEnabled,
9280
10806
  ptyEnabled,
9281
10807
  createClient: makeClient,
10808
+ drilldownEnabled: graphViewEnabled,
10809
+ conversationContentEnabled: config.console.sessionHistory?.contentEnabled === true,
10810
+ ...config.console.sessionHistory?.endpoint !== undefined ? { historyEndpoint: config.console.sessionHistory.endpoint } : {},
10811
+ readConversation: createConversationReader({
10812
+ directory: deps.directory ?? process.cwd(),
10813
+ ...deps.serverPassword !== undefined ? { password: deps.serverPassword } : {}
10814
+ }),
9282
10815
  createPtyClient: makePtyClient
9283
10816
  },
9284
10817
  ...graphViewProvider !== undefined ? { graphView: graphViewProvider } : {},
@@ -9407,13 +10940,13 @@ async function invokeStateGraph(definition, input, deps) {
9407
10940
  }
9408
10941
 
9409
10942
  // src/graph/langgraph/checkpointer.ts
9410
- import { z as z14 } from "zod";
10943
+ import { z as z16 } from "zod";
9411
10944
  var EPHEMERAL_CHECKPOINT_DIR = ".opencode/openteam-local/langgraph-checkpoints";
9412
10945
  var COMMITTED_CHECKPOINT_DIR = ".opencode/openteam/graph/checkpoints";
9413
- var PersistedCheckpointSchema = z14.object({
9414
- runID: z14.string().min(1),
9415
- nodeID: z14.string().min(1),
9416
- route: z14.enum(["local", "frontier"]),
10946
+ var PersistedCheckpointSchema = z16.object({
10947
+ runID: z16.string().min(1),
10948
+ nodeID: z16.string().min(1),
10949
+ route: z16.enum(["local", "frontier"]),
9417
10950
  stateHash: Sha256Schema
9418
10951
  }).strict();
9419
10952
  function createReferenceOnlySaver(location = COMMITTED_CHECKPOINT_DIR) {
@@ -9544,13 +11077,13 @@ function runCancelled(runID, seq) {
9544
11077
 
9545
11078
  // src/storage/graph/workspaceLease.ts
9546
11079
  import { join as join7 } from "node:path";
9547
- import { z as z16 } from "zod";
11080
+ import { z as z18 } from "zod";
9548
11081
 
9549
11082
  // src/storage/graph/runRegistry.ts
9550
11083
  import { join as join6 } from "node:path";
9551
- import { z as z15 } from "zod";
11084
+ import { z as z17 } from "zod";
9552
11085
  var REGISTRY_FILE = "active-runs.json";
9553
- var registrySchema = z15.object({ runs: z15.array(z15.string().min(1)) }).strict();
11086
+ var registrySchema = z17.object({ runs: z17.array(z17.string().min(1)) }).strict();
9554
11087
 
9555
11088
  class RunRegistryError extends Error {
9556
11089
  code = "corrupt";
@@ -9606,11 +11139,11 @@ function createRunRegistry(root) {
9606
11139
 
9607
11140
  // src/storage/graph/workspaceLease.ts
9608
11141
  var NUL5 = "\x00";
9609
- var leaseRecordSchema = z16.object({
9610
- runID: z16.string().min(1),
9611
- holder: z16.string().min(1),
9612
- token: z16.string().length(32),
9613
- released: z16.boolean()
11142
+ var leaseRecordSchema = z18.object({
11143
+ runID: z18.string().min(1),
11144
+ holder: z18.string().min(1),
11145
+ token: z18.string().length(32),
11146
+ released: z18.boolean()
9614
11147
  }).strict();
9615
11148
 
9616
11149
  class LeaseError extends Error {
@@ -9626,7 +11159,7 @@ class LeaseError extends Error {
9626
11159
  function createWorkspaceLease(root, registry = createRunRegistry(root)) {
9627
11160
  const leasePath = (runID) => join7(root, `lease-${runID}.json`);
9628
11161
  const deriveToken = (runID, holder) => sha256Hex(`lease${NUL5}${runID}${NUL5}${holder}`).slice(0, 32);
9629
- const parse2 = (text) => {
11162
+ const parse3 = (text) => {
9630
11163
  let raw;
9631
11164
  try {
9632
11165
  raw = JSON.parse(text);
@@ -9641,7 +11174,7 @@ function createWorkspaceLease(root, registry = createRunRegistry(root)) {
9641
11174
  };
9642
11175
  const readRecord = (runID) => {
9643
11176
  const text = readText(leasePath(runID));
9644
- return text === undefined ? undefined : parse2(text);
11177
+ return text === undefined ? undefined : parse3(text);
9645
11178
  };
9646
11179
  const grant = async (runID, holder, token) => {
9647
11180
  const record2 = { runID, holder, token, released: false };
@@ -9704,7 +11237,7 @@ function planCancellation(state) {
9704
11237
  }
9705
11238
 
9706
11239
  // src/orchestrator/graphReview.ts
9707
- import { z as z17 } from "zod";
11240
+ import { z as z19 } from "zod";
9708
11241
 
9709
11242
  // src/graph/policies.ts
9710
11243
  var DEFAULT_RETRY_LIMIT = 3;
@@ -9727,11 +11260,11 @@ function retryAllowed(errorClass, attempts, limit = DEFAULT_RETRY_LIMIT) {
9727
11260
  }
9728
11261
 
9729
11262
  // src/orchestrator/graphReview.ts
9730
- var ReviewInputSchema = z17.object({
9731
- decision: z17.enum(["approve", "reject"]),
11263
+ var ReviewInputSchema = z19.object({
11264
+ decision: z19.enum(["approve", "reject"]),
9732
11265
  anchor: TaskAnchorSchema.optional(),
9733
11266
  artifactSha256: Sha256Schema.optional(),
9734
- reason: z17.string().min(1).max(500).optional()
11267
+ reason: z19.string().min(1).max(500).optional()
9735
11268
  }).strict();
9736
11269
  function planRevision(input) {
9737
11270
  const limit = input.limit ?? DEFAULT_REVISION_LIMIT;
@@ -11079,15 +12612,15 @@ function createGraphOperator(options) {
11079
12612
  }
11080
12613
 
11081
12614
  // src/cli/graphStatusSnapshot.ts
11082
- import { z as z18 } from "zod";
11083
- var activeRunRegistrySchema = z18.object({
11084
- runs: z18.array(z18.string().min(1))
12615
+ import { z as z20 } from "zod";
12616
+ var activeRunRegistrySchema = z20.object({
12617
+ runs: z20.array(z20.string().min(1))
11085
12618
  }).strict();
11086
- var leaseRecordSchema2 = z18.object({
11087
- runID: z18.string().min(1),
11088
- holder: z18.string().min(1),
11089
- token: z18.string().length(32),
11090
- released: z18.boolean()
12619
+ var leaseRecordSchema2 = z20.object({
12620
+ runID: z20.string().min(1),
12621
+ holder: z20.string().min(1),
12622
+ token: z20.string().length(32),
12623
+ released: z20.boolean()
11091
12624
  }).strict();
11092
12625
 
11093
12626
  class BoundaryJsonError extends Error {
@@ -11768,7 +13301,7 @@ import {
11768
13301
  statSync as statSync2,
11769
13302
  unlinkSync as unlinkSync2
11770
13303
  } from "node:fs";
11771
- import { join as join11, resolve as resolve3 } from "node:path";
13304
+ import { join as join11, resolve as resolve4 } from "node:path";
11772
13305
  import { ZodError } from "zod";
11773
13306
 
11774
13307
  // src/storage/lifecycle/fsLifecycleSupport.ts
@@ -11789,7 +13322,7 @@ import {
11789
13322
  unlinkSync,
11790
13323
  writeSync as writeSync2
11791
13324
  } from "node:fs";
11792
- import { basename as basename2, dirname as dirname3, join as join10, relative, resolve as resolve2 } from "node:path";
13325
+ import { basename as basename2, dirname as dirname3, join as join10, relative, resolve as resolve3 } from "node:path";
11793
13326
  var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
11794
13327
 
11795
13328
  class LifecycleFsError extends Error {
@@ -11813,7 +13346,7 @@ function validateRunID(runID) {
11813
13346
  }
11814
13347
  function resolvedLifecycleRoot(root) {
11815
13348
  try {
11816
- const absolute = resolve2(root);
13349
+ const absolute = resolve3(root);
11817
13350
  mkdirSync2(absolute, { recursive: true });
11818
13351
  const rootStat = lstatSync(absolute);
11819
13352
  if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
@@ -11856,7 +13389,7 @@ function assertExistingSafeRun(root, runID) {
11856
13389
  throw new LifecycleFsError("unavailable");
11857
13390
  }
11858
13391
  const child = relative(root, real);
11859
- if (child === "" || child.startsWith("..") || resolve2(root, child) !== real || dirname3(real) !== root) {
13392
+ if (child === "" || child.startsWith("..") || resolve3(root, child) !== real || dirname3(real) !== root) {
11860
13393
  throw new LifecycleFsError("corrupt");
11861
13394
  }
11862
13395
  return real;
@@ -11989,9 +13522,9 @@ function mapFsFailure(error, runID) {
11989
13522
  }
11990
13523
  return failure("unavailable", { recoverable: true, ...context });
11991
13524
  }
11992
- function parseJson(text, parse2) {
13525
+ function parseJson(text, parse3) {
11993
13526
  try {
11994
- return parse2(JSON.parse(text));
13527
+ return parse3(JSON.parse(text));
11995
13528
  } catch {
11996
13529
  throw new LifecycleFsError("corrupt");
11997
13530
  }
@@ -12096,7 +13629,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
12096
13629
  return now >= lease.expiresAt;
12097
13630
  }
12098
13631
  var createFsLifecycleJournal = (options) => {
12099
- const configuredRoot = resolve3(options.root);
13632
+ const configuredRoot = resolve4(options.root);
12100
13633
  const now = options.now ?? Date.now;
12101
13634
  const mutateRun = options.withMutationLock ?? withRunMutationLock;
12102
13635
  return {
@@ -12619,9 +14152,9 @@ var createLifecycleHistoryProvider = (options, legacyFs = legacyReadFs) => {
12619
14152
 
12620
14153
  // src/cli/migrateAdapter.ts
12621
14154
  import * as fs from "node:fs";
12622
- import { dirname as dirname4, join as join14, resolve as resolve4 } from "node:path";
14155
+ import { dirname as dirname4, join as join14, resolve as resolve5 } from "node:path";
12623
14156
  function createMigrateAdapter(root) {
12624
- const rootAbs = resolve4(root);
14157
+ const rootAbs = resolve5(root);
12625
14158
  const toDisk = (relPath) => join14(rootAbs, ...splitVirtualPath(relPath));
12626
14159
  return {
12627
14160
  async exists(relPath) {
@@ -12715,7 +14248,7 @@ async function resolveOpencodeVersionBestEffort(deps) {
12715
14248
  // src/cli/purgeAdapter.ts
12716
14249
  import { execFile } from "node:child_process";
12717
14250
  import * as fs2 from "node:fs";
12718
- import { dirname as dirname5, join as join15, resolve as resolve5 } from "node:path";
14251
+ import { dirname as dirname5, join as join15, resolve as resolve6 } from "node:path";
12719
14252
  import { promisify } from "node:util";
12720
14253
 
12721
14254
  // src/opencodeArtifacts/orchestratorAgent.ts
@@ -13125,7 +14658,7 @@ var REFUSAL_MARKERS = [
13125
14658
  "cannot remove a locked"
13126
14659
  ];
13127
14660
  function createPurgeAdapter(root) {
13128
- const repoRootAbs = resolve5(root);
14661
+ const repoRootAbs = resolve6(root);
13129
14662
  const worktreesDir = join15(repoRootAbs, ...DEFAULT_GRAPH_WORKTREES_DIR.split("/"));
13130
14663
  const agentDirAbs = join15(repoRootAbs, ...AGENT_DIR_POSIX.split("/"));
13131
14664
  const exec = nodeExec();
@@ -13134,7 +14667,7 @@ function createPurgeAdapter(root) {
13134
14667
  repoRoot: repoRootAbs,
13135
14668
  worktreesDir
13136
14669
  });
13137
- const toDisk = (relPath) => resolve5(repoRootAbs, relPath);
14670
+ const toDisk = (relPath) => resolve6(repoRootAbs, relPath);
13138
14671
  const runGit2 = async (rest) => exec("git", ["-C", repoRootAbs, ...GIT_TOP_FLAGS2, ...rest]);
13139
14672
  return {
13140
14673
  repoRoot() {
@@ -14334,11 +15867,11 @@ function planWorktreeReconciliation(input) {
14334
15867
  }
14335
15868
 
14336
15869
  // src/telemetry/otelConfig.ts
14337
- import { z as z19 } from "zod";
14338
- var OtelBackendConfigSchema = z19.object({
14339
- backend: z19.literal("opentelemetry"),
14340
- connectionEnv: z19.string().min(1),
14341
- serviceName: z19.string().min(1).optional()
15870
+ import { z as z21 } from "zod";
15871
+ var OtelBackendConfigSchema = z21.object({
15872
+ backend: z21.literal("opentelemetry"),
15873
+ connectionEnv: z21.string().min(1),
15874
+ serviceName: z21.string().min(1).optional()
14342
15875
  }).strict();
14343
15876
  function parseConnectionString(raw) {
14344
15877
  const pairs = new Map;
@@ -15317,31 +16850,31 @@ function mergeOpencodeConfigs(base, override) {
15317
16850
  }
15318
16851
 
15319
16852
  // src/graph/soakLedger.ts
15320
- import { z as z20 } from "zod";
15321
- var Sha256Schema2 = z20.string().regex(/^[0-9a-f]{64}$/);
15322
- var SoakPlatformSchema = z20.enum(["linux", "win32", "darwin"]);
15323
- var PrivacyPairSchema = z20.object({
15324
- surfacesScanned: z20.number().int().nonnegative(),
15325
- rawFindings: z20.number().int().nonnegative()
16853
+ import { z as z22 } from "zod";
16854
+ var Sha256Schema2 = z22.string().regex(/^[0-9a-f]{64}$/);
16855
+ var SoakPlatformSchema = z22.enum(["linux", "win32", "darwin"]);
16856
+ var PrivacyPairSchema = z22.object({
16857
+ surfacesScanned: z22.number().int().nonnegative(),
16858
+ rawFindings: z22.number().int().nonnegative()
15326
16859
  }).strict();
15327
- var DuplicateEffectPairSchema = z20.object({
15328
- effectsExamined: z20.number().int().nonnegative(),
15329
- duplicatesFound: z20.number().int().nonnegative()
16860
+ var DuplicateEffectPairSchema = z22.object({
16861
+ effectsExamined: z22.number().int().nonnegative(),
16862
+ duplicatesFound: z22.number().int().nonnegative()
15330
16863
  }).strict();
15331
- var ModelVerificationPairSchema = z20.object({
15332
- nodesChecked: z20.number().int().nonnegative(),
15333
- unverified: z20.number().int().nonnegative(),
15334
- mismatched: z20.number().int().nonnegative()
16864
+ var ModelVerificationPairSchema = z22.object({
16865
+ nodesChecked: z22.number().int().nonnegative(),
16866
+ unverified: z22.number().int().nonnegative(),
16867
+ mismatched: z22.number().int().nonnegative()
15335
16868
  }).strict();
15336
- var SoakObservationSchema = z20.object({
15337
- version: z20.literal(1),
15338
- seq: z20.number().int().nonnegative(),
15339
- timestamp: z20.string().datetime(),
16869
+ var SoakObservationSchema = z22.object({
16870
+ version: z22.literal(1),
16871
+ seq: z22.number().int().nonnegative(),
16872
+ timestamp: z22.string().datetime(),
15340
16873
  platform: SoakPlatformSchema,
15341
- opencodeVersion: z20.string().min(1),
15342
- provenance: z20.enum(["genuine-usage", "ci-synthetic"]),
16874
+ opencodeVersion: z22.string().min(1),
16875
+ provenance: z22.enum(["genuine-usage", "ci-synthetic"]),
15343
16876
  traceDigest: Sha256Schema2,
15344
- criticalDivergences: z20.number().int().nonnegative().nullable(),
16877
+ criticalDivergences: z22.number().int().nonnegative().nullable(),
15345
16878
  privacy: PrivacyPairSchema.nullable(),
15346
16879
  duplicateEffects: DuplicateEffectPairSchema.nullable(),
15347
16880
  modelVerification: ModelVerificationPairSchema.nullable(),
@@ -17762,14 +19295,14 @@ ${HELP}`
17762
19295
  }
17763
19296
 
17764
19297
  // src/orchestrator/roster.ts
17765
- import { z as z21 } from "zod";
17766
- var RosterEntrySchema = z21.object({
17767
- roleID: z21.string().min(1),
17768
- agentName: z21.string().min(1)
19298
+ import { z as z23 } from "zod";
19299
+ var RosterEntrySchema = z23.object({
19300
+ roleID: z23.string().min(1),
19301
+ agentName: z23.string().min(1)
17769
19302
  }).strict();
17770
- var RosterSchema = z21.object({
17771
- universe: z21.string().min(1),
17772
- entries: z21.array(RosterEntrySchema)
19303
+ var RosterSchema = z23.object({
19304
+ universe: z23.string().min(1),
19305
+ entries: z23.array(RosterEntrySchema)
17773
19306
  }).strict();
17774
19307
  var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
17775
19308
 
@@ -18323,7 +19856,7 @@ import { readFile as readFile2 } from "node:fs/promises";
18323
19856
  import { basename as basename3, dirname as dirname6 } from "node:path";
18324
19857
 
18325
19858
  // src/graph/certificate.ts
18326
- import { z as z22 } from "zod";
19859
+ import { z as z24 } from "zod";
18327
19860
 
18328
19861
  // src/contract/opencode.ts
18329
19862
  var SUPPORTED_OPENCODE_VERSIONS = [
@@ -18364,7 +19897,7 @@ function isCertificateVersionCompatible(certifiedVersion, liveVersion) {
18364
19897
 
18365
19898
  // src/graph/certificate.ts
18366
19899
  var SHADOW_CERTIFICATE_MIN_RUNS = 1000;
18367
- var DivergenceCodeSchema = z22.enum([
19900
+ var DivergenceCodeSchema = z24.enum([
18368
19901
  "status",
18369
19902
  "order",
18370
19903
  "roles",
@@ -18372,50 +19905,50 @@ var DivergenceCodeSchema = z22.enum([
18372
19905
  "fixes",
18373
19906
  "outcome"
18374
19907
  ]);
18375
- var ProvenanceSchema = z22.enum([
19908
+ var ProvenanceSchema = z24.enum([
18376
19909
  "recomputed",
18377
19910
  "compiled",
18378
19911
  "validated",
18379
19912
  "carried"
18380
19913
  ]);
18381
- var EvidenceSchema = z22.object({
18382
- opencodeVersion: z22.string().min(1),
18383
- parity: z22.object({
18384
- runs: z22.number().int().nonnegative(),
18385
- match: z22.number().int().nonnegative(),
18386
- divergent: z22.number().int().nonnegative(),
18387
- inconclusive: z22.number().int().nonnegative(),
18388
- divergences: z22.array(DivergenceCodeSchema)
19914
+ var EvidenceSchema = z24.object({
19915
+ opencodeVersion: z24.string().min(1),
19916
+ parity: z24.object({
19917
+ runs: z24.number().int().nonnegative(),
19918
+ match: z24.number().int().nonnegative(),
19919
+ divergent: z24.number().int().nonnegative(),
19920
+ inconclusive: z24.number().int().nonnegative(),
19921
+ divergences: z24.array(DivergenceCodeSchema)
18389
19922
  }).strict(),
18390
- legacy: z22.object({
18391
- observed: z22.number().int().nonnegative(),
18392
- duplicated: z22.number().int().nonnegative()
19923
+ legacy: z24.object({
19924
+ observed: z24.number().int().nonnegative(),
19925
+ duplicated: z24.number().int().nonnegative()
18393
19926
  }).strict(),
18394
- privacy: z22.object({
18395
- surfacesScanned: z22.number().int().nonnegative(),
18396
- rawFindings: z22.number().int().nonnegative()
19927
+ privacy: z24.object({
19928
+ surfacesScanned: z24.number().int().nonnegative(),
19929
+ rawFindings: z24.number().int().nonnegative()
18397
19930
  }).strict(),
18398
- overhead: z22.object({
18399
- p95Millis: z22.number().nonnegative(),
18400
- budgetMillis: z22.number().positive(),
18401
- samples: z22.number().int().nonnegative()
19931
+ overhead: z24.object({
19932
+ p95Millis: z24.number().nonnegative(),
19933
+ budgetMillis: z24.number().positive(),
19934
+ samples: z24.number().int().nonnegative()
18402
19935
  }).strict(),
18403
- provenance: z22.record(DivergenceCodeSchema, ProvenanceSchema)
19936
+ provenance: z24.record(DivergenceCodeSchema, ProvenanceSchema)
18404
19937
  }).strict();
18405
- var CertificateSchema = z22.object({
18406
- version: z22.literal(1),
18407
- certificate: z22.literal("graph-shadow"),
18408
- opencodeVersion: z22.string().min(1),
19938
+ var CertificateSchema = z24.object({
19939
+ version: z24.literal(1),
19940
+ certificate: z24.literal("graph-shadow"),
19941
+ opencodeVersion: z24.string().min(1),
18409
19942
  evidence: EvidenceSchema,
18410
- verdict: z22.enum(["pass", "fail"]),
18411
- failedGates: z22.array(z22.enum([
19943
+ verdict: z24.enum(["pass", "fail"]),
19944
+ failedGates: z24.array(z24.enum([
18412
19945
  "sample",
18413
19946
  "parity",
18414
19947
  "one-legacy-execution",
18415
19948
  "privacy",
18416
19949
  "overhead"
18417
19950
  ])),
18418
- digest: z22.string().regex(/^[0-9a-f]{64}$/)
19951
+ digest: z24.string().regex(/^[0-9a-f]{64}$/)
18419
19952
  }).strict();
18420
19953
 
18421
19954
  class ShadowCertificateError extends Error {
@@ -18530,37 +20063,37 @@ function parseShadowCertificate(value, opencodeVersion) {
18530
20063
  }
18531
20064
  return certificate;
18532
20065
  }
18533
- var ReleaseDeterminismSchema = z22.object({ runs: z22.number().int().nonnegative(), allMatch: z22.boolean() }).strict();
18534
- var ReleaseCrashRecoverySchema = z22.object({
18535
- scenarios: z22.number().int().nonnegative(),
18536
- allConverge: z22.boolean()
20066
+ var ReleaseDeterminismSchema = z24.object({ runs: z24.number().int().nonnegative(), allMatch: z24.boolean() }).strict();
20067
+ var ReleaseCrashRecoverySchema = z24.object({
20068
+ scenarios: z24.number().int().nonnegative(),
20069
+ allConverge: z24.boolean()
18537
20070
  }).strict();
18538
- var ReleaseReplayEquivalenceSchema = z22.object({
18539
- checks: z22.number().int().nonnegative(),
18540
- allEquivalent: z22.boolean()
20071
+ var ReleaseReplayEquivalenceSchema = z24.object({
20072
+ checks: z24.number().int().nonnegative(),
20073
+ allEquivalent: z24.boolean()
18541
20074
  }).strict();
18542
- var ReleasePrivacySchema = z22.object({
18543
- surfacesScanned: z22.number().int().nonnegative(),
18544
- rawFindings: z22.number().int().nonnegative()
20075
+ var ReleasePrivacySchema = z24.object({
20076
+ surfacesScanned: z24.number().int().nonnegative(),
20077
+ rawFindings: z24.number().int().nonnegative()
18545
20078
  }).strict();
18546
- var ReleaseContractSchema = z22.object({
18547
- roundTrips: z22.number().int().nonnegative(),
18548
- allSettled: z22.boolean()
20079
+ var ReleaseContractSchema = z24.object({
20080
+ roundTrips: z24.number().int().nonnegative(),
20081
+ allSettled: z24.boolean()
18549
20082
  }).strict();
18550
- var ReleaseHealthSchema = z22.object({
18551
- samples: z22.number().int().nonnegative(),
18552
- bounded: z22.boolean(),
18553
- idempotent: z22.boolean()
20083
+ var ReleaseHealthSchema = z24.object({
20084
+ samples: z24.number().int().nonnegative(),
20085
+ bounded: z24.boolean(),
20086
+ idempotent: z24.boolean()
18554
20087
  }).strict();
18555
- var ReleasePerformanceSchema = z22.object({
18556
- p95Millis: z22.number().nonnegative(),
18557
- budgetMillis: z22.number().positive(),
18558
- samples: z22.number().int().nonnegative()
20088
+ var ReleasePerformanceSchema = z24.object({
20089
+ p95Millis: z24.number().nonnegative(),
20090
+ budgetMillis: z24.number().positive(),
20091
+ samples: z24.number().int().nonnegative()
18559
20092
  }).strict();
18560
- var ReleaseEvidenceSchema = z22.object({
18561
- opencodeVersion: z22.string().min(1),
18562
- platform: z22.enum(["linux", "win32"]),
18563
- shadowCertificateDigest: z22.string().regex(/^[0-9a-f]{64}$/),
20093
+ var ReleaseEvidenceSchema = z24.object({
20094
+ opencodeVersion: z24.string().min(1),
20095
+ platform: z24.enum(["linux", "win32"]),
20096
+ shadowCertificateDigest: z24.string().regex(/^[0-9a-f]{64}$/),
18564
20097
  determinism: ReleaseDeterminismSchema,
18565
20098
  crashRecovery: ReleaseCrashRecoverySchema,
18566
20099
  replayEquivalence: ReleaseReplayEquivalenceSchema,
@@ -18569,15 +20102,15 @@ var ReleaseEvidenceSchema = z22.object({
18569
20102
  health: ReleaseHealthSchema,
18570
20103
  performance: ReleasePerformanceSchema
18571
20104
  }).strict();
18572
- var ReleaseCertificateSchema = z22.object({
18573
- version: z22.literal(2),
18574
- certificate: z22.literal("graph-release"),
18575
- platform: z22.enum(["linux", "win32"]),
18576
- opencodeVersion: z22.string().min(1),
18577
- shadowCertificateDigest: z22.string().regex(/^[0-9a-f]{64}$/),
20105
+ var ReleaseCertificateSchema = z24.object({
20106
+ version: z24.literal(2),
20107
+ certificate: z24.literal("graph-release"),
20108
+ platform: z24.enum(["linux", "win32"]),
20109
+ opencodeVersion: z24.string().min(1),
20110
+ shadowCertificateDigest: z24.string().regex(/^[0-9a-f]{64}$/),
18578
20111
  evidence: ReleaseEvidenceSchema,
18579
- verdict: z22.enum(["pass", "fail"]),
18580
- failedGates: z22.array(z22.enum([
20112
+ verdict: z24.enum(["pass", "fail"]),
20113
+ failedGates: z24.array(z24.enum([
18581
20114
  "shadow-valid",
18582
20115
  "determinism",
18583
20116
  "crash-recovery",
@@ -18587,7 +20120,7 @@ var ReleaseCertificateSchema = z22.object({
18587
20120
  "health",
18588
20121
  "performance"
18589
20122
  ])),
18590
- digest: z22.string().regex(/^[0-9a-f]{64}$/)
20123
+ digest: z24.string().regex(/^[0-9a-f]{64}$/)
18591
20124
  }).strict();
18592
20125
 
18593
20126
  class ReleaseCertificateError extends Error {
@@ -18715,7 +20248,7 @@ function parseReleaseCertificate(value, opencodeVersion, expectedShadowDigest) {
18715
20248
  }
18716
20249
  return certificate;
18717
20250
  }
18718
- var ShadowDivergenceCodeSchema = z22.enum([
20251
+ var ShadowDivergenceCodeSchema = z24.enum([
18719
20252
  "status",
18720
20253
  "order",
18721
20254
  "roles",
@@ -18724,13 +20257,13 @@ var ShadowDivergenceCodeSchema = z22.enum([
18724
20257
  "outcome"
18725
20258
  ]);
18726
20259
  var RECOMPUTED_DIVERGENCE_CODES = ["fixes"];
18727
- var RecomputedDivergenceCodeSchema = z22.enum(RECOMPUTED_DIVERGENCE_CODES);
18728
- var SoakPolicySchema = z22.object({
18729
- minimumGenuineObservations: z22.number().int().positive(),
18730
- minimumDistinctDays: z22.number().int().positive(),
18731
- requireGenuineUsageOnAllPlatforms: z22.boolean(),
18732
- supportedOpencodeVersions: z22.array(z22.string().min(1)).min(1),
18733
- criticalDivergenceCodes: z22.array(RecomputedDivergenceCodeSchema).min(1)
20260
+ var RecomputedDivergenceCodeSchema = z24.enum(RECOMPUTED_DIVERGENCE_CODES);
20261
+ var SoakPolicySchema = z24.object({
20262
+ minimumGenuineObservations: z24.number().int().positive(),
20263
+ minimumDistinctDays: z24.number().int().positive(),
20264
+ requireGenuineUsageOnAllPlatforms: z24.boolean(),
20265
+ supportedOpencodeVersions: z24.array(z24.string().min(1)).min(1),
20266
+ criticalDivergenceCodes: z24.array(RecomputedDivergenceCodeSchema).min(1)
18734
20267
  }).strict();
18735
20268
  var DEFAULT_SOAK_POLICY = {
18736
20269
  minimumGenuineObservations: 100,
@@ -18739,46 +20272,46 @@ var DEFAULT_SOAK_POLICY = {
18739
20272
  supportedOpencodeVersions: [...SUPPORTED_OPENCODE_VERSIONS],
18740
20273
  criticalDivergenceCodes: ["fixes"]
18741
20274
  };
18742
- var SoakPlatformEnumSchema = z22.enum(["linux", "win32", "darwin"]);
18743
- var SoakPrivacyPairEvidenceSchema = z22.object({
18744
- surfacesScanned: z22.number().int().nonnegative(),
18745
- rawFindings: z22.number().int().nonnegative()
20275
+ var SoakPlatformEnumSchema = z24.enum(["linux", "win32", "darwin"]);
20276
+ var SoakPrivacyPairEvidenceSchema = z24.object({
20277
+ surfacesScanned: z24.number().int().nonnegative(),
20278
+ rawFindings: z24.number().int().nonnegative()
18746
20279
  }).strict();
18747
- var SoakDuplicateEffectPairEvidenceSchema = z22.object({
18748
- effectsExamined: z22.number().int().nonnegative(),
18749
- duplicatesFound: z22.number().int().nonnegative()
20280
+ var SoakDuplicateEffectPairEvidenceSchema = z24.object({
20281
+ effectsExamined: z24.number().int().nonnegative(),
20282
+ duplicatesFound: z24.number().int().nonnegative()
18750
20283
  }).strict();
18751
- var SoakModelVerificationPairEvidenceSchema = z22.object({
18752
- nodesChecked: z22.number().int().nonnegative(),
18753
- unverified: z22.number().int().nonnegative(),
18754
- mismatched: z22.number().int().nonnegative()
20284
+ var SoakModelVerificationPairEvidenceSchema = z24.object({
20285
+ nodesChecked: z24.number().int().nonnegative(),
20286
+ unverified: z24.number().int().nonnegative(),
20287
+ mismatched: z24.number().int().nonnegative()
18755
20288
  }).strict();
18756
- var SoakEvidenceSchema = z22.object({
18757
- totalObservations: z22.number().int().nonnegative(),
18758
- genuineUsageObservations: z22.number().int().nonnegative(),
18759
- ciSyntheticObservations: z22.number().int().nonnegative(),
18760
- recorderCount: z22.number().int().nonnegative(),
18761
- ineligibleObservations: z22.number().int().nonnegative(),
18762
- firstTimestamp: z22.string().datetime().nullable(),
18763
- lastTimestamp: z22.string().datetime().nullable(),
18764
- distinctDays: z22.number().int().nonnegative(),
18765
- criticalDivergences: z22.number().int().nonnegative().nullable(),
20289
+ var SoakEvidenceSchema = z24.object({
20290
+ totalObservations: z24.number().int().nonnegative(),
20291
+ genuineUsageObservations: z24.number().int().nonnegative(),
20292
+ ciSyntheticObservations: z24.number().int().nonnegative(),
20293
+ recorderCount: z24.number().int().nonnegative(),
20294
+ ineligibleObservations: z24.number().int().nonnegative(),
20295
+ firstTimestamp: z24.string().datetime().nullable(),
20296
+ lastTimestamp: z24.string().datetime().nullable(),
20297
+ distinctDays: z24.number().int().nonnegative(),
20298
+ criticalDivergences: z24.number().int().nonnegative().nullable(),
18766
20299
  privacy: SoakPrivacyPairEvidenceSchema.nullable(),
18767
20300
  duplicateEffects: SoakDuplicateEffectPairEvidenceSchema.nullable(),
18768
20301
  modelVerification: SoakModelVerificationPairEvidenceSchema.nullable(),
18769
- platformsGenuine: z22.array(SoakPlatformEnumSchema),
18770
- platformsSynthetic: z22.array(SoakPlatformEnumSchema),
18771
- opencodeVersionsObserved: z22.array(z22.string().min(1)),
18772
- invalidChains: z22.number().int().nonnegative()
20302
+ platformsGenuine: z24.array(SoakPlatformEnumSchema),
20303
+ platformsSynthetic: z24.array(SoakPlatformEnumSchema),
20304
+ opencodeVersionsObserved: z24.array(z24.string().min(1)),
20305
+ invalidChains: z24.number().int().nonnegative()
18773
20306
  }).strict();
18774
- var SoakCertificateSchema = z22.object({
18775
- version: z22.literal(1),
18776
- certificate: z22.literal("graph-soak"),
18777
- trustBoundary: z22.literal("contributors"),
20307
+ var SoakCertificateSchema = z24.object({
20308
+ version: z24.literal(1),
20309
+ certificate: z24.literal("graph-soak"),
20310
+ trustBoundary: z24.literal("contributors"),
18778
20311
  policy: SoakPolicySchema,
18779
20312
  evidence: SoakEvidenceSchema,
18780
- verdict: z22.enum(["pass", "fail"]),
18781
- failedGates: z22.array(z22.enum([
20313
+ verdict: z24.enum(["pass", "fail"]),
20314
+ failedGates: z24.array(z24.enum([
18782
20315
  "minimum-observations",
18783
20316
  "minimum-duration",
18784
20317
  "chain-integrity",
@@ -18789,8 +20322,8 @@ var SoakCertificateSchema = z22.object({
18789
20322
  "os-diversity",
18790
20323
  "opencode-pin"
18791
20324
  ])),
18792
- ledgerDigest: z22.string().regex(/^[0-9a-f]{64}$/),
18793
- digest: z22.string().regex(/^[0-9a-f]{64}$/)
20325
+ ledgerDigest: z24.string().regex(/^[0-9a-f]{64}$/),
20326
+ digest: z24.string().regex(/^[0-9a-f]{64}$/)
18794
20327
  }).strict();
18795
20328
 
18796
20329
  class SoakCertificateError extends Error {
@@ -18916,7 +20449,7 @@ function parseSoakCertificate(value, expectedPolicy, expectedLedgerDigest) {
18916
20449
  }
18917
20450
 
18918
20451
  // src/lifecycle/root.ts
18919
- import { isAbsolute, normalize, relative as relative2, resolve as resolve8 } from "node:path";
20452
+ import { isAbsolute as isAbsolute2, normalize as normalize2, relative as relative2, resolve as resolve9 } from "node:path";
18920
20453
 
18921
20454
  // src/messages/lifecycleStorage.ts
18922
20455
  var lifecycleStorageMessages = {
@@ -18925,16 +20458,16 @@ var lifecycleStorageMessages = {
18925
20458
 
18926
20459
  // src/lifecycle/root.ts
18927
20460
  var resolveLifecycleRoot = (options) => {
18928
- const workspaceRoot = resolve8(options.workspaceRoot);
18929
- if (isAbsolute(options.configuredRoot)) {
18930
- return normalize(resolve8(options.configuredRoot));
20461
+ const workspaceRoot = resolve9(options.workspaceRoot);
20462
+ if (isAbsolute2(options.configuredRoot)) {
20463
+ return normalize2(resolve9(options.configuredRoot));
18931
20464
  }
18932
- const resolved = resolve8(workspaceRoot, options.configuredRoot);
20465
+ const resolved = resolve9(workspaceRoot, options.configuredRoot);
18933
20466
  const workspaceRelative = relative2(workspaceRoot, resolved);
18934
- if (workspaceRelative === ".." || workspaceRelative.startsWith(`..\\`) || workspaceRelative.startsWith("../") || isAbsolute(workspaceRelative)) {
20467
+ if (workspaceRelative === ".." || workspaceRelative.startsWith(`..\\`) || workspaceRelative.startsWith("../") || isAbsolute2(workspaceRelative)) {
18935
20468
  throw new Error(lifecycleStorageMessages.configuredRootEscapesWorkspace);
18936
20469
  }
18937
- return normalize(resolved);
20470
+ return normalize2(resolved);
18938
20471
  };
18939
20472
 
18940
20473
  // src/lifecycle/runtimeRecorder.ts
@@ -19438,62 +20971,62 @@ var realCacheAdapter = {
19438
20971
  };
19439
20972
 
19440
20973
  // src/memory/types.ts
19441
- import { z as z23 } from "zod";
20974
+ import { z as z25 } from "zod";
19442
20975
  var SHARED_OWNER_KEY = "*";
19443
- var OwnerKeySchema = z23.string().min(1);
19444
- var MemoryKindSchema = z23.enum(["fact", "preference", "entity"]);
19445
- var MemoryBaseSchema = z23.object({
19446
- id: z23.string().min(1),
20976
+ var OwnerKeySchema = z25.string().min(1);
20977
+ var MemoryKindSchema = z25.enum(["fact", "preference", "entity"]);
20978
+ var MemoryBaseSchema = z25.object({
20979
+ id: z25.string().min(1),
19447
20980
  ownerKey: OwnerKeySchema,
19448
- confidence: z23.number().min(0).max(1),
19449
- validFrom: z23.number().finite(),
19450
- validUntil: z23.number().finite().nullable().default(null),
19451
- createdAt: z23.number().finite(),
19452
- invalidatedAt: z23.number().finite().nullable().default(null),
19453
- sourceHash: z23.string().min(1),
19454
- supersededBy: z23.string().min(1).nullable().default(null)
20981
+ confidence: z25.number().min(0).max(1),
20982
+ validFrom: z25.number().finite(),
20983
+ validUntil: z25.number().finite().nullable().default(null),
20984
+ createdAt: z25.number().finite(),
20985
+ invalidatedAt: z25.number().finite().nullable().default(null),
20986
+ sourceHash: z25.string().min(1),
20987
+ supersededBy: z25.string().min(1).nullable().default(null)
19455
20988
  }).strict();
19456
20989
  var FactSchema = MemoryBaseSchema.extend({
19457
- kind: z23.literal("fact"),
19458
- subject: z23.string().min(1),
19459
- predicate: z23.string().min(1),
19460
- object: z23.string().min(1),
19461
- category: z23.string().min(1).nullable().default(null)
20990
+ kind: z25.literal("fact"),
20991
+ subject: z25.string().min(1),
20992
+ predicate: z25.string().min(1),
20993
+ object: z25.string().min(1),
20994
+ category: z25.string().min(1).nullable().default(null)
19462
20995
  });
19463
20996
  var PreferenceSchema = MemoryBaseSchema.extend({
19464
- kind: z23.literal("preference"),
19465
- category: z23.string().min(1),
19466
- preference: z23.string().min(1),
19467
- context: z23.string().min(1).nullable().default(null),
19468
- lastAccessedAt: z23.number().finite().nullable().default(null),
19469
- accessCount: z23.number().int().min(0).default(0)
20997
+ kind: z25.literal("preference"),
20998
+ category: z25.string().min(1),
20999
+ preference: z25.string().min(1),
21000
+ context: z25.string().min(1).nullable().default(null),
21001
+ lastAccessedAt: z25.number().finite().nullable().default(null),
21002
+ accessCount: z25.number().int().min(0).default(0)
19470
21003
  });
19471
21004
  var EntitySchema = MemoryBaseSchema.extend({
19472
- kind: z23.literal("entity"),
19473
- canonicalName: z23.string().min(1),
19474
- type: z23.string().min(1),
19475
- aliases: z23.array(z23.string().min(1)).default([])
21005
+ kind: z25.literal("entity"),
21006
+ canonicalName: z25.string().min(1),
21007
+ type: z25.string().min(1),
21008
+ aliases: z25.array(z25.string().min(1)).default([])
19476
21009
  });
19477
21010
  var RelationSchema = MemoryBaseSchema.extend({
19478
- kind: z23.literal("relation"),
19479
- from: z23.string().min(1),
19480
- to: z23.string().min(1),
19481
- predicate: z23.string().min(1),
19482
- annotation: z23.string().min(1).nullable().default(null)
21011
+ kind: z25.literal("relation"),
21012
+ from: z25.string().min(1),
21013
+ to: z25.string().min(1),
21014
+ predicate: z25.string().min(1),
21015
+ annotation: z25.string().min(1).nullable().default(null)
19483
21016
  });
19484
- var MemoryRecordSchema = z23.discriminatedUnion("kind", [
21017
+ var MemoryRecordSchema = z25.discriminatedUnion("kind", [
19485
21018
  FactSchema,
19486
21019
  PreferenceSchema,
19487
21020
  EntitySchema,
19488
21021
  RelationSchema
19489
21022
  ]);
19490
- var RecallQuerySchema = z23.object({
21023
+ var RecallQuerySchema = z25.object({
19491
21024
  ownerKey: OwnerKeySchema,
19492
- kinds: z23.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
19493
- asOf: z23.number().finite().nullable().default(null),
19494
- limit: z23.number().int().positive().default(8),
19495
- minSimilarity: z23.number().min(0).max(1).default(0.2),
19496
- includeShared: z23.boolean().default(true)
21025
+ kinds: z25.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
21026
+ asOf: z25.number().finite().nullable().default(null),
21027
+ limit: z25.number().int().positive().default(8),
21028
+ minSimilarity: z25.number().min(0).max(1).default(0.2),
21029
+ includeShared: z25.boolean().default(true)
19497
21030
  }).strict();
19498
21031
 
19499
21032
  // src/memory/rank.ts
@@ -20102,12 +21635,12 @@ function createLocalEmbedder(request, deps) {
20102
21635
  }
20103
21636
 
20104
21637
  // src/memory/embedText.ts
20105
- function normalize2(parts) {
21638
+ function normalize3(parts) {
20106
21639
  return parts.map((part) => part.trim()).filter((part) => part.length > 0).join(" ");
20107
21640
  }
20108
21641
  function recordEmbeddingText(record2) {
20109
21642
  if (record2.kind === "fact") {
20110
- return normalize2([
21643
+ return normalize3([
20111
21644
  record2.subject,
20112
21645
  record2.predicate,
20113
21646
  record2.object,
@@ -20115,21 +21648,21 @@ function recordEmbeddingText(record2) {
20115
21648
  ]);
20116
21649
  }
20117
21650
  if (record2.kind === "preference") {
20118
- return normalize2([
21651
+ return normalize3([
20119
21652
  record2.category,
20120
21653
  record2.preference,
20121
21654
  record2.context ?? ""
20122
21655
  ]);
20123
21656
  }
20124
21657
  if (record2.kind === "relation") {
20125
- return normalize2([
21658
+ return normalize3([
20126
21659
  record2.from,
20127
21660
  record2.predicate,
20128
21661
  record2.to,
20129
21662
  record2.annotation ?? ""
20130
21663
  ]);
20131
21664
  }
20132
- return normalize2([record2.canonicalName, record2.type, ...record2.aliases]);
21665
+ return normalize3([record2.canonicalName, record2.type, ...record2.aliases]);
20133
21666
  }
20134
21667
 
20135
21668
  // src/storage/index/memoryEmbeddings.ts
@@ -20211,7 +21744,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
20211
21744
  // package.json
20212
21745
  var package_default = {
20213
21746
  name: "@jmanuelcorral/openteam",
20214
- version: "0.20.0",
21747
+ version: "0.21.0",
20215
21748
  packageManager: "bun@1.3.14",
20216
21749
  description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
20217
21750
  license: "MIT",
@@ -20338,14 +21871,14 @@ async function readPackagedCertificate(path4) {
20338
21871
  return;
20339
21872
  }
20340
21873
  }
20341
- async function readAndParseCertificate(storage, path4, parse2, digestExtractor, fallbackRead) {
21874
+ async function readAndParseCertificate(storage, path4, parse3, digestExtractor, fallbackRead) {
20342
21875
  try {
20343
21876
  const content = await storage.read(path4) ?? (fallbackRead === undefined ? undefined : await fallbackRead(path4));
20344
21877
  if (content === undefined) {
20345
21878
  return { status: "absent" };
20346
21879
  }
20347
21880
  const raw = JSON.parse(content);
20348
- const cert = parse2(raw);
21881
+ const cert = parse3(raw);
20349
21882
  return { status: "valid", digest: digestExtractor(cert) };
20350
21883
  } catch (error) {
20351
21884
  if (isMissingFile(error)) {
@@ -21104,7 +22637,7 @@ async function readConfigFile(path4, resolution) {
21104
22637
  return storage.read(path4);
21105
22638
  }
21106
22639
  try {
21107
- return await readFile3(resolve9(path4), "utf8");
22640
+ return await readFile3(resolve10(path4), "utf8");
21108
22641
  } catch (error) {
21109
22642
  throw new Error(`[openteam] config file named by --config could not be read: ${path4} (${describeFileReadError(error)})`);
21110
22643
  }
@@ -21127,7 +22660,7 @@ async function saveConfig(config, path4, resolution = { explicit: false }) {
21127
22660
  return;
21128
22661
  }
21129
22662
  const contents = serializeOpenTeamConfig(config);
21130
- const diskPath = resolve9(path4);
22663
+ const diskPath = resolve10(path4);
21131
22664
  await mkdir2(dirname7(diskPath), { recursive: true });
21132
22665
  await writeFile2(diskPath, contents, "utf8");
21133
22666
  }
@@ -21173,8 +22706,8 @@ async function openBrowser(url) {
21173
22706
  }
21174
22707
  }
21175
22708
  function waitForSignal() {
21176
- return new Promise((resolve10) => {
21177
- const done = () => resolve10();
22709
+ return new Promise((resolve11) => {
22710
+ const done = () => resolve11();
21178
22711
  process.once("SIGINT", done);
21179
22712
  process.once("SIGTERM", done);
21180
22713
  });
@@ -21363,7 +22896,7 @@ async function main() {
21363
22896
  workspaceRoot,
21364
22897
  configuredRoot: initialConsoleConfig.lifecycle?.root ?? DEFAULT_LIFECYCLE_ROOT
21365
22898
  });
21366
- const legacyGraphRoot = resolve9(workspaceRoot, initialConsoleConfig.graph?.journalRoot ?? DEFAULT_GRAPH_JOURNAL_ROOT);
22899
+ const legacyGraphRoot = resolve10(workspaceRoot, initialConsoleConfig.graph?.journalRoot ?? DEFAULT_GRAPH_JOURNAL_ROOT);
21367
22900
  const lifecycleAvailability = initialConsoleConfig.console.graphView?.enabled === true ? "enabled" : "history-disabled";
21368
22901
  const lifecycleHistoryReader = createLifecycleHistoryProvider({
21369
22902
  lifecycleRoot,