@adhdev/daemon-standalone 0.9.82-rc.353 → 0.9.82-rc.355
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +699 -219
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/vendor/mcp-server/index.js +36 -5
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -30036,10 +30036,10 @@ var require_dist3 = __commonJS({
|
|
|
30036
30036
|
}
|
|
30037
30037
|
function getDaemonBuildInfo() {
|
|
30038
30038
|
if (cached2) return cached2;
|
|
30039
|
-
const commit = readInjected(true ? "
|
|
30040
|
-
const commitShort = readInjected(true ? "
|
|
30041
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30042
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
30039
|
+
const commit = readInjected(true ? "a45106605e2ae1c10c0bc6cbe48c2cac4e862ded" : void 0) ?? "unknown";
|
|
30040
|
+
const commitShort = readInjected(true ? "a4510660" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30041
|
+
const version2 = readInjected(true ? "0.9.82-rc.355" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30042
|
+
const builtAt = readInjected(true ? "2026-06-22T15:22:12.689Z" : void 0);
|
|
30043
30043
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30044
30044
|
return cached2;
|
|
30045
30045
|
}
|
|
@@ -30793,6 +30793,9 @@ var require_dist3 = __commonJS({
|
|
|
30793
30793
|
getGitDiffSummary: () => getGitDiffSummary,
|
|
30794
30794
|
getGitFileDiff: () => getGitFileDiff
|
|
30795
30795
|
});
|
|
30796
|
+
function withCollectionTimeout(options) {
|
|
30797
|
+
return options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
|
|
30798
|
+
}
|
|
30796
30799
|
function validateBaseRef(ref) {
|
|
30797
30800
|
const trimmed = ref.trim();
|
|
30798
30801
|
if (!trimmed || trimmed.startsWith("-") || trimmed.includes("..") || !/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(trimmed)) {
|
|
@@ -30802,14 +30805,15 @@ var require_dist3 = __commonJS({
|
|
|
30802
30805
|
}
|
|
30803
30806
|
async function getGitDiffSummary(workspace, options = {}) {
|
|
30804
30807
|
const lastCheckedAt = Date.now();
|
|
30808
|
+
const effectiveOptions = withCollectionTimeout(options);
|
|
30805
30809
|
try {
|
|
30806
|
-
const repo = await resolveGitRepository(workspace,
|
|
30810
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
30807
30811
|
const repoRoot = repo.repoRoot;
|
|
30808
30812
|
if (options.baseRef) {
|
|
30809
30813
|
const range = `${validateBaseRef(options.baseRef)}...HEAD`;
|
|
30810
30814
|
const [nameStatus, numstat] = await Promise.all([
|
|
30811
|
-
runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...
|
|
30812
|
-
runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...
|
|
30815
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...effectiveOptions, cwd: repoRoot }),
|
|
30816
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...effectiveOptions, cwd: repoRoot })
|
|
30813
30817
|
]);
|
|
30814
30818
|
const outputBytes2 = byteLength(nameStatus.stdout + numstat.stdout);
|
|
30815
30819
|
const changes2 = combineDiffEntries(nameStatus.stdout, numstat.stdout, false);
|
|
@@ -30828,11 +30832,11 @@ var require_dist3 = __commonJS({
|
|
|
30828
30832
|
};
|
|
30829
30833
|
}
|
|
30830
30834
|
const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
|
|
30831
|
-
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...
|
|
30832
|
-
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...
|
|
30833
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...
|
|
30834
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...
|
|
30835
|
-
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...
|
|
30835
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
|
|
30836
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
|
|
30837
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
|
|
30838
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
|
|
30839
|
+
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...effectiveOptions, cwd: repoRoot })
|
|
30836
30840
|
]);
|
|
30837
30841
|
const outputBytes = byteLength(
|
|
30838
30842
|
unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
|
|
@@ -30874,13 +30878,14 @@ var require_dist3 = __commonJS({
|
|
|
30874
30878
|
}
|
|
30875
30879
|
async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
30876
30880
|
const lastCheckedAt = Date.now();
|
|
30877
|
-
const
|
|
30881
|
+
const effectiveOptions = withCollectionTimeout(options);
|
|
30882
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
30878
30883
|
const repoRoot = repo.repoRoot;
|
|
30879
30884
|
const selected = await resolveRepoFilePath(repoRoot, filePath);
|
|
30880
30885
|
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
30881
30886
|
if (options.baseRef) {
|
|
30882
30887
|
const range = `${validateBaseRef(options.baseRef)}...HEAD`;
|
|
30883
|
-
const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...
|
|
30888
|
+
const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot });
|
|
30884
30889
|
const bounded2 = truncateText(result.stdout, maxBytes);
|
|
30885
30890
|
return {
|
|
30886
30891
|
workspace: repo.workspace,
|
|
@@ -30893,13 +30898,13 @@ var require_dist3 = __commonJS({
|
|
|
30893
30898
|
};
|
|
30894
30899
|
}
|
|
30895
30900
|
const [unstaged, staged] = await Promise.all([
|
|
30896
|
-
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...
|
|
30897
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...
|
|
30901
|
+
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot }),
|
|
30902
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot })
|
|
30898
30903
|
]);
|
|
30899
30904
|
let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
|
|
30900
30905
|
if (!diff) {
|
|
30901
30906
|
const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
|
|
30902
|
-
...
|
|
30907
|
+
...effectiveOptions,
|
|
30903
30908
|
cwd: repoRoot
|
|
30904
30909
|
});
|
|
30905
30910
|
const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
|
|
@@ -34588,9 +34593,12 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
34588
34593
|
return [];
|
|
34589
34594
|
}
|
|
34590
34595
|
}
|
|
34591
|
-
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
34596
|
+
function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
34592
34597
|
try {
|
|
34593
|
-
|
|
34598
|
+
if (!taskId) {
|
|
34599
|
+
LOG2.warn("MeshQueue", `updateDirectDispatchStatus(${status}) for mesh ${meshId} session ${sessionId} has no taskId \u2014 falling back to session_id match (may flip a sibling dispatch row)`);
|
|
34600
|
+
}
|
|
34601
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
|
|
34594
34602
|
} catch {
|
|
34595
34603
|
}
|
|
34596
34604
|
}
|
|
@@ -35435,9 +35443,25 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
35435
35443
|
updatedAt: r.updated_at
|
|
35436
35444
|
}));
|
|
35437
35445
|
}
|
|
35438
|
-
|
|
35439
|
-
|
|
35446
|
+
// CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
|
|
35447
|
+
// single session can host several sequential direct dispatches (re-dispatch / nudge), so
|
|
35448
|
+
// matching a status flip by session_id alone hits EVERY non-terminal row for that session
|
|
35449
|
+
// — flipping a sibling task's row and stranding the one whose event actually fired (the
|
|
35450
|
+
// assigned-stranded watchdog then requeues a task that is really still generating). When
|
|
35451
|
+
// the firing event carries a taskId, target the single PK row; the session_id match is the
|
|
35452
|
+
// legacy fallback only for events that arrive without a taskId.
|
|
35453
|
+
updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
35440
35454
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
35455
|
+
if (taskId) {
|
|
35456
|
+
this.db.prepare(`
|
|
35457
|
+
UPDATE mesh_direct_dispatches
|
|
35458
|
+
SET status = @status, updated_at = @updatedAt
|
|
35459
|
+
WHERE mesh_id = @meshId AND task_id = @taskId
|
|
35460
|
+
AND status NOT IN ('completed', 'failed')
|
|
35461
|
+
`).run({ status, meshId, taskId, updatedAt: now });
|
|
35462
|
+
return;
|
|
35463
|
+
}
|
|
35464
|
+
if (!sessionId) return;
|
|
35441
35465
|
this.db.prepare(`
|
|
35442
35466
|
UPDATE mesh_direct_dispatches
|
|
35443
35467
|
SET status = @status, updated_at = @updatedAt
|
|
@@ -37164,7 +37188,7 @@ ${rendered}`, "utf-8");
|
|
|
37164
37188
|
windowsHide: true
|
|
37165
37189
|
}).trim();
|
|
37166
37190
|
if (out) {
|
|
37167
|
-
const matches = out.split(/\r?\n/).map((
|
|
37191
|
+
const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
|
|
37168
37192
|
const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
|
|
37169
37193
|
return direct || matches[0] || command;
|
|
37170
37194
|
}
|
|
@@ -38516,11 +38540,29 @@ Next step: ${nextStep}`;
|
|
|
38516
38540
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
38517
38541
|
);
|
|
38518
38542
|
}
|
|
38543
|
+
function isWeakCompletionMetadata(metadata) {
|
|
38544
|
+
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
38545
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
38546
|
+
if (metadata.reviewRecommended === true) return true;
|
|
38547
|
+
const diag = readRecord4(metadata.completionDiagnostic);
|
|
38548
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
38549
|
+
}
|
|
38519
38550
|
function buildPendingEventFingerprint(event) {
|
|
38520
38551
|
const metadata = readRecord4(event.metadataEvent) || {};
|
|
38521
38552
|
if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
|
|
38522
38553
|
return [event.meshId, event.event, event.nodeId || ""].join("::");
|
|
38523
38554
|
}
|
|
38555
|
+
if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
|
|
38556
|
+
const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
38557
|
+
if (terminalTaskId) {
|
|
38558
|
+
return [
|
|
38559
|
+
event.meshId,
|
|
38560
|
+
event.event,
|
|
38561
|
+
terminalTaskId,
|
|
38562
|
+
isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
|
|
38563
|
+
].join("::");
|
|
38564
|
+
}
|
|
38565
|
+
}
|
|
38524
38566
|
const sessionId = resolveEventSessionId(metadata);
|
|
38525
38567
|
const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
|
|
38526
38568
|
const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
@@ -38883,6 +38925,7 @@ Next step: ${nextStep}`;
|
|
|
38883
38925
|
var import_path9;
|
|
38884
38926
|
var import_crypto7;
|
|
38885
38927
|
var REFINE_TERMINAL_EVENTS;
|
|
38928
|
+
var TERMINAL_COMPLETION_EVENTS;
|
|
38886
38929
|
var MAX_PENDING_EVENTS_BYTES;
|
|
38887
38930
|
var MAX_PENDING_EVENTS_KEEP;
|
|
38888
38931
|
var init_mesh_events_pending = __esm2({
|
|
@@ -38897,6 +38940,7 @@ Next step: ${nextStep}`;
|
|
|
38897
38940
|
init_mesh_events_utils();
|
|
38898
38941
|
init_dist();
|
|
38899
38942
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
38943
|
+
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
38900
38944
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
38901
38945
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
38902
38946
|
}
|
|
@@ -39225,7 +39269,7 @@ Next step: ${nextStep}`;
|
|
|
39225
39269
|
evidence
|
|
39226
39270
|
}
|
|
39227
39271
|
});
|
|
39228
|
-
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
39272
|
+
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
|
|
39229
39273
|
markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
39230
39274
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
39231
39275
|
queuePendingMeshCoordinatorEvent({
|
|
@@ -39511,8 +39555,8 @@ Next step: ${nextStep}`;
|
|
|
39511
39555
|
if (x instanceof RegExp) return x;
|
|
39512
39556
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
39513
39557
|
try {
|
|
39514
|
-
const
|
|
39515
|
-
return new RegExp(
|
|
39558
|
+
const s2 = x;
|
|
39559
|
+
return new RegExp(s2.source, s2.flags || "");
|
|
39516
39560
|
} catch {
|
|
39517
39561
|
return null;
|
|
39518
39562
|
}
|
|
@@ -40086,6 +40130,36 @@ Next step: ${nextStep}`;
|
|
|
40086
40130
|
UNRESOLVED_FORWARD_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
40087
40131
|
}
|
|
40088
40132
|
});
|
|
40133
|
+
function s(v) {
|
|
40134
|
+
return typeof v === "string" && v.trim() ? v.trim() : "";
|
|
40135
|
+
}
|
|
40136
|
+
function meshEventTraceKey(ctx) {
|
|
40137
|
+
const segs = [`task=${s(ctx.taskId) || "-"}`];
|
|
40138
|
+
const eventId = s(ctx.eventId);
|
|
40139
|
+
if (eventId) segs.push(`evt=${eventId}`);
|
|
40140
|
+
segs.push(`sess=${s(ctx.sessionId) || "-"}`);
|
|
40141
|
+
const nodeId = s(ctx.nodeId);
|
|
40142
|
+
if (nodeId) segs.push(`node=${nodeId}`);
|
|
40143
|
+
const meshId = s(ctx.meshId);
|
|
40144
|
+
if (meshId) segs.push(`mesh=${meshId}`);
|
|
40145
|
+
const event = s(ctx.event);
|
|
40146
|
+
if (event) segs.push(`event=${event}`);
|
|
40147
|
+
return segs.join(" ");
|
|
40148
|
+
}
|
|
40149
|
+
function traceMeshEventStage(stage, ctx, detail) {
|
|
40150
|
+
LOG2.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
40151
|
+
}
|
|
40152
|
+
function traceMeshEventDrop(reason, ctx, detail) {
|
|
40153
|
+
LOG2.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
40154
|
+
}
|
|
40155
|
+
var CAT;
|
|
40156
|
+
var init_mesh_event_trace = __esm2({
|
|
40157
|
+
"src/mesh/mesh-event-trace.ts"() {
|
|
40158
|
+
"use strict";
|
|
40159
|
+
init_logger();
|
|
40160
|
+
CAT = "EvtTrace";
|
|
40161
|
+
}
|
|
40162
|
+
});
|
|
40089
40163
|
function isPlainObject22(value) {
|
|
40090
40164
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
40091
40165
|
}
|
|
@@ -41879,9 +41953,9 @@ ${cleanBody}`;
|
|
|
41879
41953
|
}
|
|
41880
41954
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
41881
41955
|
const sessions = [];
|
|
41882
|
-
const ideStates = allStates.filter((
|
|
41883
|
-
const cliStates = allStates.filter((
|
|
41884
|
-
const acpStates = allStates.filter((
|
|
41956
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
41957
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
41958
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
41885
41959
|
for (const state of ideStates) {
|
|
41886
41960
|
sessions.push(buildWorkspaceSession(state, cdpManagers, options));
|
|
41887
41961
|
for (const ext of state.extensions) {
|
|
@@ -42365,6 +42439,15 @@ ${cleanBody}`;
|
|
|
42365
42439
|
meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
|
|
42366
42440
|
return mesh;
|
|
42367
42441
|
}
|
|
42442
|
+
function recoverMeshIdByNodeId(nodeId) {
|
|
42443
|
+
if (!nodeId) return "";
|
|
42444
|
+
for (const mesh of listMeshes()) {
|
|
42445
|
+
if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
|
|
42446
|
+
return readNonEmptyString2(mesh.id);
|
|
42447
|
+
}
|
|
42448
|
+
}
|
|
42449
|
+
return "";
|
|
42450
|
+
}
|
|
42368
42451
|
function __resetIdleAutoFastForwardForTests() {
|
|
42369
42452
|
idleAutoFastForwardLastAttempt.clear();
|
|
42370
42453
|
}
|
|
@@ -43267,6 +43350,13 @@ ${cleanBody}`;
|
|
|
43267
43350
|
function injectMeshSystemMessage(components, args) {
|
|
43268
43351
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
43269
43352
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
43353
|
+
const traceCtx = {
|
|
43354
|
+
taskId: args.metadataEvent.taskId,
|
|
43355
|
+
sessionId: eventSessionId,
|
|
43356
|
+
nodeId: eventNodeId,
|
|
43357
|
+
meshId: args.meshId,
|
|
43358
|
+
event: args.event
|
|
43359
|
+
};
|
|
43270
43360
|
const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
|
|
43271
43361
|
const workerCoordinatorDaemonId = readNonEmptyString2(
|
|
43272
43362
|
sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
|
|
@@ -43320,6 +43410,7 @@ ${cleanBody}`;
|
|
|
43320
43410
|
}
|
|
43321
43411
|
}
|
|
43322
43412
|
LOG2.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
43413
|
+
traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
|
|
43323
43414
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
43324
43415
|
}
|
|
43325
43416
|
if (args.event === "monitor:no_progress") {
|
|
@@ -43340,6 +43431,7 @@ ${cleanBody}`;
|
|
|
43340
43431
|
}
|
|
43341
43432
|
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
43342
43433
|
LOG2.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
43434
|
+
traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
|
|
43343
43435
|
return {
|
|
43344
43436
|
success: true,
|
|
43345
43437
|
forwarded: 0,
|
|
@@ -43351,6 +43443,7 @@ ${cleanBody}`;
|
|
|
43351
43443
|
}
|
|
43352
43444
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
43353
43445
|
LOG2.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
43446
|
+
traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
|
|
43354
43447
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
43355
43448
|
}
|
|
43356
43449
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
@@ -43365,6 +43458,7 @@ ${cleanBody}`;
|
|
|
43365
43458
|
});
|
|
43366
43459
|
if (duplicateApproval) {
|
|
43367
43460
|
LOG2.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
43461
|
+
traceMeshEventDrop("duplicate_approval", traceCtx);
|
|
43368
43462
|
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
43369
43463
|
}
|
|
43370
43464
|
}
|
|
@@ -43384,6 +43478,7 @@ ${cleanBody}`;
|
|
|
43384
43478
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
43385
43479
|
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
43386
43480
|
LOG2.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
43481
|
+
traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
|
|
43387
43482
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
43388
43483
|
}
|
|
43389
43484
|
}
|
|
@@ -43402,6 +43497,7 @@ ${cleanBody}`;
|
|
|
43402
43497
|
});
|
|
43403
43498
|
if (duplicateCompletion) {
|
|
43404
43499
|
LOG2.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
43500
|
+
traceMeshEventDrop("duplicate_completion", traceCtx);
|
|
43405
43501
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
43406
43502
|
}
|
|
43407
43503
|
}
|
|
@@ -43420,6 +43516,7 @@ ${cleanBody}`;
|
|
|
43420
43516
|
});
|
|
43421
43517
|
if (duplicateStopped) {
|
|
43422
43518
|
LOG2.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
43519
|
+
traceMeshEventDrop("duplicate_stopped", traceCtx);
|
|
43423
43520
|
return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
|
|
43424
43521
|
}
|
|
43425
43522
|
}
|
|
@@ -43431,7 +43528,7 @@ ${cleanBody}`;
|
|
|
43431
43528
|
});
|
|
43432
43529
|
const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
|
|
43433
43530
|
if (!leaveDirectDispatchActive) {
|
|
43434
|
-
updateDirectDispatchStatus(args.meshId, sessionId, outcome);
|
|
43531
|
+
updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
|
|
43435
43532
|
}
|
|
43436
43533
|
markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
|
|
43437
43534
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
@@ -43444,7 +43541,7 @@ ${cleanBody}`;
|
|
|
43444
43541
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
43445
43542
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
43446
43543
|
if (sessionId) {
|
|
43447
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
43544
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
43448
43545
|
const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
|
|
43449
43546
|
completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
|
|
43450
43547
|
if (nodeId && providerType) {
|
|
@@ -43527,7 +43624,8 @@ ${cleanBody}`;
|
|
|
43527
43624
|
}
|
|
43528
43625
|
}
|
|
43529
43626
|
if (sessionId) {
|
|
43530
|
-
|
|
43627
|
+
const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
|
|
43628
|
+
updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
|
|
43531
43629
|
const activeDeliveries = (() => {
|
|
43532
43630
|
try {
|
|
43533
43631
|
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
|
|
@@ -43535,7 +43633,8 @@ ${cleanBody}`;
|
|
|
43535
43633
|
return [];
|
|
43536
43634
|
}
|
|
43537
43635
|
})();
|
|
43538
|
-
|
|
43636
|
+
const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
|
|
43637
|
+
for (const d of deliveriesToAck) {
|
|
43539
43638
|
updateSessionDeliveryStatus(d.id, "acked");
|
|
43540
43639
|
}
|
|
43541
43640
|
}
|
|
@@ -43549,7 +43648,7 @@ ${cleanBody}`;
|
|
|
43549
43648
|
}
|
|
43550
43649
|
}
|
|
43551
43650
|
if (sessionId) {
|
|
43552
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
43651
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
43553
43652
|
completedTaskForLedger = markSessionTerminal(sessionId, "failed");
|
|
43554
43653
|
}
|
|
43555
43654
|
}
|
|
@@ -43695,6 +43794,9 @@ ${cleanBody}`;
|
|
|
43695
43794
|
};
|
|
43696
43795
|
if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
|
|
43697
43796
|
LOG2.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
|
|
43797
|
+
traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
|
|
43798
|
+
} else {
|
|
43799
|
+
traceMeshEventDrop("queue_dedup", traceCtx);
|
|
43698
43800
|
}
|
|
43699
43801
|
return { success: true, forwarded: 0 };
|
|
43700
43802
|
}
|
|
@@ -43705,8 +43807,23 @@ ${cleanBody}`;
|
|
|
43705
43807
|
}
|
|
43706
43808
|
const nodeId = readNonEmptyString2(payload.nodeId);
|
|
43707
43809
|
const workspace = readNonEmptyString2(payload.workspace);
|
|
43708
|
-
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
|
|
43709
|
-
if (!meshId)
|
|
43810
|
+
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
|
|
43811
|
+
if (!meshId) {
|
|
43812
|
+
traceMeshEventDrop("meshId_required", {
|
|
43813
|
+
taskId: payload.taskId,
|
|
43814
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
43815
|
+
nodeId,
|
|
43816
|
+
event: eventName
|
|
43817
|
+
}, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
|
|
43818
|
+
return { success: false, error: "meshId required" };
|
|
43819
|
+
}
|
|
43820
|
+
traceMeshEventStage("received", {
|
|
43821
|
+
taskId: payload.taskId,
|
|
43822
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
43823
|
+
nodeId,
|
|
43824
|
+
meshId,
|
|
43825
|
+
event: eventName
|
|
43826
|
+
});
|
|
43710
43827
|
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
43711
43828
|
const relayModalMessage = readNonEmptyString2(payload.modalMessage);
|
|
43712
43829
|
const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
|
|
@@ -43787,9 +43904,18 @@ ${cleanBody}`;
|
|
|
43787
43904
|
workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
|
|
43788
43905
|
};
|
|
43789
43906
|
const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
|
|
43907
|
+
const fwdTraceCtx = {
|
|
43908
|
+
taskId: payload.taskId,
|
|
43909
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
43910
|
+
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
|
|
43911
|
+
event: eventName
|
|
43912
|
+
};
|
|
43913
|
+
traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
|
|
43914
|
+
traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
|
|
43790
43915
|
Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
|
|
43791
43916
|
if (result && result.success === false) {
|
|
43792
43917
|
LOG2.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
|
|
43918
|
+
traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
43793
43919
|
return;
|
|
43794
43920
|
}
|
|
43795
43921
|
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
@@ -43857,6 +43983,14 @@ ${cleanBody}`;
|
|
|
43857
43983
|
if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
|
|
43858
43984
|
return;
|
|
43859
43985
|
}
|
|
43986
|
+
if (isUnroutableDelegateRejection(routing)) {
|
|
43987
|
+
traceMeshEventDrop("unroutable", {
|
|
43988
|
+
taskId: event.meshActiveTaskId ?? event.taskId,
|
|
43989
|
+
sessionId: routing.sessionId,
|
|
43990
|
+
nodeId: routing.nodeId,
|
|
43991
|
+
event: event.event
|
|
43992
|
+
}, "no coordinator anchor / mesh_unresolved");
|
|
43993
|
+
}
|
|
43860
43994
|
recordUnroutableDelegateEvent(routing, event.event);
|
|
43861
43995
|
return;
|
|
43862
43996
|
}
|
|
@@ -43904,6 +44038,7 @@ ${cleanBody}`;
|
|
|
43904
44038
|
init_mesh_events_pending();
|
|
43905
44039
|
init_mesh_routing();
|
|
43906
44040
|
init_mesh_unresolved_forward_outbox();
|
|
44041
|
+
init_mesh_event_trace();
|
|
43907
44042
|
init_snapshot();
|
|
43908
44043
|
init_repo_mesh_types();
|
|
43909
44044
|
init_dist();
|
|
@@ -44013,6 +44148,13 @@ ${cleanBody}`;
|
|
|
44013
44148
|
function injectPendingIntoCoordinator(coordinator, pending) {
|
|
44014
44149
|
if (!coordinator || !pending.coordinatorMessage) return;
|
|
44015
44150
|
const force = shouldForceInjectMeshEvent(pending.event);
|
|
44151
|
+
traceMeshEventStage("surfaced", {
|
|
44152
|
+
taskId: pending.metadataEvent?.taskId,
|
|
44153
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
|
|
44154
|
+
nodeId: pending.nodeId,
|
|
44155
|
+
meshId: pending.meshId,
|
|
44156
|
+
event: pending.event
|
|
44157
|
+
}, force ? "force-inject" : "inject");
|
|
44016
44158
|
coordinator.onEvent("send_message", {
|
|
44017
44159
|
input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
|
|
44018
44160
|
...force ? { force: true } : {}
|
|
@@ -44071,6 +44213,13 @@ ${cleanBody}`;
|
|
|
44071
44213
|
});
|
|
44072
44214
|
if (reclaimed) {
|
|
44073
44215
|
LOG2.warn("MeshReconcile", `Reclaimed stranded assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, dispatched ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s ago, never confirmed delivered \u2192 ${reclaimed.status})`);
|
|
44216
|
+
traceMeshEventDrop("assigned_stranded_reclaim", {
|
|
44217
|
+
taskId: row.id,
|
|
44218
|
+
sessionId: row.assignedSessionId,
|
|
44219
|
+
nodeId: row.assignedNodeId,
|
|
44220
|
+
meshId,
|
|
44221
|
+
event: "agent:generating_completed"
|
|
44222
|
+
}, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
|
|
44074
44223
|
}
|
|
44075
44224
|
}
|
|
44076
44225
|
}
|
|
@@ -44230,6 +44379,13 @@ ${cleanBody}`;
|
|
|
44230
44379
|
try {
|
|
44231
44380
|
queuePendingMeshCoordinatorEvent(pending);
|
|
44232
44381
|
LOG2.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
|
|
44382
|
+
traceMeshEventDrop("strict_route_hold", {
|
|
44383
|
+
taskId: pending.metadataEvent?.taskId,
|
|
44384
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
44385
|
+
nodeId: pending.nodeId,
|
|
44386
|
+
meshId,
|
|
44387
|
+
event: pending.event
|
|
44388
|
+
}, `coordinatorSession=${wantSession} not live`);
|
|
44233
44389
|
} catch (e) {
|
|
44234
44390
|
LOG2.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
|
|
44235
44391
|
}
|
|
@@ -44253,6 +44409,13 @@ ${cleanBody}`;
|
|
|
44253
44409
|
}
|
|
44254
44410
|
});
|
|
44255
44411
|
LOG2.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
|
|
44412
|
+
traceMeshEventDrop("strict_route_expired", {
|
|
44413
|
+
taskId: pending.metadataEvent?.taskId,
|
|
44414
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
44415
|
+
nodeId: pending.nodeId,
|
|
44416
|
+
meshId,
|
|
44417
|
+
event: pending.event
|
|
44418
|
+
}, `coordinatorSession=${wantSession} never returned`);
|
|
44256
44419
|
} catch (e) {
|
|
44257
44420
|
LOG2.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
44258
44421
|
}
|
|
@@ -44264,15 +44427,24 @@ ${cleanBody}`;
|
|
|
44264
44427
|
const entries = peekUnresolvedDelegateForwards();
|
|
44265
44428
|
if (entries.length === 0) return;
|
|
44266
44429
|
for (const entry of entries) {
|
|
44430
|
+
const entryTraceCtx = {
|
|
44431
|
+
taskId: entry.payload.taskId,
|
|
44432
|
+
sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
|
|
44433
|
+
nodeId: readNonEmptyString2(entry.payload.nodeId),
|
|
44434
|
+
event: readNonEmptyString2(entry.payload.event)
|
|
44435
|
+
};
|
|
44267
44436
|
let result;
|
|
44268
44437
|
try {
|
|
44438
|
+
traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
|
|
44269
44439
|
result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
|
|
44270
44440
|
} catch (e) {
|
|
44271
44441
|
LOG2.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
|
|
44442
|
+
traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
|
|
44272
44443
|
continue;
|
|
44273
44444
|
}
|
|
44274
44445
|
if (result && result.success === false) {
|
|
44275
44446
|
LOG2.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
|
|
44447
|
+
traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
44276
44448
|
continue;
|
|
44277
44449
|
}
|
|
44278
44450
|
ackUnresolvedDelegateForward(entry.id);
|
|
@@ -44518,6 +44690,7 @@ ${cleanBody}`;
|
|
|
44518
44690
|
init_mesh_events_coordinator();
|
|
44519
44691
|
init_mesh_unresolved_forward_outbox();
|
|
44520
44692
|
init_mesh_events_utils();
|
|
44693
|
+
init_mesh_event_trace();
|
|
44521
44694
|
init_dist();
|
|
44522
44695
|
init_mesh_work_queue();
|
|
44523
44696
|
init_mesh_ledger();
|
|
@@ -45347,8 +45520,8 @@ ${cleanBody}`;
|
|
|
45347
45520
|
}
|
|
45348
45521
|
function isValidSource(x) {
|
|
45349
45522
|
if (!x || typeof x !== "object") return false;
|
|
45350
|
-
const
|
|
45351
|
-
return typeof
|
|
45523
|
+
const s2 = x;
|
|
45524
|
+
return typeof s2.name === "string" && s2.name.length > 0 && typeof s2.url === "string" && s2.url.length > 0 && typeof s2.ref === "string" && s2.ref.length > 0 && typeof s2.addedAt === "string";
|
|
45352
45525
|
}
|
|
45353
45526
|
function deriveSourceName(url2) {
|
|
45354
45527
|
const m = url2.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -45404,7 +45577,7 @@ ${cleanBody}`;
|
|
|
45404
45577
|
}
|
|
45405
45578
|
function sourcesProviding(category, type) {
|
|
45406
45579
|
const inventory = inventoryExternalSources();
|
|
45407
|
-
return inventory.filter((
|
|
45580
|
+
return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
|
|
45408
45581
|
}
|
|
45409
45582
|
function resolveActiveSource(category, type, activeFile) {
|
|
45410
45583
|
const candidates = sourcesProviding(category, type);
|
|
@@ -45612,10 +45785,10 @@ ${cleanBody}`;
|
|
|
45612
45785
|
const footers = (spec.withFooter ?? []).map((f) => {
|
|
45613
45786
|
if (f.kind === "regex") {
|
|
45614
45787
|
const re = compile2(f.pattern, f.flags ?? "i");
|
|
45615
|
-
return { test: (
|
|
45788
|
+
return { test: (s2) => re.test(s2) };
|
|
45616
45789
|
}
|
|
45617
45790
|
const needle = f.pattern.toLowerCase();
|
|
45618
|
-
return { test: (
|
|
45791
|
+
return { test: (s2) => s2.toLowerCase().includes(needle) };
|
|
45619
45792
|
});
|
|
45620
45793
|
return { prompt, footers };
|
|
45621
45794
|
}
|
|
@@ -46490,7 +46663,7 @@ ${cont}` : cont;
|
|
|
46490
46663
|
}
|
|
46491
46664
|
resolveModal(buttonIndex) {
|
|
46492
46665
|
const snap = this.transport.getSnapshot();
|
|
46493
|
-
const parseApproval = typeof this.transport.runParseApproval === "function" ? (
|
|
46666
|
+
const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
|
|
46494
46667
|
let modal = this.activeModal ?? parseApproval(snap);
|
|
46495
46668
|
if (!modal && this.runner.hasParseSession()) {
|
|
46496
46669
|
try {
|
|
@@ -49176,22 +49349,23 @@ ${lastSnapshot}`;
|
|
|
49176
49349
|
const matchesCandidate = (c, i) => c.re.test(lines[i]) && (c.prevRe === null || i > 0 && c.prevRe.test(lines[i - 1])) && (c.nextRe === null || i < total - 1 && c.nextRe.test(lines[i + 1]));
|
|
49177
49350
|
let idx = -1;
|
|
49178
49351
|
for (const c of candidates) {
|
|
49352
|
+
let candIdx = -1;
|
|
49179
49353
|
if (sec.anchor_last) {
|
|
49180
49354
|
for (let i = total - 1; i >= 0; i--) {
|
|
49181
49355
|
if (matchesCandidate(c, i)) {
|
|
49182
|
-
|
|
49356
|
+
candIdx = i;
|
|
49183
49357
|
break;
|
|
49184
49358
|
}
|
|
49185
49359
|
}
|
|
49186
49360
|
} else {
|
|
49187
49361
|
for (let i = 0; i < total; i++) {
|
|
49188
49362
|
if (matchesCandidate(c, i)) {
|
|
49189
|
-
|
|
49363
|
+
candIdx = i;
|
|
49190
49364
|
break;
|
|
49191
49365
|
}
|
|
49192
49366
|
}
|
|
49193
49367
|
}
|
|
49194
|
-
if (
|
|
49368
|
+
if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
|
|
49195
49369
|
}
|
|
49196
49370
|
if (idx !== -1) {
|
|
49197
49371
|
from = idx;
|
|
@@ -49243,7 +49417,7 @@ ${lastSnapshot}`;
|
|
|
49243
49417
|
}
|
|
49244
49418
|
function sectionText(sections, sectionId, fullScreen) {
|
|
49245
49419
|
if (!sectionId) return fullScreen;
|
|
49246
|
-
const found = sections.find((
|
|
49420
|
+
const found = sections.find((s2) => s2.id === sectionId);
|
|
49247
49421
|
return found ? found.text : "";
|
|
49248
49422
|
}
|
|
49249
49423
|
function isRegexCondition(c) {
|
|
@@ -49409,10 +49583,10 @@ ${lastSnapshot}`;
|
|
|
49409
49583
|
return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
|
|
49410
49584
|
}
|
|
49411
49585
|
function initialState(spec) {
|
|
49412
|
-
return spec.states.find((
|
|
49586
|
+
return spec.states.find((s2) => s2.initial) ?? spec.states[0];
|
|
49413
49587
|
}
|
|
49414
49588
|
function stateById(spec, id) {
|
|
49415
|
-
return spec.states.find((
|
|
49589
|
+
return spec.states.find((s2) => s2.id === id);
|
|
49416
49590
|
}
|
|
49417
49591
|
function outgoingTransitions(spec, stateId) {
|
|
49418
49592
|
const matches = spec.transitions.filter((t) => {
|
|
@@ -49499,7 +49673,17 @@ ${lastSnapshot}`;
|
|
|
49499
49673
|
const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
|
|
49500
49674
|
const kind = isRegex(cond) ? "regex" : "changed";
|
|
49501
49675
|
const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
|
|
49502
|
-
|
|
49676
|
+
let matchedText;
|
|
49677
|
+
if (result && isRegex(cond)) {
|
|
49678
|
+
try {
|
|
49679
|
+
const hay = sectionText(sections, cond.section, fullScreen);
|
|
49680
|
+
const re = new RegExp(cond.matches, cond.flags ?? "i");
|
|
49681
|
+
const m = re.exec(hay);
|
|
49682
|
+
if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
|
|
49683
|
+
} catch {
|
|
49684
|
+
}
|
|
49685
|
+
}
|
|
49686
|
+
return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
|
|
49503
49687
|
}
|
|
49504
49688
|
return { kind: "all", result: false, detail: "unknown condition" };
|
|
49505
49689
|
}
|
|
@@ -49612,17 +49796,17 @@ ${lastSnapshot}`;
|
|
|
49612
49796
|
}
|
|
49613
49797
|
const ids = /* @__PURE__ */ new Set();
|
|
49614
49798
|
let initialCount = 0;
|
|
49615
|
-
for (const [i,
|
|
49616
|
-
if (!
|
|
49799
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
49800
|
+
if (!s2.id) {
|
|
49617
49801
|
errs.push(`states[${i}].id is required`);
|
|
49618
49802
|
continue;
|
|
49619
49803
|
}
|
|
49620
|
-
if (ids.has(
|
|
49621
|
-
ids.add(
|
|
49622
|
-
if (!
|
|
49623
|
-
if (
|
|
49624
|
-
if (
|
|
49625
|
-
errs.push(`states[${i}].status "${
|
|
49804
|
+
if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
|
|
49805
|
+
ids.add(s2.id);
|
|
49806
|
+
if (!s2.label) errs.push(`states[${i}].label is required`);
|
|
49807
|
+
if (s2.initial) initialCount += 1;
|
|
49808
|
+
if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
|
|
49809
|
+
errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
|
|
49626
49810
|
}
|
|
49627
49811
|
}
|
|
49628
49812
|
if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
|
|
@@ -49638,10 +49822,10 @@ ${lastSnapshot}`;
|
|
|
49638
49822
|
else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
|
|
49639
49823
|
if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
|
|
49640
49824
|
}
|
|
49641
|
-
for (const [i,
|
|
49642
|
-
const sec =
|
|
49825
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
49826
|
+
const sec = s2.extract?.title?.section;
|
|
49643
49827
|
if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
|
|
49644
|
-
const bsec =
|
|
49828
|
+
const bsec = s2.extract?.buttons?.section;
|
|
49645
49829
|
if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
|
|
49646
49830
|
}
|
|
49647
49831
|
return errs;
|
|
@@ -57154,6 +57338,40 @@ ${effect.notification.body || ""}`.trim();
|
|
|
57154
57338
|
}
|
|
57155
57339
|
return fn() || null;
|
|
57156
57340
|
}
|
|
57341
|
+
var AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS = 6e4;
|
|
57342
|
+
var ManualAttendanceTracker = class {
|
|
57343
|
+
constructor(suppressMs = AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS) {
|
|
57344
|
+
this.suppressMs = suppressMs;
|
|
57345
|
+
}
|
|
57346
|
+
lastInteractionAt = 0;
|
|
57347
|
+
/** Record that a human just drove this session by hand. */
|
|
57348
|
+
note(now = Date.now()) {
|
|
57349
|
+
this.lastInteractionAt = now;
|
|
57350
|
+
}
|
|
57351
|
+
/** True while a manual interaction is recent enough to suppress auto-approve. */
|
|
57352
|
+
isAttended(now = Date.now()) {
|
|
57353
|
+
return this.lastInteractionAt > 0 && now - this.lastInteractionAt < this.suppressMs;
|
|
57354
|
+
}
|
|
57355
|
+
/**
|
|
57356
|
+
* Milliseconds remaining in the current suppression window, or 0 when not
|
|
57357
|
+
* attended. Used to re-arm a re-check timer so auto-approve fires the moment
|
|
57358
|
+
* the window lapses even if the PTY/agent has since gone silent.
|
|
57359
|
+
*/
|
|
57360
|
+
remainingMs(now = Date.now()) {
|
|
57361
|
+
if (this.lastInteractionAt <= 0) return 0;
|
|
57362
|
+
return Math.max(0, this.suppressMs - (now - this.lastInteractionAt));
|
|
57363
|
+
}
|
|
57364
|
+
};
|
|
57365
|
+
var MANUAL_ATTENDANCE_COMMANDS = /* @__PURE__ */ new Set([
|
|
57366
|
+
"select_session",
|
|
57367
|
+
"open_panel",
|
|
57368
|
+
"invoke_provider_script",
|
|
57369
|
+
"set_mode",
|
|
57370
|
+
"change_model",
|
|
57371
|
+
"set_thought_level",
|
|
57372
|
+
"resolve_action",
|
|
57373
|
+
"pty_input"
|
|
57374
|
+
]);
|
|
57157
57375
|
var fs7 = __toESM2(require("fs"));
|
|
57158
57376
|
var os10 = __toESM2(require("os"));
|
|
57159
57377
|
var path16 = __toESM2(require("path"));
|
|
@@ -61468,11 +61686,38 @@ ${effect.notification.body || ""}`.trim();
|
|
|
61468
61686
|
setAgentStreamManager(manager) {
|
|
61469
61687
|
this._agentStream = manager;
|
|
61470
61688
|
}
|
|
61689
|
+
/**
|
|
61690
|
+
* When a command in the manual-attendance set arrives for a session this
|
|
61691
|
+
* daemon hosts, stamp the live instance so auto-approve holds while the user
|
|
61692
|
+
* drives the session by hand. Provider-common: the signal is the command
|
|
61693
|
+
* (foreground select_session / open_panel, controlbar invoke_provider_script
|
|
61694
|
+
* / set_mode / change_model / set_thought_level, manual resolve_action,
|
|
61695
|
+
* pty_input), never any CLI-specific modal text — so it works identically for
|
|
61696
|
+
* every CLI/ACP provider. send_chat is deliberately excluded because a
|
|
61697
|
+
* coordinator delegating a task to a worker also uses send_chat; counting it
|
|
61698
|
+
* would wrongly suppress the worker's delegated auto-approve. For a remote
|
|
61699
|
+
* mesh worker session the controlbar commands are forwarded to the owning
|
|
61700
|
+
* worker daemon, which runs this same hook there, so attendance is recorded
|
|
61701
|
+
* on the daemon that actually hosts the instance.
|
|
61702
|
+
*/
|
|
61703
|
+
noteManualAttendanceIfApplicable(cmd, args) {
|
|
61704
|
+
if (!MANUAL_ATTENDANCE_COMMANDS.has(cmd)) return;
|
|
61705
|
+
const sessionId = this._currentRoute.session?.sessionId || (typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "");
|
|
61706
|
+
if (!sessionId) return;
|
|
61707
|
+
const session = this._ctx.sessionRegistry?.get(sessionId);
|
|
61708
|
+
const instanceKey = session?.adapterKey || session?.instanceKey || sessionId;
|
|
61709
|
+
const instance = this._ctx.instanceManager?.getInstance(instanceKey);
|
|
61710
|
+
try {
|
|
61711
|
+
instance?.noteManualInteraction?.();
|
|
61712
|
+
} catch {
|
|
61713
|
+
}
|
|
61714
|
+
}
|
|
61471
61715
|
// ─── Command Dispatcher ──────────────────────────
|
|
61472
61716
|
async handle(cmd, args) {
|
|
61473
61717
|
this._currentRoute = this.resolveRoute(args);
|
|
61474
61718
|
const startedAt = Date.now();
|
|
61475
61719
|
this.logCommandStart(cmd, args);
|
|
61720
|
+
this.noteManualAttendanceIfApplicable(cmd, args);
|
|
61476
61721
|
let result;
|
|
61477
61722
|
if (isGitCommandName(cmd)) {
|
|
61478
61723
|
result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
|
|
@@ -62207,10 +62452,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62207
62452
|
const path422 = require("path");
|
|
62208
62453
|
const { spawnSync: spawnSync2 } = require("child_process");
|
|
62209
62454
|
const file2 = ext.loadExternalSources();
|
|
62210
|
-
if (file2.sources.some((
|
|
62455
|
+
if (file2.sources.some((s2) => s2.name === requestedName)) {
|
|
62211
62456
|
return { success: false, error: `source name "${requestedName}" is already registered` };
|
|
62212
62457
|
}
|
|
62213
|
-
if (file2.sources.some((
|
|
62458
|
+
if (file2.sources.some((s2) => s2.url === url2 && s2.ref === ref)) {
|
|
62214
62459
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
62215
62460
|
}
|
|
62216
62461
|
const sourceDir = path422.join(ext.externalRoot(), requestedName);
|
|
@@ -62272,7 +62517,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62272
62517
|
const fs322 = require("fs");
|
|
62273
62518
|
const path422 = require("path");
|
|
62274
62519
|
const file2 = ext.loadExternalSources();
|
|
62275
|
-
const match = file2.sources.find((
|
|
62520
|
+
const match = file2.sources.find((s2) => s2.name === name);
|
|
62276
62521
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
62277
62522
|
const sourceDir = path422.join(ext.externalRoot(), name);
|
|
62278
62523
|
if (fs322.existsSync(sourceDir)) {
|
|
@@ -62284,7 +62529,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62284
62529
|
}
|
|
62285
62530
|
ext.saveExternalSources({
|
|
62286
62531
|
schema: 1,
|
|
62287
|
-
sources: file2.sources.filter((
|
|
62532
|
+
sources: file2.sources.filter((s2) => s2.name !== name)
|
|
62288
62533
|
});
|
|
62289
62534
|
const active = ext.loadProvidersActive();
|
|
62290
62535
|
const filteredActive = {};
|
|
@@ -62308,10 +62553,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62308
62553
|
const file2 = ext.loadExternalSources();
|
|
62309
62554
|
const inventory = ext.inventoryExternalSources();
|
|
62310
62555
|
const active = ext.loadProvidersActive();
|
|
62311
|
-
const sources = file2.sources.map((
|
|
62312
|
-
const inv = inventory.find((e) => e.sourceName ===
|
|
62556
|
+
const sources = file2.sources.map((s2) => {
|
|
62557
|
+
const inv = inventory.find((e) => e.sourceName === s2.name);
|
|
62313
62558
|
return {
|
|
62314
|
-
...
|
|
62559
|
+
...s2,
|
|
62315
62560
|
providers: inv?.providers ?? {}
|
|
62316
62561
|
};
|
|
62317
62562
|
});
|
|
@@ -62478,6 +62723,21 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62478
62723
|
var path21 = __toESM2(require("path"));
|
|
62479
62724
|
init_terminal_screen();
|
|
62480
62725
|
var import_session_host_core6 = require_dist();
|
|
62726
|
+
var MAX_PTY_EVENTS = 300;
|
|
62727
|
+
var EVENT_CONTENT_CAP = 240;
|
|
62728
|
+
function escapeControl(text) {
|
|
62729
|
+
return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
|
|
62730
|
+
const code = ch.charCodeAt(0);
|
|
62731
|
+
if (ch === "\r") return "\\r";
|
|
62732
|
+
if (ch === "\n") return "\\n";
|
|
62733
|
+
if (ch === " ") return "\\t";
|
|
62734
|
+
if (code === 27) return "\\x1b";
|
|
62735
|
+
return "\\x" + code.toString(16).padStart(2, "0");
|
|
62736
|
+
});
|
|
62737
|
+
}
|
|
62738
|
+
function capPreview(text) {
|
|
62739
|
+
return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
|
|
62740
|
+
}
|
|
62481
62741
|
var TerminalAdapter = class {
|
|
62482
62742
|
constructor(opts, handlers) {
|
|
62483
62743
|
this.opts = opts;
|
|
@@ -62504,6 +62764,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62504
62764
|
screenTimer = null;
|
|
62505
62765
|
tickTimer = null;
|
|
62506
62766
|
lastScreen = "";
|
|
62767
|
+
/** Debug-only ring buffer of PTY input/output/resize/cursor events. */
|
|
62768
|
+
events = [];
|
|
62769
|
+
lastCursorKey = "";
|
|
62507
62770
|
start() {
|
|
62508
62771
|
const env2 = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
|
|
62509
62772
|
this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
|
|
@@ -62512,10 +62775,12 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62512
62775
|
cols: this.cols,
|
|
62513
62776
|
rows: this.rows
|
|
62514
62777
|
});
|
|
62778
|
+
this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
|
|
62515
62779
|
this.handlers.init?.({ pid: this.pty.pid });
|
|
62516
62780
|
this.pty.onData((chunk) => this.onChunk(chunk));
|
|
62517
62781
|
this.pty.onExit((info) => {
|
|
62518
62782
|
this.stopTimers();
|
|
62783
|
+
this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
|
|
62519
62784
|
this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
|
|
62520
62785
|
this.pty = null;
|
|
62521
62786
|
});
|
|
@@ -62526,6 +62791,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62526
62791
|
resize(cols, rows) {
|
|
62527
62792
|
this.cols = cols;
|
|
62528
62793
|
this.rows = rows;
|
|
62794
|
+
this.recordEvent("resize", `${cols}x${rows}`);
|
|
62529
62795
|
this.pty?.resize(cols, rows);
|
|
62530
62796
|
this.screen.resize(rows, cols);
|
|
62531
62797
|
}
|
|
@@ -62546,8 +62812,21 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62546
62812
|
return { row: pos.row, col: pos.col };
|
|
62547
62813
|
}
|
|
62548
62814
|
send_keys(text) {
|
|
62815
|
+
this.recordEvent("input", capPreview(escapeControl(text)), text.length);
|
|
62549
62816
|
this.pty?.write(text);
|
|
62550
62817
|
}
|
|
62818
|
+
/** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
|
|
62819
|
+
* first. Pure observation — never consulted by the FSM. */
|
|
62820
|
+
getEventTimeline(limit = MAX_PTY_EVENTS) {
|
|
62821
|
+
const n = Math.max(0, Math.min(limit, this.events.length));
|
|
62822
|
+
return this.events.slice(this.events.length - n);
|
|
62823
|
+
}
|
|
62824
|
+
recordEvent(kind, content, bytes) {
|
|
62825
|
+
const ev = { ts: Date.now(), kind, content };
|
|
62826
|
+
if (typeof bytes === "number") ev.bytes = bytes;
|
|
62827
|
+
this.events.push(ev);
|
|
62828
|
+
if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
|
|
62829
|
+
}
|
|
62551
62830
|
kill() {
|
|
62552
62831
|
this.stopTimers();
|
|
62553
62832
|
try {
|
|
@@ -62558,6 +62837,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62558
62837
|
this.screen.dispose();
|
|
62559
62838
|
}
|
|
62560
62839
|
onChunk(chunk) {
|
|
62840
|
+
this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
|
|
62561
62841
|
try {
|
|
62562
62842
|
this.handlers.on_pty_data?.(chunk);
|
|
62563
62843
|
} catch {
|
|
@@ -62567,6 +62847,12 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62567
62847
|
this.screenTimer = setTimeout(() => {
|
|
62568
62848
|
this.screenTimer = null;
|
|
62569
62849
|
const snap = this.computeScreen();
|
|
62850
|
+
const cur = this.screen.getCursorPosition();
|
|
62851
|
+
const curKey = `${cur.row},${cur.col}`;
|
|
62852
|
+
if (curKey !== this.lastCursorKey) {
|
|
62853
|
+
this.lastCursorKey = curKey;
|
|
62854
|
+
this.recordEvent("cursor", `(${cur.row},${cur.col})`);
|
|
62855
|
+
}
|
|
62570
62856
|
if (snap === this.lastScreen) return;
|
|
62571
62857
|
this.lastScreen = snap;
|
|
62572
62858
|
try {
|
|
@@ -62645,20 +62931,40 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62645
62931
|
}
|
|
62646
62932
|
}
|
|
62647
62933
|
init_logger();
|
|
62648
|
-
function countNewlines(
|
|
62934
|
+
function countNewlines(s2) {
|
|
62649
62935
|
let n = 0;
|
|
62650
|
-
for (let i = 0; i <
|
|
62936
|
+
for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
|
|
62651
62937
|
return n;
|
|
62652
62938
|
}
|
|
62653
62939
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
62654
62940
|
var WIN32_SUBMIT_RESEND_GAP_MS = 350;
|
|
62655
62941
|
var WIN32_SUBMIT_MAX_RESENDS = 14;
|
|
62942
|
+
var WIN32_SUBMIT_SETTLE_MS = 500;
|
|
62943
|
+
var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
|
|
62944
|
+
var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
|
|
62945
|
+
var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
|
|
62946
|
+
var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
|
|
62656
62947
|
function resolveSubmitDelayMs(specBeforeSubmit, text) {
|
|
62657
62948
|
const lines = countNewlines(text);
|
|
62658
62949
|
const linesBonus = Math.min(800, lines * 80);
|
|
62659
62950
|
const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
|
|
62660
62951
|
return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
|
|
62661
62952
|
}
|
|
62953
|
+
function chunkPreservingSurrogates(text, size) {
|
|
62954
|
+
const chunks = [];
|
|
62955
|
+
let offset = 0;
|
|
62956
|
+
while (offset < text.length) {
|
|
62957
|
+
let end = Math.min(text.length, offset + size);
|
|
62958
|
+
if (end < text.length) {
|
|
62959
|
+
const code = text.charCodeAt(end - 1);
|
|
62960
|
+
if (code >= 55296 && code <= 56319) end -= 1;
|
|
62961
|
+
}
|
|
62962
|
+
if (end <= offset) end = Math.min(text.length, offset + size);
|
|
62963
|
+
chunks.push(text.slice(offset, end));
|
|
62964
|
+
offset = end;
|
|
62965
|
+
}
|
|
62966
|
+
return chunks;
|
|
62967
|
+
}
|
|
62662
62968
|
function guessExt(mime) {
|
|
62663
62969
|
if (/png/i.test(mime)) return ".png";
|
|
62664
62970
|
if (/jpe?g/i.test(mime)) return ".jpg";
|
|
@@ -62674,7 +62980,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62674
62980
|
this.buildAdapterOpts(),
|
|
62675
62981
|
{
|
|
62676
62982
|
init: () => this.emitInitialState(),
|
|
62677
|
-
on_pty_data: (chunk) =>
|
|
62983
|
+
on_pty_data: (chunk) => {
|
|
62984
|
+
this.lastPtyDataAt = Date.now();
|
|
62985
|
+
this.emit({ kind: "pty_data", chunk });
|
|
62986
|
+
},
|
|
62678
62987
|
on_screen_changed: () => this.reevaluate(),
|
|
62679
62988
|
on_exit: ({ exitCode }) => this.handleExit(exitCode)
|
|
62680
62989
|
}
|
|
@@ -62708,6 +63017,16 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62708
63017
|
* WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
|
|
62709
63018
|
* leaves idle (submitted) or the resend budget is spent. */
|
|
62710
63019
|
win32SubmitTimer = null;
|
|
63020
|
+
/** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
|
|
63021
|
+
* on_pty_data — including the echo of text written into the composer — so the
|
|
63022
|
+
* win32 submit settle-gate can tell when input has finished landing. */
|
|
63023
|
+
lastPtyDataAt = 0;
|
|
63024
|
+
/** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
|
|
63025
|
+
* the gap between writing a chunk and its echo so the settle-gate does not
|
|
63026
|
+
* declare "quiet" mid-write. */
|
|
63027
|
+
lastWin32WriteAt = 0;
|
|
63028
|
+
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
63029
|
+
win32WriteTimer = null;
|
|
62711
63030
|
currentEval = null;
|
|
62712
63031
|
stateHistory = [];
|
|
62713
63032
|
prevStateAt = 0;
|
|
@@ -62828,6 +63147,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62828
63147
|
clearTimeout(this.win32SubmitTimer);
|
|
62829
63148
|
this.win32SubmitTimer = null;
|
|
62830
63149
|
}
|
|
63150
|
+
if (this.win32WriteTimer) {
|
|
63151
|
+
clearTimeout(this.win32WriteTimer);
|
|
63152
|
+
this.win32WriteTimer = null;
|
|
63153
|
+
}
|
|
62831
63154
|
this.specWatcher?.close();
|
|
62832
63155
|
this.adapter.kill();
|
|
62833
63156
|
}
|
|
@@ -62858,11 +63181,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
62858
63181
|
getFsmSnapshotHistory() {
|
|
62859
63182
|
return this.fsmSnapshotHistory;
|
|
62860
63183
|
}
|
|
63184
|
+
/** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
|
|
63185
|
+
getEventTimeline(limit) {
|
|
63186
|
+
return this.adapter.getEventTimeline(limit);
|
|
63187
|
+
}
|
|
62861
63188
|
getSections() {
|
|
62862
63189
|
try {
|
|
62863
63190
|
const screen = this.adapter.snapshot();
|
|
62864
63191
|
const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
62865
|
-
return resolveSections(this.spec.sections ?? {}, lines).map((
|
|
63192
|
+
return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
|
|
62866
63193
|
} catch {
|
|
62867
63194
|
return null;
|
|
62868
63195
|
}
|
|
@@ -63240,7 +63567,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
63240
63567
|
const perChar = sm.delay_ms_per_char ?? 0;
|
|
63241
63568
|
const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
|
|
63242
63569
|
if (process.platform === "win32") {
|
|
63243
|
-
this.
|
|
63570
|
+
this.writeWin32Body(text);
|
|
63244
63571
|
this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
|
|
63245
63572
|
return;
|
|
63246
63573
|
}
|
|
@@ -63266,20 +63593,72 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
63266
63593
|
const st = stateById(this.spec, this.currentStateId);
|
|
63267
63594
|
return st ? statusForState(st) : "idle";
|
|
63268
63595
|
}
|
|
63596
|
+
/** Record a win32 body write so the settle-gate counts it as input activity
|
|
63597
|
+
* even before the echo arrives. */
|
|
63598
|
+
markWin32Write() {
|
|
63599
|
+
this.lastWin32WriteAt = Date.now();
|
|
63600
|
+
}
|
|
63601
|
+
/** Most recent win32 input activity — a write we issued OR a PTY output chunk
|
|
63602
|
+
* (echo). The submit settle-gate waits for this to go quiet. */
|
|
63603
|
+
lastWin32InputActivityAt() {
|
|
63604
|
+
return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
|
|
63605
|
+
}
|
|
63269
63606
|
/**
|
|
63270
|
-
*
|
|
63271
|
-
*
|
|
63272
|
-
* a
|
|
63273
|
-
*
|
|
63274
|
-
*
|
|
63275
|
-
*
|
|
63276
|
-
|
|
63607
|
+
* Write the message body to the PTY for win32, paced into bounded chunks. A
|
|
63608
|
+
* single unbounded ConPTY write can overflow the input pipe and drop leading
|
|
63609
|
+
* bytes; splitting it with a short inter-chunk gap keeps the console input
|
|
63610
|
+
* buffer from overflowing. Small bodies still go out in a single write. Each
|
|
63611
|
+
* chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
|
|
63612
|
+
* the final chunk is out and echoed.
|
|
63613
|
+
*/
|
|
63614
|
+
writeWin32Body(text) {
|
|
63615
|
+
if (this.win32WriteTimer) {
|
|
63616
|
+
clearTimeout(this.win32WriteTimer);
|
|
63617
|
+
this.win32WriteTimer = null;
|
|
63618
|
+
}
|
|
63619
|
+
if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
|
|
63620
|
+
this.markWin32Write();
|
|
63621
|
+
this.adapter.send_keys(text);
|
|
63622
|
+
return;
|
|
63623
|
+
}
|
|
63624
|
+
const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
|
|
63625
|
+
let idx = 0;
|
|
63626
|
+
const writeNext = () => {
|
|
63627
|
+
this.win32WriteTimer = null;
|
|
63628
|
+
if (idx >= chunks.length) return;
|
|
63629
|
+
this.markWin32Write();
|
|
63630
|
+
this.adapter.send_keys(chunks[idx]);
|
|
63631
|
+
idx += 1;
|
|
63632
|
+
if (idx < chunks.length) {
|
|
63633
|
+
this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
|
|
63634
|
+
}
|
|
63635
|
+
};
|
|
63636
|
+
writeNext();
|
|
63637
|
+
}
|
|
63638
|
+
/**
|
|
63639
|
+
* win32 submit. Two phases:
|
|
63640
|
+
*
|
|
63641
|
+
* Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
|
|
63642
|
+
* for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
|
|
63643
|
+
* (possibly multi-KB / multiline) body has finished arriving in the composer
|
|
63644
|
+
* and echoing. Honors an initial minimum delay and is bounded by
|
|
63645
|
+
* WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
|
|
63646
|
+
* This is what stops a long message from being submitted half-arrived (its
|
|
63647
|
+
* leading lines lost). A short message settles almost immediately.
|
|
63648
|
+
*
|
|
63649
|
+
* Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
|
|
63650
|
+
* if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
|
|
63651
|
+
* newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
|
|
63652
|
+
* (a stale/edge status never suppresses it); resends are gated on still being
|
|
63653
|
+
* idle and stop the instant the agent leaves idle (submitted → generating /
|
|
63654
|
+
* approval). This preserves the win32 lone-CR-swallow handling.
|
|
63277
63655
|
*/
|
|
63278
63656
|
scheduleWin32Submit(submitKey, initialDelayMs) {
|
|
63279
63657
|
if (this.win32SubmitTimer) {
|
|
63280
63658
|
clearTimeout(this.win32SubmitTimer);
|
|
63281
63659
|
this.win32SubmitTimer = null;
|
|
63282
63660
|
}
|
|
63661
|
+
const startedAt = Date.now();
|
|
63283
63662
|
const fire = (attempt) => {
|
|
63284
63663
|
this.win32SubmitTimer = null;
|
|
63285
63664
|
this.adapter.send_keys(submitKey);
|
|
@@ -63292,8 +63671,20 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
63292
63671
|
fire(attempt + 1);
|
|
63293
63672
|
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
63294
63673
|
};
|
|
63295
|
-
|
|
63296
|
-
|
|
63674
|
+
const waitForSettle = () => {
|
|
63675
|
+
this.win32SubmitTimer = null;
|
|
63676
|
+
const now = Date.now();
|
|
63677
|
+
const quietFor = now - this.lastWin32InputActivityAt();
|
|
63678
|
+
const waited = now - startedAt;
|
|
63679
|
+
if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
|
|
63680
|
+
fire(0);
|
|
63681
|
+
return;
|
|
63682
|
+
}
|
|
63683
|
+
const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
|
|
63684
|
+
this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
|
|
63685
|
+
};
|
|
63686
|
+
if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
|
|
63687
|
+
else waitForSettle();
|
|
63297
63688
|
}
|
|
63298
63689
|
handleClickControl(controlId, payload) {
|
|
63299
63690
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
|
|
@@ -63406,7 +63797,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
63406
63797
|
return out;
|
|
63407
63798
|
}
|
|
63408
63799
|
function flattenCond(c, out, depth) {
|
|
63409
|
-
|
|
63800
|
+
const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
|
|
63801
|
+
out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
|
|
63410
63802
|
for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
|
|
63411
63803
|
}
|
|
63412
63804
|
function findStable(c) {
|
|
@@ -64122,8 +64514,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64122
64514
|
}
|
|
64123
64515
|
return null;
|
|
64124
64516
|
}
|
|
64125
|
-
function oneLine(
|
|
64126
|
-
const flat =
|
|
64517
|
+
function oneLine(s2, max) {
|
|
64518
|
+
const flat = s2.replace(/\s+/g, " ").trim();
|
|
64127
64519
|
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
64128
64520
|
}
|
|
64129
64521
|
function parseTimestamp(v) {
|
|
@@ -64143,10 +64535,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64143
64535
|
return null;
|
|
64144
64536
|
}
|
|
64145
64537
|
function normalizeRole(r) {
|
|
64146
|
-
const
|
|
64147
|
-
if (
|
|
64148
|
-
if (
|
|
64149
|
-
if (
|
|
64538
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
64539
|
+
if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
|
|
64540
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
64541
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
64150
64542
|
return "system";
|
|
64151
64543
|
}
|
|
64152
64544
|
function stringifyContent(v) {
|
|
@@ -64194,18 +64586,18 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64194
64586
|
return (record2) => ors.some((ands) => ands.every((t) => evalTerm(t, record2)));
|
|
64195
64587
|
}
|
|
64196
64588
|
function parseTerm(src) {
|
|
64197
|
-
let
|
|
64589
|
+
let s2 = src.trim();
|
|
64198
64590
|
let negate = false;
|
|
64199
|
-
if (
|
|
64591
|
+
if (s2.startsWith("!")) {
|
|
64200
64592
|
negate = true;
|
|
64201
|
-
|
|
64593
|
+
s2 = s2.slice(1).trim();
|
|
64202
64594
|
}
|
|
64203
|
-
const fnMatch =
|
|
64595
|
+
const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
|
|
64204
64596
|
if (fnMatch) {
|
|
64205
64597
|
const [, op2, pathExpr, litExpr] = fnMatch;
|
|
64206
64598
|
return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
|
|
64207
64599
|
}
|
|
64208
|
-
const opMatch =
|
|
64600
|
+
const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
|
|
64209
64601
|
if (!opMatch) return null;
|
|
64210
64602
|
const [, lhs, op, rhsRaw] = opMatch;
|
|
64211
64603
|
return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
|
|
@@ -64635,7 +65027,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64635
65027
|
try {
|
|
64636
65028
|
const sections = this.driver.getSections();
|
|
64637
65029
|
if (sectionId && sections) {
|
|
64638
|
-
const hit = sections.find((
|
|
65030
|
+
const hit = sections.find((s2) => s2.id === sectionId);
|
|
64639
65031
|
if (hit) return hit.text;
|
|
64640
65032
|
}
|
|
64641
65033
|
return this.driver.getScreen();
|
|
@@ -64650,7 +65042,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64650
65042
|
screen = this.driver.snapshot();
|
|
64651
65043
|
const driverSections = this.driver.getSections?.();
|
|
64652
65044
|
if (driverSections) {
|
|
64653
|
-
sections = Object.fromEntries(driverSections.map((
|
|
65045
|
+
sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
|
|
64654
65046
|
} else {
|
|
64655
65047
|
sections = this.readCurrentScreenSections(screen);
|
|
64656
65048
|
}
|
|
@@ -64696,6 +65088,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
64696
65088
|
// answers "why did this rule fire" after the fact, unlike the live
|
|
64697
65089
|
// `fsm` field which only reflects the current instant.
|
|
64698
65090
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
65091
|
+
// PTY input/output/resize/cursor event timeline (debug-only) so the
|
|
65092
|
+
// snapshot shows what we typed / what the PTY printed around each
|
|
65093
|
+
// status transition. Null for drivers without the timeline.
|
|
65094
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
64699
65095
|
// Extended fields
|
|
64700
65096
|
name: this.cliName,
|
|
64701
65097
|
status: this.getStatus().status,
|
|
@@ -65060,6 +65456,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
65060
65456
|
// v4 FSM transition snapshot history — the captured pre-transition
|
|
65061
65457
|
// evaluation table at each transition (null for v3 specs).
|
|
65062
65458
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
65459
|
+
// PTY input/output/resize/cursor event timeline (debug-only).
|
|
65460
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
65063
65461
|
messages,
|
|
65064
65462
|
committedMessages: messages
|
|
65065
65463
|
};
|
|
@@ -65100,6 +65498,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
65100
65498
|
return new ProviderCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFactory);
|
|
65101
65499
|
}
|
|
65102
65500
|
init_logger();
|
|
65501
|
+
init_mesh_event_trace();
|
|
65103
65502
|
init_control_effects();
|
|
65104
65503
|
init_approval_utils();
|
|
65105
65504
|
init_provider_patch_state();
|
|
@@ -65394,6 +65793,11 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
65394
65793
|
// a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
|
|
65395
65794
|
// brief generating flip does not immediately wipe the settle clock.
|
|
65396
65795
|
autoApproveInactiveSince = 0;
|
|
65796
|
+
// Provider-common manual-attendance signal: while a human is actively driving
|
|
65797
|
+
// this session from the dashboard, auto-approve holds so they can take manual
|
|
65798
|
+
// control. Background mesh workers are never attended → delegated auto-approve
|
|
65799
|
+
// is unaffected.
|
|
65800
|
+
manualAttendance = new ManualAttendanceTracker();
|
|
65397
65801
|
controlValues = {};
|
|
65398
65802
|
summaryMetadata = void 0;
|
|
65399
65803
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -65669,7 +66073,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
65669
66073
|
}
|
|
65670
66074
|
getHotChatSessionState() {
|
|
65671
66075
|
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|
|
65672
|
-
const autoApproveActive = adapterStatus.status
|
|
66076
|
+
const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
|
|
65673
66077
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
|
|
65674
66078
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
|
|
65675
66079
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
@@ -65684,7 +66088,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
65684
66088
|
}
|
|
65685
66089
|
getSessionModalState(sessionId) {
|
|
65686
66090
|
const adapterStatus = this.adapter.getStatus({ allowParse: true });
|
|
65687
|
-
const autoApproveActive = adapterStatus.status
|
|
66091
|
+
const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
|
|
65688
66092
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
|
|
65689
66093
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
|
|
65690
66094
|
const dirName = workingDirBasename(this.workingDir);
|
|
@@ -65765,7 +66169,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
65765
66169
|
} catch {
|
|
65766
66170
|
return null;
|
|
65767
66171
|
}
|
|
65768
|
-
if (adapterStatus.status === "waiting_approval" && !this.
|
|
66172
|
+
if (adapterStatus.status === "waiting_approval" && !this.autoApproveEffectivelyActive(adapterStatus.status)) {
|
|
65769
66173
|
return "waiting_approval";
|
|
65770
66174
|
}
|
|
65771
66175
|
return null;
|
|
@@ -66138,6 +66542,23 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
66138
66542
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
66139
66543
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|
|
66140
66544
|
}
|
|
66545
|
+
// EVTTRACE (observation-only): is this a mesh worker session whose completion
|
|
66546
|
+
// events must route to a coordinator? Used purely to gate trace logging so a
|
|
66547
|
+
// non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
|
|
66548
|
+
isMeshWorkerSession() {
|
|
66549
|
+
return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
|
|
66550
|
+
}
|
|
66551
|
+
// EVTTRACE correlation context for this session's completion lifecycle. taskId is
|
|
66552
|
+
// the primary grep anchor; instanceId is the session fallback.
|
|
66553
|
+
meshTraceCtx(event = "agent:generating_completed") {
|
|
66554
|
+
return {
|
|
66555
|
+
taskId: this.settings.meshActiveTaskId,
|
|
66556
|
+
sessionId: this.instanceId,
|
|
66557
|
+
nodeId: this.settings.meshNodeId,
|
|
66558
|
+
meshId: this.settings.meshNodeFor,
|
|
66559
|
+
event
|
|
66560
|
+
};
|
|
66561
|
+
}
|
|
66141
66562
|
flushCompletedDebounceIfFinalized() {
|
|
66142
66563
|
const pending = this.completedDebouncePending;
|
|
66143
66564
|
if (!pending) {
|
|
@@ -66158,24 +66579,33 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
66158
66579
|
if (block2) {
|
|
66159
66580
|
const blockReason = block2.reason;
|
|
66160
66581
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
66161
|
-
|
|
66162
|
-
|
|
66582
|
+
const isTranscriptEvidenceGate = block2.allowTimeout === true;
|
|
66583
|
+
LOG2.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
66584
|
+
if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
|
|
66163
66585
|
if (pending.loggedBlockReason !== blockReason) {
|
|
66164
66586
|
LOG2.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
66587
|
+
if (this.isMeshWorkerSession()) {
|
|
66588
|
+
traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
|
|
66589
|
+
}
|
|
66165
66590
|
pending.loggedBlockReason = blockReason;
|
|
66166
66591
|
}
|
|
66167
66592
|
this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
|
|
66168
66593
|
return;
|
|
66169
66594
|
}
|
|
66595
|
+
const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
|
|
66170
66596
|
const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
|
|
66171
66597
|
blockReason,
|
|
66172
66598
|
latestStatus,
|
|
66173
66599
|
latestVisibleStatus,
|
|
66174
66600
|
waitedMs,
|
|
66175
66601
|
pending,
|
|
66176
|
-
emittedAfterFinalizationTimeout
|
|
66602
|
+
emittedAfterFinalizationTimeout
|
|
66177
66603
|
});
|
|
66178
|
-
|
|
66604
|
+
completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
|
|
66605
|
+
LOG2.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
|
|
66606
|
+
if (this.isMeshWorkerSession()) {
|
|
66607
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
|
|
66608
|
+
}
|
|
66179
66609
|
this.pushEvent({
|
|
66180
66610
|
event: "agent:generating_completed",
|
|
66181
66611
|
chatTitle: pending.chatTitle,
|
|
@@ -66198,6 +66628,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
66198
66628
|
return;
|
|
66199
66629
|
}
|
|
66200
66630
|
LOG2.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
|
|
66631
|
+
if (this.isMeshWorkerSession()) {
|
|
66632
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
|
|
66633
|
+
}
|
|
66201
66634
|
this.pushEvent({
|
|
66202
66635
|
event: "agent:generating_completed",
|
|
66203
66636
|
chatTitle: pending.chatTitle,
|
|
@@ -66211,6 +66644,18 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
66211
66644
|
this.lastApprovalEventFingerprint = "";
|
|
66212
66645
|
}
|
|
66213
66646
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
66647
|
+
if (adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove() && this.manualAttendance.isAttended(now)) {
|
|
66648
|
+
this.lastAutoApprovalSignature = "";
|
|
66649
|
+
this.pendingAutoApprovalSignature = "";
|
|
66650
|
+
this.pendingAutoApprovalSince = 0;
|
|
66651
|
+
this.autoApproveInactiveSince = 0;
|
|
66652
|
+
if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
|
|
66653
|
+
this.autoApproveSettleTimer = setTimeout(() => {
|
|
66654
|
+
this.autoApproveSettleTimer = null;
|
|
66655
|
+
this.recheckAutoApproveSettled();
|
|
66656
|
+
}, this.manualAttendance.remainingMs(now) + 20);
|
|
66657
|
+
return false;
|
|
66658
|
+
}
|
|
66214
66659
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
66215
66660
|
if (!autoApproveActive) {
|
|
66216
66661
|
this.lastAutoApprovalSignature = "";
|
|
@@ -66424,6 +66869,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
66424
66869
|
if (missingEvidence && !hasMeshContext) {
|
|
66425
66870
|
LOG2.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
|
|
66426
66871
|
} else {
|
|
66872
|
+
if (this.isMeshWorkerSession()) {
|
|
66873
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
|
|
66874
|
+
}
|
|
66427
66875
|
this.pushEvent({
|
|
66428
66876
|
event: "agent:generating_completed",
|
|
66429
66877
|
chatTitle,
|
|
@@ -66500,6 +66948,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
66500
66948
|
const monitorParsedStatus = parsedStatus;
|
|
66501
66949
|
for (const me of monitorEvents) {
|
|
66502
66950
|
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
66951
|
+
if (this.isMeshWorkerSession()) {
|
|
66952
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
|
|
66953
|
+
}
|
|
66503
66954
|
this.pushEvent({
|
|
66504
66955
|
event: "agent:generating_completed",
|
|
66505
66956
|
chatTitle,
|
|
@@ -66676,6 +67127,21 @@ ${effect.notification.body || ""}`.trim();
|
|
|
66676
67127
|
}
|
|
66677
67128
|
return false;
|
|
66678
67129
|
}
|
|
67130
|
+
/** @see ProviderInstance.noteManualInteraction */
|
|
67131
|
+
noteManualInteraction(now = Date.now()) {
|
|
67132
|
+
this.manualAttendance.note(now);
|
|
67133
|
+
}
|
|
67134
|
+
/**
|
|
67135
|
+
* Whether auto-approve should be treated as active *right now* for display
|
|
67136
|
+
* and firing decisions: the configured intent AND the user is not currently
|
|
67137
|
+
* attending this session by hand. When a human is attending, auto-approve is
|
|
67138
|
+
* held so the modal stays visible and they can drive it via the controlbar.
|
|
67139
|
+
* Provider-agnostic — the attendance signal is the command set, never any
|
|
67140
|
+
* CLI-specific modal text.
|
|
67141
|
+
*/
|
|
67142
|
+
autoApproveEffectivelyActive(status, now = Date.now()) {
|
|
67143
|
+
return status === "waiting_approval" && this.shouldAutoApprove() && !this.manualAttendance.isAttended(now);
|
|
67144
|
+
}
|
|
66679
67145
|
recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
|
|
66680
67146
|
this.appendRuntimeSystemMessage(
|
|
66681
67147
|
formatAutoApprovalMessage(modalMessage, buttonLabel),
|
|
@@ -67619,7 +68085,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
67619
68085
|
input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
|
|
67620
68086
|
});
|
|
67621
68087
|
}
|
|
67622
|
-
if (this.settings.autoApprove !== false) {
|
|
68088
|
+
if (this.settings.autoApprove !== false && !this.manualAttendance.isAttended()) {
|
|
67623
68089
|
const toolTitle = tc.title || tc.toolCallId || "tool call";
|
|
67624
68090
|
this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
|
|
67625
68091
|
this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
|
|
@@ -67850,6 +68316,15 @@ ${effect.notification.body || ""}`.trim();
|
|
|
67850
68316
|
this.detectStatusTransition();
|
|
67851
68317
|
}
|
|
67852
68318
|
permissionResolvers = [];
|
|
68319
|
+
// Provider-common manual-attendance signal: while a human is actively driving
|
|
68320
|
+
// this session from the dashboard, auto-approve holds so they can decide on
|
|
68321
|
+
// the permission request themselves. Background workers are never attended →
|
|
68322
|
+
// delegated auto-approve is unaffected.
|
|
68323
|
+
manualAttendance = new ManualAttendanceTracker();
|
|
68324
|
+
/** @see ProviderInstance.noteManualInteraction */
|
|
68325
|
+
noteManualInteraction(now = Date.now()) {
|
|
68326
|
+
this.manualAttendance.note(now);
|
|
68327
|
+
}
|
|
67853
68328
|
async resolvePermission(approved) {
|
|
67854
68329
|
const resolver = this.permissionResolvers.shift();
|
|
67855
68330
|
if (resolver) {
|
|
@@ -69001,6 +69476,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
69001
69476
|
);
|
|
69002
69477
|
continue;
|
|
69003
69478
|
}
|
|
69479
|
+
const restoredSettings = { ...this.providerLoader.getSettings(normalizedType) };
|
|
69480
|
+
const coordinatorEntry = getCoordinatorForSession(record2.runtimeId);
|
|
69481
|
+
if (coordinatorEntry?.meshId) {
|
|
69482
|
+
restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
|
|
69483
|
+
}
|
|
69004
69484
|
try {
|
|
69005
69485
|
await this.registerCliInstance(
|
|
69006
69486
|
record2.runtimeId,
|
|
@@ -69009,7 +69489,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
69009
69489
|
record2.workspace,
|
|
69010
69490
|
record2.cliArgs,
|
|
69011
69491
|
resolvedProvider,
|
|
69012
|
-
|
|
69492
|
+
restoredSettings,
|
|
69013
69493
|
true,
|
|
69014
69494
|
{
|
|
69015
69495
|
providerSessionId: sessionBinding.providerSessionId,
|
|
@@ -70310,7 +70790,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
70310
70790
|
}
|
|
70311
70791
|
if (buf.length === 0) return null;
|
|
70312
70792
|
const strings = extractStringsFromBuffer(buf);
|
|
70313
|
-
const meaningful = strings.filter((
|
|
70793
|
+
const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
|
|
70314
70794
|
if (meaningful.length === 0) return null;
|
|
70315
70795
|
const content = meaningful.join("\n");
|
|
70316
70796
|
const sourceMtimeMs = statMtimeMs3(filePath);
|
|
@@ -70516,10 +70996,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
70516
70996
|
};
|
|
70517
70997
|
}
|
|
70518
70998
|
function normalizeHermesRole(r) {
|
|
70519
|
-
const
|
|
70520
|
-
if (
|
|
70521
|
-
if (
|
|
70522
|
-
if (
|
|
70999
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
71000
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
71001
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
71002
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
70523
71003
|
return "system";
|
|
70524
71004
|
}
|
|
70525
71005
|
function createNativeHistoryDispatcher(reader) {
|
|
@@ -70743,10 +71223,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
70743
71223
|
}
|
|
70744
71224
|
}
|
|
70745
71225
|
function normalizeRole2(r) {
|
|
70746
|
-
const
|
|
70747
|
-
if (
|
|
70748
|
-
if (
|
|
70749
|
-
if (
|
|
71226
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
71227
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
71228
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
71229
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
70750
71230
|
return "system";
|
|
70751
71231
|
}
|
|
70752
71232
|
function registerProviderScriptRootSafely(root) {
|
|
@@ -70764,7 +71244,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
70764
71244
|
const actionType = ctl?.action?.type;
|
|
70765
71245
|
if (!id || !actionType) return;
|
|
70766
71246
|
const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
|
|
70767
|
-
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((
|
|
71247
|
+
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
|
|
70768
71248
|
if (actionType === "open_picker") {
|
|
70769
71249
|
out.push({
|
|
70770
71250
|
id,
|
|
@@ -77650,7 +78130,7 @@ ${mergeTreeErr?.stderr || ""}`;
|
|
|
77650
78130
|
const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing; merge/refine was not attempted. Configure validation.bootstrapCommands if Refinery should bootstrap dependencies before validation." : validationSummary.failureCode === "dependency_bootstrap_failed" ? "Refinery dependency/bootstrap command failed; merge/refine was not attempted." : validationSummary.failureCode === "spawn_resolution_failed" ? validationSummary.spawnResolutionError || "Refinery validation command could not be spawned (executable not found); merge/refine was not attempted." : "Refinery validation gate failed; merge/refine was not attempted.";
|
|
77651
78131
|
if (!firstFailedCmd) return base;
|
|
77652
78132
|
const cmdName = typeof firstFailedCmd.displayCommand === "string" ? firstFailedCmd.displayCommand : typeof firstFailedCmd.command === "string" ? [firstFailedCmd.command, ...Array.isArray(firstFailedCmd.args) ? firstFailedCmd.args : []].join(" ").trim() : typeof firstFailedCmd.cmd === "string" ? firstFailedCmd.cmd : "";
|
|
77653
|
-
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((
|
|
78133
|
+
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|
|
77654
78134
|
const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
|
|
77655
78135
|
return [
|
|
77656
78136
|
base,
|
|
@@ -78401,7 +78881,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
78401
78881
|
convergence = "blocked_review";
|
|
78402
78882
|
}
|
|
78403
78883
|
const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
|
|
78404
|
-
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((
|
|
78884
|
+
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
|
|
78405
78885
|
results.push({
|
|
78406
78886
|
nodeId: node.id,
|
|
78407
78887
|
workspace: node.workspace,
|
|
@@ -79398,7 +79878,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
79398
79878
|
return {
|
|
79399
79879
|
success: true,
|
|
79400
79880
|
screenLineCount: lines.length,
|
|
79401
|
-
sections: resolved.map((
|
|
79881
|
+
sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
|
|
79402
79882
|
};
|
|
79403
79883
|
} catch (e) {
|
|
79404
79884
|
return { success: false, error: `resolve failed: ${e.message}` };
|
|
@@ -79967,7 +80447,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
79967
80447
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
79968
80448
|
try {
|
|
79969
80449
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
79970
|
-
const status = Array.isArray(args?.status) ? args.status.map((
|
|
80450
|
+
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
79971
80451
|
const rawQueue = getQueue2(meshId, { status });
|
|
79972
80452
|
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
79973
80453
|
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
@@ -80248,7 +80728,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
80248
80728
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
80249
80729
|
}
|
|
80250
80730
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
80251
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
80731
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
80252
80732
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
80253
80733
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
80254
80734
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -80282,7 +80762,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
80282
80762
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
80283
80763
|
}
|
|
80284
80764
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
80285
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
80765
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
80286
80766
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
80287
80767
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
80288
80768
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -80330,7 +80810,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
80330
80810
|
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
80331
80811
|
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
80332
80812
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
80333
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
80813
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
80334
80814
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
80335
80815
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
80336
80816
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
@@ -80417,7 +80897,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
80417
80897
|
let worktreeCleanup;
|
|
80418
80898
|
if (node?.isLocalWorktree) {
|
|
80419
80899
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
80420
|
-
const isRemoteWorktree = nodeDaemonId && nodeDaemonId
|
|
80900
|
+
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
80421
80901
|
if (isRemoteWorktree) {
|
|
80422
80902
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
80423
80903
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -80499,7 +80979,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
80499
80979
|
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
80500
80980
|
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
80501
80981
|
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
80502
|
-
if (sourceDaemonId && sourceDaemonId
|
|
80982
|
+
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
80503
80983
|
const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
80504
80984
|
...typeof args === "object" && args !== null ? args : {},
|
|
80505
80985
|
_meshDirectDispatch: true
|
|
@@ -80741,7 +81221,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
80741
81221
|
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
80742
81222
|
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
80743
81223
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
80744
|
-
if (nodeDaemonId && nodeDaemonId
|
|
81224
|
+
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
80745
81225
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
80746
81226
|
...typeof args === "object" && args !== null ? args : {},
|
|
80747
81227
|
_meshDirectDispatch: true
|
|
@@ -81949,16 +82429,16 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
81949
82429
|
const now = this.lastStatusSentAt;
|
|
81950
82430
|
const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
|
|
81951
82431
|
const allStates = this.deps.instanceManager.collectAllStates();
|
|
81952
|
-
const ideStates = allStates.filter((
|
|
81953
|
-
const cliStates = allStates.filter((
|
|
81954
|
-
const acpStates = allStates.filter((
|
|
81955
|
-
const ideSummary = ideStates.map((
|
|
81956
|
-
const msgs =
|
|
81957
|
-
const exts =
|
|
81958
|
-
return `${
|
|
82432
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
82433
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
82434
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
82435
|
+
const ideSummary = ideStates.map((s2) => {
|
|
82436
|
+
const msgs = s2.activeChat?.messages?.length || 0;
|
|
82437
|
+
const exts = s2.extensions.length;
|
|
82438
|
+
return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
|
|
81959
82439
|
}).join(", ");
|
|
81960
|
-
const cliSummary = cliStates.map((
|
|
81961
|
-
const acpSummary = acpStates.map((
|
|
82440
|
+
const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
82441
|
+
const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
81962
82442
|
const logLevel = opts?.p2pOnly ? "debug" : "info";
|
|
81963
82443
|
const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
|
|
81964
82444
|
const summaryChanged = baseSummary !== this.lastStatusSummary;
|
|
@@ -82069,10 +82549,10 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
82069
82549
|
}
|
|
82070
82550
|
return false;
|
|
82071
82551
|
}
|
|
82072
|
-
simpleHash(
|
|
82552
|
+
simpleHash(s2) {
|
|
82073
82553
|
let h = 2166136261;
|
|
82074
|
-
for (let i = 0; i <
|
|
82075
|
-
h ^=
|
|
82554
|
+
for (let i = 0; i < s2.length; i++) {
|
|
82555
|
+
h ^= s2.charCodeAt(i);
|
|
82076
82556
|
h = h * 16777619 >>> 0;
|
|
82077
82557
|
}
|
|
82078
82558
|
return h.toString(36);
|
|
@@ -83280,7 +83760,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
83280
83760
|
* Per-category status collect
|
|
83281
83761
|
*/
|
|
83282
83762
|
collectStatesByCategory(category) {
|
|
83283
|
-
return this.collectAllStates().filter((
|
|
83763
|
+
return this.collectAllStates().filter((s2) => s2.category === category);
|
|
83284
83764
|
}
|
|
83285
83765
|
// ─── Tick engine ─────────────────────────────────
|
|
83286
83766
|
/**
|
|
@@ -85166,9 +85646,9 @@ async (params) => {
|
|
|
85166
85646
|
function findCliTarget(ctx, type, instanceId) {
|
|
85167
85647
|
if (!ctx.instanceManager) return null;
|
|
85168
85648
|
const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
|
|
85169
|
-
if (instanceId) return cliStates.find((
|
|
85649
|
+
if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
|
|
85170
85650
|
if (!type) return cliStates[cliStates.length - 1] || null;
|
|
85171
|
-
const matches = cliStates.filter((
|
|
85651
|
+
const matches = cliStates.filter((s2) => s2.type === type);
|
|
85172
85652
|
return matches[matches.length - 1] || null;
|
|
85173
85653
|
}
|
|
85174
85654
|
function getCliTargetBundle(ctx, type, instanceId) {
|
|
@@ -85531,20 +86011,20 @@ async (params) => {
|
|
|
85531
86011
|
return;
|
|
85532
86012
|
}
|
|
85533
86013
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
85534
|
-
const cliStates = allStates.filter((
|
|
85535
|
-
const result = cliStates.map((
|
|
85536
|
-
instanceId:
|
|
85537
|
-
type:
|
|
85538
|
-
name:
|
|
85539
|
-
category:
|
|
85540
|
-
status:
|
|
85541
|
-
mode:
|
|
85542
|
-
workspace:
|
|
85543
|
-
messageCount:
|
|
85544
|
-
lastMessage:
|
|
85545
|
-
activeModal:
|
|
85546
|
-
pendingEvents:
|
|
85547
|
-
settings:
|
|
86014
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
86015
|
+
const result = cliStates.map((s2) => ({
|
|
86016
|
+
instanceId: s2.instanceId,
|
|
86017
|
+
type: s2.type,
|
|
86018
|
+
name: s2.name,
|
|
86019
|
+
category: s2.category,
|
|
86020
|
+
status: s2.status,
|
|
86021
|
+
mode: s2.mode,
|
|
86022
|
+
workspace: s2.workspace,
|
|
86023
|
+
messageCount: s2.activeChat?.messages?.length || 0,
|
|
86024
|
+
lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
|
|
86025
|
+
activeModal: s2.activeChat?.activeModal || null,
|
|
86026
|
+
pendingEvents: s2.pendingEvents || [],
|
|
86027
|
+
settings: s2.settings
|
|
85548
86028
|
}));
|
|
85549
86029
|
ctx.json(res, 200, { instances: result, count: result.length });
|
|
85550
86030
|
}
|
|
@@ -85633,9 +86113,9 @@ async (params) => {
|
|
|
85633
86113
|
}
|
|
85634
86114
|
if (ctx.instanceManager) {
|
|
85635
86115
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
85636
|
-
const cliStates = allStates.filter((
|
|
85637
|
-
for (const
|
|
85638
|
-
ctx.sendCliSSE({ event: "snapshot", providerType:
|
|
86116
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
86117
|
+
for (const s2 of cliStates) {
|
|
86118
|
+
ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
|
|
85639
86119
|
}
|
|
85640
86120
|
}
|
|
85641
86121
|
_req.on("close", () => {
|
|
@@ -85651,7 +86131,7 @@ async (params) => {
|
|
|
85651
86131
|
const target = findCliTarget(ctx, type);
|
|
85652
86132
|
if (!target) {
|
|
85653
86133
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
85654
|
-
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((
|
|
86134
|
+
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
|
|
85655
86135
|
return;
|
|
85656
86136
|
}
|
|
85657
86137
|
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
@@ -85697,7 +86177,7 @@ async (params) => {
|
|
|
85697
86177
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
85698
86178
|
ctx.json(res, 404, {
|
|
85699
86179
|
error: `No running instance for: ${type}`,
|
|
85700
|
-
available: allStates.filter((
|
|
86180
|
+
available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
|
|
85701
86181
|
});
|
|
85702
86182
|
return;
|
|
85703
86183
|
}
|
|
@@ -86500,7 +86980,7 @@ async (params) => {
|
|
|
86500
86980
|
child.write("\x1B[12;1R");
|
|
86501
86981
|
ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
|
|
86502
86982
|
}
|
|
86503
|
-
checkAutoApproval(data, (
|
|
86983
|
+
checkAutoApproval(data, (s2) => child.write(s2));
|
|
86504
86984
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
|
|
86505
86985
|
scheduleAutoStopForVerification();
|
|
86506
86986
|
});
|
|
@@ -86513,7 +86993,7 @@ async (params) => {
|
|
|
86513
86993
|
stdout += chunk;
|
|
86514
86994
|
clearAutoStopTimer();
|
|
86515
86995
|
if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
|
|
86516
|
-
checkAutoApproval(chunk, (
|
|
86996
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
86517
86997
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
|
|
86518
86998
|
scheduleAutoStopForVerification();
|
|
86519
86999
|
});
|
|
@@ -86521,7 +87001,7 @@ async (params) => {
|
|
|
86521
87001
|
const chunk = d.toString();
|
|
86522
87002
|
stderr += chunk;
|
|
86523
87003
|
clearAutoStopTimer();
|
|
86524
|
-
checkAutoApproval(chunk, (
|
|
87004
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
86525
87005
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
|
|
86526
87006
|
scheduleAutoStopForVerification();
|
|
86527
87007
|
});
|
|
@@ -87334,59 +87814,59 @@ data: ${JSON.stringify(msg.data)}
|
|
|
87334
87814
|
// ─── Route Table ─────────────────────────────────────
|
|
87335
87815
|
routes = [
|
|
87336
87816
|
// Static routes
|
|
87337
|
-
{ method: "GET", pattern: "/api/providers", handler: (q,
|
|
87338
|
-
{ method: "GET", pattern: "/api/providers/source-config", handler: (q,
|
|
87339
|
-
{ method: "POST", pattern: "/api/providers/source-config", handler: (q,
|
|
87340
|
-
{ method: "GET", pattern: "/api/providers/versions", handler: (q,
|
|
87341
|
-
{ method: "POST", pattern: "/api/providers/reload", handler: (q,
|
|
87342
|
-
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q,
|
|
87343
|
-
{ method: "POST", pattern: "/api/cdp/click", handler: (q,
|
|
87344
|
-
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q,
|
|
87345
|
-
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q,
|
|
87346
|
-
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q,
|
|
87347
|
-
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q,
|
|
87348
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q,
|
|
87349
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q,
|
|
87350
|
-
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q,
|
|
87351
|
-
{ method: "GET", pattern: "/api/cdp/targets", handler: (q,
|
|
87352
|
-
{ method: "POST", pattern: "/api/scripts/run", handler: (q,
|
|
87353
|
-
{ method: "GET", pattern: "/api/status", handler: (q,
|
|
87354
|
-
{ method: "POST", pattern: "/api/watch/start", handler: (q,
|
|
87355
|
-
{ method: "POST", pattern: "/api/watch/stop", handler: (q,
|
|
87356
|
-
{ method: "GET", pattern: "/api/watch/events", handler: (q,
|
|
87357
|
-
{ method: "POST", pattern: "/api/scaffold", handler: (q,
|
|
87817
|
+
{ method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
|
|
87818
|
+
{ method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
|
|
87819
|
+
{ method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
|
|
87820
|
+
{ method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
|
|
87821
|
+
{ method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
|
|
87822
|
+
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
|
|
87823
|
+
{ method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
|
|
87824
|
+
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
|
|
87825
|
+
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
|
|
87826
|
+
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
|
|
87827
|
+
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
|
|
87828
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
|
|
87829
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
|
|
87830
|
+
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
|
|
87831
|
+
{ method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
|
|
87832
|
+
{ method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
|
|
87833
|
+
{ method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
|
|
87834
|
+
{ method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
|
|
87835
|
+
{ method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
|
|
87836
|
+
{ method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
|
|
87837
|
+
{ method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
|
|
87358
87838
|
// CLI Debug routes
|
|
87359
|
-
{ method: "GET", pattern: "/api/cli/status", handler: (q,
|
|
87360
|
-
{ method: "POST", pattern: "/api/cli/launch", handler: (q,
|
|
87361
|
-
{ method: "POST", pattern: "/api/cli/send", handler: (q,
|
|
87362
|
-
{ method: "POST", pattern: "/api/cli/exercise", handler: (q,
|
|
87363
|
-
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q,
|
|
87364
|
-
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q,
|
|
87365
|
-
{ method: "POST", pattern: "/api/cli/resolve", handler: (q,
|
|
87366
|
-
{ method: "POST", pattern: "/api/cli/raw", handler: (q,
|
|
87367
|
-
{ method: "POST", pattern: "/api/cli/stop", handler: (q,
|
|
87368
|
-
{ method: "GET", pattern: "/api/cli/events", handler: (q,
|
|
87369
|
-
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q,
|
|
87370
|
-
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q,
|
|
87371
|
-
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q,
|
|
87839
|
+
{ method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
|
|
87840
|
+
{ method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
|
|
87841
|
+
{ method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
|
|
87842
|
+
{ method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
|
|
87843
|
+
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
|
|
87844
|
+
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
|
|
87845
|
+
{ method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
|
|
87846
|
+
{ method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
|
|
87847
|
+
{ method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
|
|
87848
|
+
{ method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
|
|
87849
|
+
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
|
|
87850
|
+
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
|
|
87851
|
+
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
|
|
87372
87852
|
// Dynamic routes (provider :type param)
|
|
87373
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q,
|
|
87374
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q,
|
|
87375
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
87376
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
87377
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q,
|
|
87378
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q,
|
|
87379
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q,
|
|
87380
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q,
|
|
87381
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q,
|
|
87382
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q,
|
|
87383
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q,
|
|
87384
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q,
|
|
87385
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q,
|
|
87386
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q,
|
|
87387
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q,
|
|
87388
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q,
|
|
87389
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q,
|
|
87853
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
|
|
87854
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
|
|
87855
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
|
|
87856
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
|
|
87857
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
|
|
87858
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
|
|
87859
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
|
|
87860
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
|
|
87861
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
|
|
87862
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
|
|
87863
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
|
|
87864
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
|
|
87865
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
|
|
87866
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
|
|
87867
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
|
|
87868
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
|
|
87869
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
|
|
87390
87870
|
];
|
|
87391
87871
|
matchRoute(method, pathname) {
|
|
87392
87872
|
for (const route of this.routes) {
|
|
@@ -87981,14 +88461,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
87981
88461
|
warnings.push(...validation.warnings);
|
|
87982
88462
|
if (config2.settings) {
|
|
87983
88463
|
for (const [key, val] of Object.entries(config2.settings)) {
|
|
87984
|
-
const
|
|
87985
|
-
if (!
|
|
87986
|
-
else if (!["boolean", "number", "string", "select"].includes(
|
|
87987
|
-
errors.push(`settings.${key}: invalid type '${
|
|
87988
|
-
if (
|
|
87989
|
-
if (
|
|
87990
|
-
errors.push(`settings.${key}: min (${
|
|
87991
|
-
if (
|
|
88464
|
+
const s2 = val;
|
|
88465
|
+
if (!s2.type) errors.push(`settings.${key}: missing type`);
|
|
88466
|
+
else if (!["boolean", "number", "string", "select"].includes(s2.type))
|
|
88467
|
+
errors.push(`settings.${key}: invalid type '${s2.type}'`);
|
|
88468
|
+
if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
|
|
88469
|
+
if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
|
|
88470
|
+
errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
|
|
88471
|
+
if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
|
|
87992
88472
|
errors.push(`settings.${key}: select type requires options[]`);
|
|
87993
88473
|
}
|
|
87994
88474
|
}
|