@adhdev/daemon-core 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/commands/handler.d.ts +15 -0
- package/dist/index.js +703 -220
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +703 -220
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-event-trace.d.ts +21 -0
- package/dist/mesh/mesh-runtime-store.d.ts +1 -1
- package/dist/mesh/mesh-work-queue.d.ts +1 -1
- package/dist/providers/acp-provider-instance.d.ts +3 -0
- package/dist/providers/cli-provider-instance.d.ts +14 -0
- package/dist/providers/manual-attendance.d.ts +63 -0
- package/dist/providers/provider-instance.d.ts +8 -0
- package/dist/providers/spec/adapter.d.ts +22 -0
- package/dist/providers/spec/fsm-driver.d.ts +49 -7
- package/dist/providers/spec/fsm-evaluator.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +9 -5
- package/package.json +2 -2
- package/src/commands/cli-manager.ts +20 -2
- package/src/commands/handler.ts +32 -0
- package/src/commands/router.ts +19 -6
- package/src/git/git-diff.ts +31 -14
- package/src/mesh/mesh-event-trace.ts +67 -0
- package/src/mesh/mesh-events-coordinator.ts +117 -12
- package/src/mesh/mesh-events-pending.ts +33 -0
- package/src/mesh/mesh-events-stale.ts +3 -1
- package/src/mesh/mesh-reconcile-loop.ts +47 -0
- package/src/mesh/mesh-runtime-store.ts +18 -2
- package/src/mesh/mesh-work-queue.ts +8 -1
- package/src/providers/acp-provider-instance.ts +18 -1
- package/src/providers/cli-provider-instance.ts +123 -7
- package/src/providers/manual-attendance.ts +85 -0
- package/src/providers/provider-instance.ts +9 -0
- package/src/providers/spec/adapter.ts +67 -0
- package/src/providers/spec/cli-adapter.ts +6 -0
- package/src/providers/spec/evaluator.ts +24 -9
- package/src/providers/spec/fsm-driver.ts +135 -13
- package/src/providers/spec/fsm-evaluator.ts +19 -2
- package/src/providers/spec/types.ts +9 -5
package/dist/index.js
CHANGED
|
@@ -316,10 +316,10 @@ function readInjected(value) {
|
|
|
316
316
|
}
|
|
317
317
|
function getDaemonBuildInfo() {
|
|
318
318
|
if (cached) return cached;
|
|
319
|
-
const commit = readInjected(true ? "
|
|
320
|
-
const commitShort = readInjected(true ? "
|
|
321
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
322
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
319
|
+
const commit = readInjected(true ? "a45106605e2ae1c10c0bc6cbe48c2cac4e862ded" : void 0) ?? "unknown";
|
|
320
|
+
const commitShort = readInjected(true ? "a4510660" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
321
|
+
const version = readInjected(true ? "0.9.82-rc.355" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
322
|
+
const builtAt = readInjected(true ? "2026-06-22T15:21:19.981Z" : void 0);
|
|
323
323
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
324
324
|
return cached;
|
|
325
325
|
}
|
|
@@ -1070,6 +1070,9 @@ __export(git_diff_exports, {
|
|
|
1070
1070
|
getGitDiffSummary: () => getGitDiffSummary,
|
|
1071
1071
|
getGitFileDiff: () => getGitFileDiff
|
|
1072
1072
|
});
|
|
1073
|
+
function withCollectionTimeout(options) {
|
|
1074
|
+
return options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
|
|
1075
|
+
}
|
|
1073
1076
|
function validateBaseRef(ref) {
|
|
1074
1077
|
const trimmed = ref.trim();
|
|
1075
1078
|
if (!trimmed || trimmed.startsWith("-") || trimmed.includes("..") || !/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(trimmed)) {
|
|
@@ -1079,14 +1082,15 @@ function validateBaseRef(ref) {
|
|
|
1079
1082
|
}
|
|
1080
1083
|
async function getGitDiffSummary(workspace, options = {}) {
|
|
1081
1084
|
const lastCheckedAt = Date.now();
|
|
1085
|
+
const effectiveOptions = withCollectionTimeout(options);
|
|
1082
1086
|
try {
|
|
1083
|
-
const repo = await resolveGitRepository(workspace,
|
|
1087
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
1084
1088
|
const repoRoot = repo.repoRoot;
|
|
1085
1089
|
if (options.baseRef) {
|
|
1086
1090
|
const range = `${validateBaseRef(options.baseRef)}...HEAD`;
|
|
1087
1091
|
const [nameStatus, numstat] = await Promise.all([
|
|
1088
|
-
runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...
|
|
1089
|
-
runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...
|
|
1092
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1093
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...effectiveOptions, cwd: repoRoot })
|
|
1090
1094
|
]);
|
|
1091
1095
|
const outputBytes2 = byteLength(nameStatus.stdout + numstat.stdout);
|
|
1092
1096
|
const changes2 = combineDiffEntries(nameStatus.stdout, numstat.stdout, false);
|
|
@@ -1105,11 +1109,11 @@ async function getGitDiffSummary(workspace, options = {}) {
|
|
|
1105
1109
|
};
|
|
1106
1110
|
}
|
|
1107
1111
|
const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
|
|
1108
|
-
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...
|
|
1109
|
-
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...
|
|
1110
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...
|
|
1111
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...
|
|
1112
|
-
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...
|
|
1112
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1113
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1114
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1115
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1116
|
+
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...effectiveOptions, cwd: repoRoot })
|
|
1113
1117
|
]);
|
|
1114
1118
|
const outputBytes = byteLength(
|
|
1115
1119
|
unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
|
|
@@ -1151,13 +1155,14 @@ async function getGitDiffSummary(workspace, options = {}) {
|
|
|
1151
1155
|
}
|
|
1152
1156
|
async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
1153
1157
|
const lastCheckedAt = Date.now();
|
|
1154
|
-
const
|
|
1158
|
+
const effectiveOptions = withCollectionTimeout(options);
|
|
1159
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
1155
1160
|
const repoRoot = repo.repoRoot;
|
|
1156
1161
|
const selected = await resolveRepoFilePath(repoRoot, filePath);
|
|
1157
1162
|
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
1158
1163
|
if (options.baseRef) {
|
|
1159
1164
|
const range = `${validateBaseRef(options.baseRef)}...HEAD`;
|
|
1160
|
-
const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...
|
|
1165
|
+
const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot });
|
|
1161
1166
|
const bounded2 = truncateText(result.stdout, maxBytes);
|
|
1162
1167
|
return {
|
|
1163
1168
|
workspace: repo.workspace,
|
|
@@ -1170,13 +1175,13 @@ async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
|
1170
1175
|
};
|
|
1171
1176
|
}
|
|
1172
1177
|
const [unstaged, staged] = await Promise.all([
|
|
1173
|
-
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...
|
|
1174
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...
|
|
1178
|
+
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot }),
|
|
1179
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot })
|
|
1175
1180
|
]);
|
|
1176
1181
|
let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
|
|
1177
1182
|
if (!diff) {
|
|
1178
1183
|
const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
|
|
1179
|
-
...
|
|
1184
|
+
...effectiveOptions,
|
|
1180
1185
|
cwd: repoRoot
|
|
1181
1186
|
});
|
|
1182
1187
|
const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
|
|
@@ -4822,9 +4827,12 @@ function getActiveDirectDispatches(meshId) {
|
|
|
4822
4827
|
return [];
|
|
4823
4828
|
}
|
|
4824
4829
|
}
|
|
4825
|
-
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
4830
|
+
function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
4826
4831
|
try {
|
|
4827
|
-
|
|
4832
|
+
if (!taskId) {
|
|
4833
|
+
LOG.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)`);
|
|
4834
|
+
}
|
|
4835
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
|
|
4828
4836
|
} catch {
|
|
4829
4837
|
}
|
|
4830
4838
|
}
|
|
@@ -5657,9 +5665,25 @@ var init_mesh_runtime_store = __esm({
|
|
|
5657
5665
|
updatedAt: r.updated_at
|
|
5658
5666
|
}));
|
|
5659
5667
|
}
|
|
5660
|
-
|
|
5661
|
-
|
|
5668
|
+
// CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
|
|
5669
|
+
// single session can host several sequential direct dispatches (re-dispatch / nudge), so
|
|
5670
|
+
// matching a status flip by session_id alone hits EVERY non-terminal row for that session
|
|
5671
|
+
// — flipping a sibling task's row and stranding the one whose event actually fired (the
|
|
5672
|
+
// assigned-stranded watchdog then requeues a task that is really still generating). When
|
|
5673
|
+
// the firing event carries a taskId, target the single PK row; the session_id match is the
|
|
5674
|
+
// legacy fallback only for events that arrive without a taskId.
|
|
5675
|
+
updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
5662
5676
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5677
|
+
if (taskId) {
|
|
5678
|
+
this.db.prepare(`
|
|
5679
|
+
UPDATE mesh_direct_dispatches
|
|
5680
|
+
SET status = @status, updated_at = @updatedAt
|
|
5681
|
+
WHERE mesh_id = @meshId AND task_id = @taskId
|
|
5682
|
+
AND status NOT IN ('completed', 'failed')
|
|
5683
|
+
`).run({ status, meshId, taskId, updatedAt: now });
|
|
5684
|
+
return;
|
|
5685
|
+
}
|
|
5686
|
+
if (!sessionId) return;
|
|
5663
5687
|
this.db.prepare(`
|
|
5664
5688
|
UPDATE mesh_direct_dispatches
|
|
5665
5689
|
SET status = @status, updated_at = @updatedAt
|
|
@@ -7385,7 +7409,7 @@ function resolveWin32Executable(command) {
|
|
|
7385
7409
|
windowsHide: true
|
|
7386
7410
|
}).trim();
|
|
7387
7411
|
if (out) {
|
|
7388
|
-
const matches = out.split(/\r?\n/).map((
|
|
7412
|
+
const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
|
|
7389
7413
|
const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
|
|
7390
7414
|
return direct || matches[0] || command;
|
|
7391
7415
|
}
|
|
@@ -8737,11 +8761,29 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
8737
8761
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
8738
8762
|
);
|
|
8739
8763
|
}
|
|
8764
|
+
function isWeakCompletionMetadata(metadata) {
|
|
8765
|
+
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
8766
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
8767
|
+
if (metadata.reviewRecommended === true) return true;
|
|
8768
|
+
const diag = readRecord4(metadata.completionDiagnostic);
|
|
8769
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
8770
|
+
}
|
|
8740
8771
|
function buildPendingEventFingerprint(event) {
|
|
8741
8772
|
const metadata = readRecord4(event.metadataEvent) || {};
|
|
8742
8773
|
if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
|
|
8743
8774
|
return [event.meshId, event.event, event.nodeId || ""].join("::");
|
|
8744
8775
|
}
|
|
8776
|
+
if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
|
|
8777
|
+
const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
8778
|
+
if (terminalTaskId) {
|
|
8779
|
+
return [
|
|
8780
|
+
event.meshId,
|
|
8781
|
+
event.event,
|
|
8782
|
+
terminalTaskId,
|
|
8783
|
+
isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
|
|
8784
|
+
].join("::");
|
|
8785
|
+
}
|
|
8786
|
+
}
|
|
8745
8787
|
const sessionId = resolveEventSessionId(metadata);
|
|
8746
8788
|
const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
|
|
8747
8789
|
const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
@@ -9100,7 +9142,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
9100
9142
|
}
|
|
9101
9143
|
}
|
|
9102
9144
|
}
|
|
9103
|
-
var import_fs10, import_path9, import_crypto7, REFINE_TERMINAL_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9145
|
+
var import_fs10, import_path9, import_crypto7, REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9104
9146
|
var init_mesh_events_pending = __esm({
|
|
9105
9147
|
"src/mesh/mesh-events-pending.ts"() {
|
|
9106
9148
|
"use strict";
|
|
@@ -9113,6 +9155,7 @@ var init_mesh_events_pending = __esm({
|
|
|
9113
9155
|
init_mesh_events_utils();
|
|
9114
9156
|
init_dist();
|
|
9115
9157
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
9158
|
+
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
9116
9159
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
9117
9160
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
9118
9161
|
}
|
|
@@ -9442,7 +9485,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
|
|
|
9442
9485
|
evidence
|
|
9443
9486
|
}
|
|
9444
9487
|
});
|
|
9445
|
-
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9488
|
+
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
|
|
9446
9489
|
markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9447
9490
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
9448
9491
|
queuePendingMeshCoordinatorEvent({
|
|
@@ -9732,8 +9775,8 @@ function parsePatternEntry(x) {
|
|
|
9732
9775
|
if (x instanceof RegExp) return x;
|
|
9733
9776
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
9734
9777
|
try {
|
|
9735
|
-
const
|
|
9736
|
-
return new RegExp(
|
|
9778
|
+
const s2 = x;
|
|
9779
|
+
return new RegExp(s2.source, s2.flags || "");
|
|
9737
9780
|
} catch {
|
|
9738
9781
|
return null;
|
|
9739
9782
|
}
|
|
@@ -10304,6 +10347,38 @@ var init_mesh_unresolved_forward_outbox = __esm({
|
|
|
10304
10347
|
}
|
|
10305
10348
|
});
|
|
10306
10349
|
|
|
10350
|
+
// src/mesh/mesh-event-trace.ts
|
|
10351
|
+
function s(v) {
|
|
10352
|
+
return typeof v === "string" && v.trim() ? v.trim() : "";
|
|
10353
|
+
}
|
|
10354
|
+
function meshEventTraceKey(ctx) {
|
|
10355
|
+
const segs = [`task=${s(ctx.taskId) || "-"}`];
|
|
10356
|
+
const eventId = s(ctx.eventId);
|
|
10357
|
+
if (eventId) segs.push(`evt=${eventId}`);
|
|
10358
|
+
segs.push(`sess=${s(ctx.sessionId) || "-"}`);
|
|
10359
|
+
const nodeId = s(ctx.nodeId);
|
|
10360
|
+
if (nodeId) segs.push(`node=${nodeId}`);
|
|
10361
|
+
const meshId = s(ctx.meshId);
|
|
10362
|
+
if (meshId) segs.push(`mesh=${meshId}`);
|
|
10363
|
+
const event = s(ctx.event);
|
|
10364
|
+
if (event) segs.push(`event=${event}`);
|
|
10365
|
+
return segs.join(" ");
|
|
10366
|
+
}
|
|
10367
|
+
function traceMeshEventStage(stage, ctx, detail) {
|
|
10368
|
+
LOG.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10369
|
+
}
|
|
10370
|
+
function traceMeshEventDrop(reason, ctx, detail) {
|
|
10371
|
+
LOG.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10372
|
+
}
|
|
10373
|
+
var CAT;
|
|
10374
|
+
var init_mesh_event_trace = __esm({
|
|
10375
|
+
"src/mesh/mesh-event-trace.ts"() {
|
|
10376
|
+
"use strict";
|
|
10377
|
+
init_logger();
|
|
10378
|
+
CAT = "EvtTrace";
|
|
10379
|
+
}
|
|
10380
|
+
});
|
|
10381
|
+
|
|
10307
10382
|
// src/config/state-store.ts
|
|
10308
10383
|
function isPlainObject2(value) {
|
|
10309
10384
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -12089,9 +12164,9 @@ function buildAcpSession(state, options) {
|
|
|
12089
12164
|
}
|
|
12090
12165
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
12091
12166
|
const sessions = [];
|
|
12092
|
-
const ideStates = allStates.filter((
|
|
12093
|
-
const cliStates = allStates.filter((
|
|
12094
|
-
const acpStates = allStates.filter((
|
|
12167
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
12168
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
12169
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
12095
12170
|
for (const state of ideStates) {
|
|
12096
12171
|
sessions.push(buildWorkspaceSession(state, cdpManagers, options));
|
|
12097
12172
|
for (const ext of state.extensions) {
|
|
@@ -12575,6 +12650,15 @@ function getCachedMeshByWorkspace(workspace) {
|
|
|
12575
12650
|
meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
|
|
12576
12651
|
return mesh;
|
|
12577
12652
|
}
|
|
12653
|
+
function recoverMeshIdByNodeId(nodeId) {
|
|
12654
|
+
if (!nodeId) return "";
|
|
12655
|
+
for (const mesh of listMeshes()) {
|
|
12656
|
+
if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
|
|
12657
|
+
return readNonEmptyString2(mesh.id);
|
|
12658
|
+
}
|
|
12659
|
+
}
|
|
12660
|
+
return "";
|
|
12661
|
+
}
|
|
12578
12662
|
function __resetIdleAutoFastForwardForTests() {
|
|
12579
12663
|
idleAutoFastForwardLastAttempt.clear();
|
|
12580
12664
|
}
|
|
@@ -13477,6 +13561,13 @@ function shouldForceInjectMeshEvent(eventName) {
|
|
|
13477
13561
|
function injectMeshSystemMessage(components, args) {
|
|
13478
13562
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
13479
13563
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13564
|
+
const traceCtx = {
|
|
13565
|
+
taskId: args.metadataEvent.taskId,
|
|
13566
|
+
sessionId: eventSessionId,
|
|
13567
|
+
nodeId: eventNodeId,
|
|
13568
|
+
meshId: args.meshId,
|
|
13569
|
+
event: args.event
|
|
13570
|
+
};
|
|
13480
13571
|
const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
|
|
13481
13572
|
const workerCoordinatorDaemonId = readNonEmptyString2(
|
|
13482
13573
|
sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
|
|
@@ -13530,6 +13621,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13530
13621
|
}
|
|
13531
13622
|
}
|
|
13532
13623
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
13624
|
+
traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
|
|
13533
13625
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
13534
13626
|
}
|
|
13535
13627
|
if (args.event === "monitor:no_progress") {
|
|
@@ -13550,6 +13642,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13550
13642
|
}
|
|
13551
13643
|
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
13552
13644
|
LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
13645
|
+
traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
|
|
13553
13646
|
return {
|
|
13554
13647
|
success: true,
|
|
13555
13648
|
forwarded: 0,
|
|
@@ -13561,6 +13654,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13561
13654
|
}
|
|
13562
13655
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
13563
13656
|
LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
13657
|
+
traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
|
|
13564
13658
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
13565
13659
|
}
|
|
13566
13660
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
@@ -13575,6 +13669,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13575
13669
|
});
|
|
13576
13670
|
if (duplicateApproval) {
|
|
13577
13671
|
LOG.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13672
|
+
traceMeshEventDrop("duplicate_approval", traceCtx);
|
|
13578
13673
|
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
13579
13674
|
}
|
|
13580
13675
|
}
|
|
@@ -13594,6 +13689,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13594
13689
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
13595
13690
|
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
13596
13691
|
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13692
|
+
traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
|
|
13597
13693
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
13598
13694
|
}
|
|
13599
13695
|
}
|
|
@@ -13612,6 +13708,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13612
13708
|
});
|
|
13613
13709
|
if (duplicateCompletion) {
|
|
13614
13710
|
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13711
|
+
traceMeshEventDrop("duplicate_completion", traceCtx);
|
|
13615
13712
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
13616
13713
|
}
|
|
13617
13714
|
}
|
|
@@ -13630,6 +13727,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13630
13727
|
});
|
|
13631
13728
|
if (duplicateStopped) {
|
|
13632
13729
|
LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13730
|
+
traceMeshEventDrop("duplicate_stopped", traceCtx);
|
|
13633
13731
|
return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
|
|
13634
13732
|
}
|
|
13635
13733
|
}
|
|
@@ -13641,7 +13739,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13641
13739
|
});
|
|
13642
13740
|
const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
|
|
13643
13741
|
if (!leaveDirectDispatchActive) {
|
|
13644
|
-
updateDirectDispatchStatus(args.meshId, sessionId, outcome);
|
|
13742
|
+
updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
|
|
13645
13743
|
}
|
|
13646
13744
|
markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
|
|
13647
13745
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
@@ -13654,7 +13752,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13654
13752
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13655
13753
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
13656
13754
|
if (sessionId) {
|
|
13657
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13755
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13658
13756
|
const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
|
|
13659
13757
|
completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
|
|
13660
13758
|
if (nodeId && providerType) {
|
|
@@ -13737,7 +13835,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13737
13835
|
}
|
|
13738
13836
|
}
|
|
13739
13837
|
if (sessionId) {
|
|
13740
|
-
|
|
13838
|
+
const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
|
|
13839
|
+
updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
|
|
13741
13840
|
const activeDeliveries = (() => {
|
|
13742
13841
|
try {
|
|
13743
13842
|
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
|
|
@@ -13745,7 +13844,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13745
13844
|
return [];
|
|
13746
13845
|
}
|
|
13747
13846
|
})();
|
|
13748
|
-
|
|
13847
|
+
const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
|
|
13848
|
+
for (const d of deliveriesToAck) {
|
|
13749
13849
|
updateSessionDeliveryStatus(d.id, "acked");
|
|
13750
13850
|
}
|
|
13751
13851
|
}
|
|
@@ -13759,7 +13859,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13759
13859
|
}
|
|
13760
13860
|
}
|
|
13761
13861
|
if (sessionId) {
|
|
13762
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13862
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13763
13863
|
completedTaskForLedger = markSessionTerminal(sessionId, "failed");
|
|
13764
13864
|
}
|
|
13765
13865
|
}
|
|
@@ -13905,6 +14005,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13905
14005
|
};
|
|
13906
14006
|
if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
|
|
13907
14007
|
LOG.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
|
|
14008
|
+
traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
|
|
14009
|
+
} else {
|
|
14010
|
+
traceMeshEventDrop("queue_dedup", traceCtx);
|
|
13908
14011
|
}
|
|
13909
14012
|
return { success: true, forwarded: 0 };
|
|
13910
14013
|
}
|
|
@@ -13915,8 +14018,23 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
13915
14018
|
}
|
|
13916
14019
|
const nodeId = readNonEmptyString2(payload.nodeId);
|
|
13917
14020
|
const workspace = readNonEmptyString2(payload.workspace);
|
|
13918
|
-
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
|
|
13919
|
-
if (!meshId)
|
|
14021
|
+
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
|
|
14022
|
+
if (!meshId) {
|
|
14023
|
+
traceMeshEventDrop("meshId_required", {
|
|
14024
|
+
taskId: payload.taskId,
|
|
14025
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14026
|
+
nodeId,
|
|
14027
|
+
event: eventName
|
|
14028
|
+
}, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
|
|
14029
|
+
return { success: false, error: "meshId required" };
|
|
14030
|
+
}
|
|
14031
|
+
traceMeshEventStage("received", {
|
|
14032
|
+
taskId: payload.taskId,
|
|
14033
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14034
|
+
nodeId,
|
|
14035
|
+
meshId,
|
|
14036
|
+
event: eventName
|
|
14037
|
+
});
|
|
13920
14038
|
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
13921
14039
|
const relayModalMessage = readNonEmptyString2(payload.modalMessage);
|
|
13922
14040
|
const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
|
|
@@ -13997,9 +14115,18 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
|
13997
14115
|
workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
|
|
13998
14116
|
};
|
|
13999
14117
|
const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
|
|
14118
|
+
const fwdTraceCtx = {
|
|
14119
|
+
taskId: payload.taskId,
|
|
14120
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14121
|
+
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
|
|
14122
|
+
event: eventName
|
|
14123
|
+
};
|
|
14124
|
+
traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
|
|
14125
|
+
traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
|
|
14000
14126
|
Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
|
|
14001
14127
|
if (result && result.success === false) {
|
|
14002
14128
|
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
|
|
14129
|
+
traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14003
14130
|
return;
|
|
14004
14131
|
}
|
|
14005
14132
|
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
@@ -14067,6 +14194,14 @@ function setupMeshEventForwarding(components) {
|
|
|
14067
14194
|
if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
|
|
14068
14195
|
return;
|
|
14069
14196
|
}
|
|
14197
|
+
if (isUnroutableDelegateRejection(routing)) {
|
|
14198
|
+
traceMeshEventDrop("unroutable", {
|
|
14199
|
+
taskId: event.meshActiveTaskId ?? event.taskId,
|
|
14200
|
+
sessionId: routing.sessionId,
|
|
14201
|
+
nodeId: routing.nodeId,
|
|
14202
|
+
event: event.event
|
|
14203
|
+
}, "no coordinator anchor / mesh_unresolved");
|
|
14204
|
+
}
|
|
14070
14205
|
recordUnroutableDelegateEvent(routing, event.event);
|
|
14071
14206
|
return;
|
|
14072
14207
|
}
|
|
@@ -14097,6 +14232,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
14097
14232
|
init_mesh_events_pending();
|
|
14098
14233
|
init_mesh_routing();
|
|
14099
14234
|
init_mesh_unresolved_forward_outbox();
|
|
14235
|
+
init_mesh_event_trace();
|
|
14100
14236
|
init_snapshot();
|
|
14101
14237
|
init_repo_mesh_types();
|
|
14102
14238
|
init_dist();
|
|
@@ -14208,6 +14344,13 @@ function findLiveCoordinators(components) {
|
|
|
14208
14344
|
function injectPendingIntoCoordinator(coordinator, pending) {
|
|
14209
14345
|
if (!coordinator || !pending.coordinatorMessage) return;
|
|
14210
14346
|
const force = shouldForceInjectMeshEvent(pending.event);
|
|
14347
|
+
traceMeshEventStage("surfaced", {
|
|
14348
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14349
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
|
|
14350
|
+
nodeId: pending.nodeId,
|
|
14351
|
+
meshId: pending.meshId,
|
|
14352
|
+
event: pending.event
|
|
14353
|
+
}, force ? "force-inject" : "inject");
|
|
14211
14354
|
coordinator.onEvent("send_message", {
|
|
14212
14355
|
input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
|
|
14213
14356
|
...force ? { force: true } : {}
|
|
@@ -14266,6 +14409,13 @@ function recoverStrandedAssignedDispatches(meshId, store) {
|
|
|
14266
14409
|
});
|
|
14267
14410
|
if (reclaimed) {
|
|
14268
14411
|
LOG.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})`);
|
|
14412
|
+
traceMeshEventDrop("assigned_stranded_reclaim", {
|
|
14413
|
+
taskId: row.id,
|
|
14414
|
+
sessionId: row.assignedSessionId,
|
|
14415
|
+
nodeId: row.assignedNodeId,
|
|
14416
|
+
meshId,
|
|
14417
|
+
event: "agent:generating_completed"
|
|
14418
|
+
}, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
|
|
14269
14419
|
}
|
|
14270
14420
|
}
|
|
14271
14421
|
}
|
|
@@ -14425,6 +14575,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14425
14575
|
try {
|
|
14426
14576
|
queuePendingMeshCoordinatorEvent(pending);
|
|
14427
14577
|
LOG.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
|
|
14578
|
+
traceMeshEventDrop("strict_route_hold", {
|
|
14579
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14580
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14581
|
+
nodeId: pending.nodeId,
|
|
14582
|
+
meshId,
|
|
14583
|
+
event: pending.event
|
|
14584
|
+
}, `coordinatorSession=${wantSession} not live`);
|
|
14428
14585
|
} catch (e) {
|
|
14429
14586
|
LOG.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
|
|
14430
14587
|
}
|
|
@@ -14448,6 +14605,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14448
14605
|
}
|
|
14449
14606
|
});
|
|
14450
14607
|
LOG.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
|
|
14608
|
+
traceMeshEventDrop("strict_route_expired", {
|
|
14609
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14610
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14611
|
+
nodeId: pending.nodeId,
|
|
14612
|
+
meshId,
|
|
14613
|
+
event: pending.event
|
|
14614
|
+
}, `coordinatorSession=${wantSession} never returned`);
|
|
14451
14615
|
} catch (e) {
|
|
14452
14616
|
LOG.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
14453
14617
|
}
|
|
@@ -14459,15 +14623,24 @@ async function retryUnresolvedDelegateForwards(components) {
|
|
|
14459
14623
|
const entries = peekUnresolvedDelegateForwards();
|
|
14460
14624
|
if (entries.length === 0) return;
|
|
14461
14625
|
for (const entry of entries) {
|
|
14626
|
+
const entryTraceCtx = {
|
|
14627
|
+
taskId: entry.payload.taskId,
|
|
14628
|
+
sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
|
|
14629
|
+
nodeId: readNonEmptyString2(entry.payload.nodeId),
|
|
14630
|
+
event: readNonEmptyString2(entry.payload.event)
|
|
14631
|
+
};
|
|
14462
14632
|
let result;
|
|
14463
14633
|
try {
|
|
14634
|
+
traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
|
|
14464
14635
|
result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
|
|
14465
14636
|
} catch (e) {
|
|
14466
14637
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
|
|
14638
|
+
traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
|
|
14467
14639
|
continue;
|
|
14468
14640
|
}
|
|
14469
14641
|
if (result && result.success === false) {
|
|
14470
14642
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
|
|
14643
|
+
traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14471
14644
|
continue;
|
|
14472
14645
|
}
|
|
14473
14646
|
ackUnresolvedDelegateForward(entry.id);
|
|
@@ -14709,6 +14882,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14709
14882
|
init_mesh_events_coordinator();
|
|
14710
14883
|
init_mesh_unresolved_forward_outbox();
|
|
14711
14884
|
init_mesh_events_utils();
|
|
14885
|
+
init_mesh_event_trace();
|
|
14712
14886
|
init_dist();
|
|
14713
14887
|
init_mesh_work_queue();
|
|
14714
14888
|
init_mesh_ledger();
|
|
@@ -15544,8 +15718,8 @@ function saveProvidersActive(file) {
|
|
|
15544
15718
|
}
|
|
15545
15719
|
function isValidSource(x) {
|
|
15546
15720
|
if (!x || typeof x !== "object") return false;
|
|
15547
|
-
const
|
|
15548
|
-
return typeof
|
|
15721
|
+
const s2 = x;
|
|
15722
|
+
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";
|
|
15549
15723
|
}
|
|
15550
15724
|
function deriveSourceName(url) {
|
|
15551
15725
|
const m = url.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -15601,7 +15775,7 @@ function inventoryExternalSources() {
|
|
|
15601
15775
|
}
|
|
15602
15776
|
function sourcesProviding(category, type) {
|
|
15603
15777
|
const inventory = inventoryExternalSources();
|
|
15604
|
-
return inventory.filter((
|
|
15778
|
+
return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
|
|
15605
15779
|
}
|
|
15606
15780
|
function resolveActiveSource(category, type, activeFile) {
|
|
15607
15781
|
const candidates = sourcesProviding(category, type);
|
|
@@ -15808,10 +15982,10 @@ function compileSettledPromptMatchers(spec) {
|
|
|
15808
15982
|
const footers = (spec.withFooter ?? []).map((f) => {
|
|
15809
15983
|
if (f.kind === "regex") {
|
|
15810
15984
|
const re = compile2(f.pattern, f.flags ?? "i");
|
|
15811
|
-
return { test: (
|
|
15985
|
+
return { test: (s2) => re.test(s2) };
|
|
15812
15986
|
}
|
|
15813
15987
|
const needle = f.pattern.toLowerCase();
|
|
15814
|
-
return { test: (
|
|
15988
|
+
return { test: (s2) => s2.toLowerCase().includes(needle) };
|
|
15815
15989
|
});
|
|
15816
15990
|
return { prompt, footers };
|
|
15817
15991
|
}
|
|
@@ -16685,7 +16859,7 @@ var init_cli_state_engine = __esm({
|
|
|
16685
16859
|
}
|
|
16686
16860
|
resolveModal(buttonIndex) {
|
|
16687
16861
|
const snap = this.transport.getSnapshot();
|
|
16688
|
-
const parseApproval = typeof this.transport.runParseApproval === "function" ? (
|
|
16862
|
+
const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
|
|
16689
16863
|
let modal = this.activeModal ?? parseApproval(snap);
|
|
16690
16864
|
if (!modal && this.runner.hasParseSession()) {
|
|
16691
16865
|
try {
|
|
@@ -19374,22 +19548,23 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19374
19548
|
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]));
|
|
19375
19549
|
let idx = -1;
|
|
19376
19550
|
for (const c of candidates) {
|
|
19551
|
+
let candIdx = -1;
|
|
19377
19552
|
if (sec.anchor_last) {
|
|
19378
19553
|
for (let i = total - 1; i >= 0; i--) {
|
|
19379
19554
|
if (matchesCandidate(c, i)) {
|
|
19380
|
-
|
|
19555
|
+
candIdx = i;
|
|
19381
19556
|
break;
|
|
19382
19557
|
}
|
|
19383
19558
|
}
|
|
19384
19559
|
} else {
|
|
19385
19560
|
for (let i = 0; i < total; i++) {
|
|
19386
19561
|
if (matchesCandidate(c, i)) {
|
|
19387
|
-
|
|
19562
|
+
candIdx = i;
|
|
19388
19563
|
break;
|
|
19389
19564
|
}
|
|
19390
19565
|
}
|
|
19391
19566
|
}
|
|
19392
|
-
if (
|
|
19567
|
+
if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
|
|
19393
19568
|
}
|
|
19394
19569
|
if (idx !== -1) {
|
|
19395
19570
|
from = idx;
|
|
@@ -19441,7 +19616,7 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19441
19616
|
}
|
|
19442
19617
|
function sectionText(sections, sectionId, fullScreen) {
|
|
19443
19618
|
if (!sectionId) return fullScreen;
|
|
19444
|
-
const found = sections.find((
|
|
19619
|
+
const found = sections.find((s2) => s2.id === sectionId);
|
|
19445
19620
|
return found ? found.text : "";
|
|
19446
19621
|
}
|
|
19447
19622
|
function isRegexCondition(c) {
|
|
@@ -19609,10 +19784,10 @@ function isV4Spec(raw) {
|
|
|
19609
19784
|
return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
|
|
19610
19785
|
}
|
|
19611
19786
|
function initialState(spec) {
|
|
19612
|
-
return spec.states.find((
|
|
19787
|
+
return spec.states.find((s2) => s2.initial) ?? spec.states[0];
|
|
19613
19788
|
}
|
|
19614
19789
|
function stateById(spec, id) {
|
|
19615
|
-
return spec.states.find((
|
|
19790
|
+
return spec.states.find((s2) => s2.id === id);
|
|
19616
19791
|
}
|
|
19617
19792
|
function outgoingTransitions(spec, stateId) {
|
|
19618
19793
|
const matches = spec.transitions.filter((t) => {
|
|
@@ -19701,7 +19876,17 @@ function evalCond(cond, sections, fullScreen, cursor, prevLines, clock, legacyTr
|
|
|
19701
19876
|
const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
|
|
19702
19877
|
const kind = isRegex(cond) ? "regex" : "changed";
|
|
19703
19878
|
const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
|
|
19704
|
-
|
|
19879
|
+
let matchedText;
|
|
19880
|
+
if (result && isRegex(cond)) {
|
|
19881
|
+
try {
|
|
19882
|
+
const hay = sectionText(sections, cond.section, fullScreen);
|
|
19883
|
+
const re = new RegExp(cond.matches, cond.flags ?? "i");
|
|
19884
|
+
const m = re.exec(hay);
|
|
19885
|
+
if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
|
|
19886
|
+
} catch {
|
|
19887
|
+
}
|
|
19888
|
+
}
|
|
19889
|
+
return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
|
|
19705
19890
|
}
|
|
19706
19891
|
return { kind: "all", result: false, detail: "unknown condition" };
|
|
19707
19892
|
}
|
|
@@ -19816,17 +20001,17 @@ function validateFsmSpec(raw) {
|
|
|
19816
20001
|
}
|
|
19817
20002
|
const ids = /* @__PURE__ */ new Set();
|
|
19818
20003
|
let initialCount = 0;
|
|
19819
|
-
for (const [i,
|
|
19820
|
-
if (!
|
|
20004
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20005
|
+
if (!s2.id) {
|
|
19821
20006
|
errs.push(`states[${i}].id is required`);
|
|
19822
20007
|
continue;
|
|
19823
20008
|
}
|
|
19824
|
-
if (ids.has(
|
|
19825
|
-
ids.add(
|
|
19826
|
-
if (!
|
|
19827
|
-
if (
|
|
19828
|
-
if (
|
|
19829
|
-
errs.push(`states[${i}].status "${
|
|
20009
|
+
if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
|
|
20010
|
+
ids.add(s2.id);
|
|
20011
|
+
if (!s2.label) errs.push(`states[${i}].label is required`);
|
|
20012
|
+
if (s2.initial) initialCount += 1;
|
|
20013
|
+
if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
|
|
20014
|
+
errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
|
|
19830
20015
|
}
|
|
19831
20016
|
}
|
|
19832
20017
|
if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
|
|
@@ -19842,10 +20027,10 @@ function validateFsmSpec(raw) {
|
|
|
19842
20027
|
else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
|
|
19843
20028
|
if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
|
|
19844
20029
|
}
|
|
19845
|
-
for (const [i,
|
|
19846
|
-
const sec =
|
|
20030
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20031
|
+
const sec = s2.extract?.title?.section;
|
|
19847
20032
|
if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
|
|
19848
|
-
const bsec =
|
|
20033
|
+
const bsec = s2.extract?.buttons?.section;
|
|
19849
20034
|
if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
|
|
19850
20035
|
}
|
|
19851
20036
|
return errs;
|
|
@@ -27440,6 +27625,42 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
27440
27625
|
return fn() || null;
|
|
27441
27626
|
}
|
|
27442
27627
|
|
|
27628
|
+
// src/providers/manual-attendance.ts
|
|
27629
|
+
var AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS = 6e4;
|
|
27630
|
+
var ManualAttendanceTracker = class {
|
|
27631
|
+
constructor(suppressMs = AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS) {
|
|
27632
|
+
this.suppressMs = suppressMs;
|
|
27633
|
+
}
|
|
27634
|
+
lastInteractionAt = 0;
|
|
27635
|
+
/** Record that a human just drove this session by hand. */
|
|
27636
|
+
note(now = Date.now()) {
|
|
27637
|
+
this.lastInteractionAt = now;
|
|
27638
|
+
}
|
|
27639
|
+
/** True while a manual interaction is recent enough to suppress auto-approve. */
|
|
27640
|
+
isAttended(now = Date.now()) {
|
|
27641
|
+
return this.lastInteractionAt > 0 && now - this.lastInteractionAt < this.suppressMs;
|
|
27642
|
+
}
|
|
27643
|
+
/**
|
|
27644
|
+
* Milliseconds remaining in the current suppression window, or 0 when not
|
|
27645
|
+
* attended. Used to re-arm a re-check timer so auto-approve fires the moment
|
|
27646
|
+
* the window lapses even if the PTY/agent has since gone silent.
|
|
27647
|
+
*/
|
|
27648
|
+
remainingMs(now = Date.now()) {
|
|
27649
|
+
if (this.lastInteractionAt <= 0) return 0;
|
|
27650
|
+
return Math.max(0, this.suppressMs - (now - this.lastInteractionAt));
|
|
27651
|
+
}
|
|
27652
|
+
};
|
|
27653
|
+
var MANUAL_ATTENDANCE_COMMANDS = /* @__PURE__ */ new Set([
|
|
27654
|
+
"select_session",
|
|
27655
|
+
"open_panel",
|
|
27656
|
+
"invoke_provider_script",
|
|
27657
|
+
"set_mode",
|
|
27658
|
+
"change_model",
|
|
27659
|
+
"set_thought_level",
|
|
27660
|
+
"resolve_action",
|
|
27661
|
+
"pty_input"
|
|
27662
|
+
]);
|
|
27663
|
+
|
|
27443
27664
|
// src/commands/chat-commands.ts
|
|
27444
27665
|
var fs7 = __toESM(require("fs"));
|
|
27445
27666
|
var os10 = __toESM(require("os"));
|
|
@@ -31779,11 +32000,38 @@ var DaemonCommandHandler = class {
|
|
|
31779
32000
|
setAgentStreamManager(manager) {
|
|
31780
32001
|
this._agentStream = manager;
|
|
31781
32002
|
}
|
|
32003
|
+
/**
|
|
32004
|
+
* When a command in the manual-attendance set arrives for a session this
|
|
32005
|
+
* daemon hosts, stamp the live instance so auto-approve holds while the user
|
|
32006
|
+
* drives the session by hand. Provider-common: the signal is the command
|
|
32007
|
+
* (foreground select_session / open_panel, controlbar invoke_provider_script
|
|
32008
|
+
* / set_mode / change_model / set_thought_level, manual resolve_action,
|
|
32009
|
+
* pty_input), never any CLI-specific modal text — so it works identically for
|
|
32010
|
+
* every CLI/ACP provider. send_chat is deliberately excluded because a
|
|
32011
|
+
* coordinator delegating a task to a worker also uses send_chat; counting it
|
|
32012
|
+
* would wrongly suppress the worker's delegated auto-approve. For a remote
|
|
32013
|
+
* mesh worker session the controlbar commands are forwarded to the owning
|
|
32014
|
+
* worker daemon, which runs this same hook there, so attendance is recorded
|
|
32015
|
+
* on the daemon that actually hosts the instance.
|
|
32016
|
+
*/
|
|
32017
|
+
noteManualAttendanceIfApplicable(cmd, args) {
|
|
32018
|
+
if (!MANUAL_ATTENDANCE_COMMANDS.has(cmd)) return;
|
|
32019
|
+
const sessionId = this._currentRoute.session?.sessionId || (typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "");
|
|
32020
|
+
if (!sessionId) return;
|
|
32021
|
+
const session = this._ctx.sessionRegistry?.get(sessionId);
|
|
32022
|
+
const instanceKey = session?.adapterKey || session?.instanceKey || sessionId;
|
|
32023
|
+
const instance = this._ctx.instanceManager?.getInstance(instanceKey);
|
|
32024
|
+
try {
|
|
32025
|
+
instance?.noteManualInteraction?.();
|
|
32026
|
+
} catch {
|
|
32027
|
+
}
|
|
32028
|
+
}
|
|
31782
32029
|
// ─── Command Dispatcher ──────────────────────────
|
|
31783
32030
|
async handle(cmd, args) {
|
|
31784
32031
|
this._currentRoute = this.resolveRoute(args);
|
|
31785
32032
|
const startedAt = Date.now();
|
|
31786
32033
|
this.logCommandStart(cmd, args);
|
|
32034
|
+
this.noteManualAttendanceIfApplicable(cmd, args);
|
|
31787
32035
|
let result;
|
|
31788
32036
|
if (isGitCommandName(cmd)) {
|
|
31789
32037
|
result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
|
|
@@ -32518,10 +32766,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32518
32766
|
const path42 = require("path");
|
|
32519
32767
|
const { spawnSync: spawnSync2 } = require("child_process");
|
|
32520
32768
|
const file = ext.loadExternalSources();
|
|
32521
|
-
if (file.sources.some((
|
|
32769
|
+
if (file.sources.some((s2) => s2.name === requestedName)) {
|
|
32522
32770
|
return { success: false, error: `source name "${requestedName}" is already registered` };
|
|
32523
32771
|
}
|
|
32524
|
-
if (file.sources.some((
|
|
32772
|
+
if (file.sources.some((s2) => s2.url === url && s2.ref === ref)) {
|
|
32525
32773
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
32526
32774
|
}
|
|
32527
32775
|
const sourceDir = path42.join(ext.externalRoot(), requestedName);
|
|
@@ -32583,7 +32831,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32583
32831
|
const fs32 = require("fs");
|
|
32584
32832
|
const path42 = require("path");
|
|
32585
32833
|
const file = ext.loadExternalSources();
|
|
32586
|
-
const match = file.sources.find((
|
|
32834
|
+
const match = file.sources.find((s2) => s2.name === name);
|
|
32587
32835
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
32588
32836
|
const sourceDir = path42.join(ext.externalRoot(), name);
|
|
32589
32837
|
if (fs32.existsSync(sourceDir)) {
|
|
@@ -32595,7 +32843,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32595
32843
|
}
|
|
32596
32844
|
ext.saveExternalSources({
|
|
32597
32845
|
schema: 1,
|
|
32598
|
-
sources: file.sources.filter((
|
|
32846
|
+
sources: file.sources.filter((s2) => s2.name !== name)
|
|
32599
32847
|
});
|
|
32600
32848
|
const active = ext.loadProvidersActive();
|
|
32601
32849
|
const filteredActive = {};
|
|
@@ -32619,10 +32867,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32619
32867
|
const file = ext.loadExternalSources();
|
|
32620
32868
|
const inventory = ext.inventoryExternalSources();
|
|
32621
32869
|
const active = ext.loadProvidersActive();
|
|
32622
|
-
const sources = file.sources.map((
|
|
32623
|
-
const inv = inventory.find((e) => e.sourceName ===
|
|
32870
|
+
const sources = file.sources.map((s2) => {
|
|
32871
|
+
const inv = inventory.find((e) => e.sourceName === s2.name);
|
|
32624
32872
|
return {
|
|
32625
|
-
...
|
|
32873
|
+
...s2,
|
|
32626
32874
|
providers: inv?.providers ?? {}
|
|
32627
32875
|
};
|
|
32628
32876
|
});
|
|
@@ -32799,6 +33047,21 @@ var path21 = __toESM(require("path"));
|
|
|
32799
33047
|
// src/providers/spec/adapter.ts
|
|
32800
33048
|
init_terminal_screen();
|
|
32801
33049
|
var import_session_host_core6 = require("@adhdev/session-host-core");
|
|
33050
|
+
var MAX_PTY_EVENTS = 300;
|
|
33051
|
+
var EVENT_CONTENT_CAP = 240;
|
|
33052
|
+
function escapeControl(text) {
|
|
33053
|
+
return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
|
|
33054
|
+
const code = ch.charCodeAt(0);
|
|
33055
|
+
if (ch === "\r") return "\\r";
|
|
33056
|
+
if (ch === "\n") return "\\n";
|
|
33057
|
+
if (ch === " ") return "\\t";
|
|
33058
|
+
if (code === 27) return "\\x1b";
|
|
33059
|
+
return "\\x" + code.toString(16).padStart(2, "0");
|
|
33060
|
+
});
|
|
33061
|
+
}
|
|
33062
|
+
function capPreview(text) {
|
|
33063
|
+
return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
|
|
33064
|
+
}
|
|
32802
33065
|
var TerminalAdapter = class {
|
|
32803
33066
|
constructor(opts, handlers) {
|
|
32804
33067
|
this.opts = opts;
|
|
@@ -32825,6 +33088,9 @@ var TerminalAdapter = class {
|
|
|
32825
33088
|
screenTimer = null;
|
|
32826
33089
|
tickTimer = null;
|
|
32827
33090
|
lastScreen = "";
|
|
33091
|
+
/** Debug-only ring buffer of PTY input/output/resize/cursor events. */
|
|
33092
|
+
events = [];
|
|
33093
|
+
lastCursorKey = "";
|
|
32828
33094
|
start() {
|
|
32829
33095
|
const env = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
|
|
32830
33096
|
this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
|
|
@@ -32833,10 +33099,12 @@ var TerminalAdapter = class {
|
|
|
32833
33099
|
cols: this.cols,
|
|
32834
33100
|
rows: this.rows
|
|
32835
33101
|
});
|
|
33102
|
+
this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
|
|
32836
33103
|
this.handlers.init?.({ pid: this.pty.pid });
|
|
32837
33104
|
this.pty.onData((chunk) => this.onChunk(chunk));
|
|
32838
33105
|
this.pty.onExit((info) => {
|
|
32839
33106
|
this.stopTimers();
|
|
33107
|
+
this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
|
|
32840
33108
|
this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
|
|
32841
33109
|
this.pty = null;
|
|
32842
33110
|
});
|
|
@@ -32847,6 +33115,7 @@ var TerminalAdapter = class {
|
|
|
32847
33115
|
resize(cols, rows) {
|
|
32848
33116
|
this.cols = cols;
|
|
32849
33117
|
this.rows = rows;
|
|
33118
|
+
this.recordEvent("resize", `${cols}x${rows}`);
|
|
32850
33119
|
this.pty?.resize(cols, rows);
|
|
32851
33120
|
this.screen.resize(rows, cols);
|
|
32852
33121
|
}
|
|
@@ -32867,8 +33136,21 @@ var TerminalAdapter = class {
|
|
|
32867
33136
|
return { row: pos.row, col: pos.col };
|
|
32868
33137
|
}
|
|
32869
33138
|
send_keys(text) {
|
|
33139
|
+
this.recordEvent("input", capPreview(escapeControl(text)), text.length);
|
|
32870
33140
|
this.pty?.write(text);
|
|
32871
33141
|
}
|
|
33142
|
+
/** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
|
|
33143
|
+
* first. Pure observation — never consulted by the FSM. */
|
|
33144
|
+
getEventTimeline(limit = MAX_PTY_EVENTS) {
|
|
33145
|
+
const n = Math.max(0, Math.min(limit, this.events.length));
|
|
33146
|
+
return this.events.slice(this.events.length - n);
|
|
33147
|
+
}
|
|
33148
|
+
recordEvent(kind, content, bytes) {
|
|
33149
|
+
const ev = { ts: Date.now(), kind, content };
|
|
33150
|
+
if (typeof bytes === "number") ev.bytes = bytes;
|
|
33151
|
+
this.events.push(ev);
|
|
33152
|
+
if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
|
|
33153
|
+
}
|
|
32872
33154
|
kill() {
|
|
32873
33155
|
this.stopTimers();
|
|
32874
33156
|
try {
|
|
@@ -32879,6 +33161,7 @@ var TerminalAdapter = class {
|
|
|
32879
33161
|
this.screen.dispose();
|
|
32880
33162
|
}
|
|
32881
33163
|
onChunk(chunk) {
|
|
33164
|
+
this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
|
|
32882
33165
|
try {
|
|
32883
33166
|
this.handlers.on_pty_data?.(chunk);
|
|
32884
33167
|
} catch {
|
|
@@ -32888,6 +33171,12 @@ var TerminalAdapter = class {
|
|
|
32888
33171
|
this.screenTimer = setTimeout(() => {
|
|
32889
33172
|
this.screenTimer = null;
|
|
32890
33173
|
const snap = this.computeScreen();
|
|
33174
|
+
const cur = this.screen.getCursorPosition();
|
|
33175
|
+
const curKey = `${cur.row},${cur.col}`;
|
|
33176
|
+
if (curKey !== this.lastCursorKey) {
|
|
33177
|
+
this.lastCursorKey = curKey;
|
|
33178
|
+
this.recordEvent("cursor", `(${cur.row},${cur.col})`);
|
|
33179
|
+
}
|
|
32891
33180
|
if (snap === this.lastScreen) return;
|
|
32892
33181
|
this.lastScreen = snap;
|
|
32893
33182
|
try {
|
|
@@ -32972,20 +33261,40 @@ function applyPreLaunchTrust(trust, workingDir) {
|
|
|
32972
33261
|
|
|
32973
33262
|
// src/providers/spec/fsm-driver.ts
|
|
32974
33263
|
init_logger();
|
|
32975
|
-
function countNewlines(
|
|
33264
|
+
function countNewlines(s2) {
|
|
32976
33265
|
let n = 0;
|
|
32977
|
-
for (let i = 0; i <
|
|
33266
|
+
for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
|
|
32978
33267
|
return n;
|
|
32979
33268
|
}
|
|
32980
33269
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
32981
33270
|
var WIN32_SUBMIT_RESEND_GAP_MS = 350;
|
|
32982
33271
|
var WIN32_SUBMIT_MAX_RESENDS = 14;
|
|
33272
|
+
var WIN32_SUBMIT_SETTLE_MS = 500;
|
|
33273
|
+
var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
|
|
33274
|
+
var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
|
|
33275
|
+
var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
|
|
33276
|
+
var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
|
|
32983
33277
|
function resolveSubmitDelayMs(specBeforeSubmit, text) {
|
|
32984
33278
|
const lines = countNewlines(text);
|
|
32985
33279
|
const linesBonus = Math.min(800, lines * 80);
|
|
32986
33280
|
const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
|
|
32987
33281
|
return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
|
|
32988
33282
|
}
|
|
33283
|
+
function chunkPreservingSurrogates(text, size) {
|
|
33284
|
+
const chunks = [];
|
|
33285
|
+
let offset = 0;
|
|
33286
|
+
while (offset < text.length) {
|
|
33287
|
+
let end = Math.min(text.length, offset + size);
|
|
33288
|
+
if (end < text.length) {
|
|
33289
|
+
const code = text.charCodeAt(end - 1);
|
|
33290
|
+
if (code >= 55296 && code <= 56319) end -= 1;
|
|
33291
|
+
}
|
|
33292
|
+
if (end <= offset) end = Math.min(text.length, offset + size);
|
|
33293
|
+
chunks.push(text.slice(offset, end));
|
|
33294
|
+
offset = end;
|
|
33295
|
+
}
|
|
33296
|
+
return chunks;
|
|
33297
|
+
}
|
|
32989
33298
|
function guessExt(mime) {
|
|
32990
33299
|
if (/png/i.test(mime)) return ".png";
|
|
32991
33300
|
if (/jpe?g/i.test(mime)) return ".jpg";
|
|
@@ -33001,7 +33310,10 @@ var FsmDriver = class {
|
|
|
33001
33310
|
this.buildAdapterOpts(),
|
|
33002
33311
|
{
|
|
33003
33312
|
init: () => this.emitInitialState(),
|
|
33004
|
-
on_pty_data: (chunk) =>
|
|
33313
|
+
on_pty_data: (chunk) => {
|
|
33314
|
+
this.lastPtyDataAt = Date.now();
|
|
33315
|
+
this.emit({ kind: "pty_data", chunk });
|
|
33316
|
+
},
|
|
33005
33317
|
on_screen_changed: () => this.reevaluate(),
|
|
33006
33318
|
on_exit: ({ exitCode }) => this.handleExit(exitCode)
|
|
33007
33319
|
}
|
|
@@ -33035,6 +33347,16 @@ var FsmDriver = class {
|
|
|
33035
33347
|
* WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
|
|
33036
33348
|
* leaves idle (submitted) or the resend budget is spent. */
|
|
33037
33349
|
win32SubmitTimer = null;
|
|
33350
|
+
/** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
|
|
33351
|
+
* on_pty_data — including the echo of text written into the composer — so the
|
|
33352
|
+
* win32 submit settle-gate can tell when input has finished landing. */
|
|
33353
|
+
lastPtyDataAt = 0;
|
|
33354
|
+
/** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
|
|
33355
|
+
* the gap between writing a chunk and its echo so the settle-gate does not
|
|
33356
|
+
* declare "quiet" mid-write. */
|
|
33357
|
+
lastWin32WriteAt = 0;
|
|
33358
|
+
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
33359
|
+
win32WriteTimer = null;
|
|
33038
33360
|
currentEval = null;
|
|
33039
33361
|
stateHistory = [];
|
|
33040
33362
|
prevStateAt = 0;
|
|
@@ -33155,6 +33477,10 @@ var FsmDriver = class {
|
|
|
33155
33477
|
clearTimeout(this.win32SubmitTimer);
|
|
33156
33478
|
this.win32SubmitTimer = null;
|
|
33157
33479
|
}
|
|
33480
|
+
if (this.win32WriteTimer) {
|
|
33481
|
+
clearTimeout(this.win32WriteTimer);
|
|
33482
|
+
this.win32WriteTimer = null;
|
|
33483
|
+
}
|
|
33158
33484
|
this.specWatcher?.close();
|
|
33159
33485
|
this.adapter.kill();
|
|
33160
33486
|
}
|
|
@@ -33185,11 +33511,15 @@ var FsmDriver = class {
|
|
|
33185
33511
|
getFsmSnapshotHistory() {
|
|
33186
33512
|
return this.fsmSnapshotHistory;
|
|
33187
33513
|
}
|
|
33514
|
+
/** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
|
|
33515
|
+
getEventTimeline(limit) {
|
|
33516
|
+
return this.adapter.getEventTimeline(limit);
|
|
33517
|
+
}
|
|
33188
33518
|
getSections() {
|
|
33189
33519
|
try {
|
|
33190
33520
|
const screen = this.adapter.snapshot();
|
|
33191
33521
|
const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
33192
|
-
return resolveSections(this.spec.sections ?? {}, lines).map((
|
|
33522
|
+
return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
|
|
33193
33523
|
} catch {
|
|
33194
33524
|
return null;
|
|
33195
33525
|
}
|
|
@@ -33567,7 +33897,7 @@ var FsmDriver = class {
|
|
|
33567
33897
|
const perChar = sm.delay_ms_per_char ?? 0;
|
|
33568
33898
|
const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
|
|
33569
33899
|
if (process.platform === "win32") {
|
|
33570
|
-
this.
|
|
33900
|
+
this.writeWin32Body(text);
|
|
33571
33901
|
this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
|
|
33572
33902
|
return;
|
|
33573
33903
|
}
|
|
@@ -33593,20 +33923,72 @@ var FsmDriver = class {
|
|
|
33593
33923
|
const st = stateById(this.spec, this.currentStateId);
|
|
33594
33924
|
return st ? statusForState(st) : "idle";
|
|
33595
33925
|
}
|
|
33926
|
+
/** Record a win32 body write so the settle-gate counts it as input activity
|
|
33927
|
+
* even before the echo arrives. */
|
|
33928
|
+
markWin32Write() {
|
|
33929
|
+
this.lastWin32WriteAt = Date.now();
|
|
33930
|
+
}
|
|
33931
|
+
/** Most recent win32 input activity — a write we issued OR a PTY output chunk
|
|
33932
|
+
* (echo). The submit settle-gate waits for this to go quiet. */
|
|
33933
|
+
lastWin32InputActivityAt() {
|
|
33934
|
+
return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
|
|
33935
|
+
}
|
|
33596
33936
|
/**
|
|
33597
|
-
*
|
|
33598
|
-
*
|
|
33599
|
-
* a
|
|
33600
|
-
*
|
|
33601
|
-
*
|
|
33602
|
-
*
|
|
33603
|
-
|
|
33937
|
+
* Write the message body to the PTY for win32, paced into bounded chunks. A
|
|
33938
|
+
* single unbounded ConPTY write can overflow the input pipe and drop leading
|
|
33939
|
+
* bytes; splitting it with a short inter-chunk gap keeps the console input
|
|
33940
|
+
* buffer from overflowing. Small bodies still go out in a single write. Each
|
|
33941
|
+
* chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
|
|
33942
|
+
* the final chunk is out and echoed.
|
|
33943
|
+
*/
|
|
33944
|
+
writeWin32Body(text) {
|
|
33945
|
+
if (this.win32WriteTimer) {
|
|
33946
|
+
clearTimeout(this.win32WriteTimer);
|
|
33947
|
+
this.win32WriteTimer = null;
|
|
33948
|
+
}
|
|
33949
|
+
if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
|
|
33950
|
+
this.markWin32Write();
|
|
33951
|
+
this.adapter.send_keys(text);
|
|
33952
|
+
return;
|
|
33953
|
+
}
|
|
33954
|
+
const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
|
|
33955
|
+
let idx = 0;
|
|
33956
|
+
const writeNext = () => {
|
|
33957
|
+
this.win32WriteTimer = null;
|
|
33958
|
+
if (idx >= chunks.length) return;
|
|
33959
|
+
this.markWin32Write();
|
|
33960
|
+
this.adapter.send_keys(chunks[idx]);
|
|
33961
|
+
idx += 1;
|
|
33962
|
+
if (idx < chunks.length) {
|
|
33963
|
+
this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
|
|
33964
|
+
}
|
|
33965
|
+
};
|
|
33966
|
+
writeNext();
|
|
33967
|
+
}
|
|
33968
|
+
/**
|
|
33969
|
+
* win32 submit. Two phases:
|
|
33970
|
+
*
|
|
33971
|
+
* Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
|
|
33972
|
+
* for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
|
|
33973
|
+
* (possibly multi-KB / multiline) body has finished arriving in the composer
|
|
33974
|
+
* and echoing. Honors an initial minimum delay and is bounded by
|
|
33975
|
+
* WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
|
|
33976
|
+
* This is what stops a long message from being submitted half-arrived (its
|
|
33977
|
+
* leading lines lost). A short message settles almost immediately.
|
|
33978
|
+
*
|
|
33979
|
+
* Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
|
|
33980
|
+
* if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
|
|
33981
|
+
* newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
|
|
33982
|
+
* (a stale/edge status never suppresses it); resends are gated on still being
|
|
33983
|
+
* idle and stop the instant the agent leaves idle (submitted → generating /
|
|
33984
|
+
* approval). This preserves the win32 lone-CR-swallow handling.
|
|
33604
33985
|
*/
|
|
33605
33986
|
scheduleWin32Submit(submitKey, initialDelayMs) {
|
|
33606
33987
|
if (this.win32SubmitTimer) {
|
|
33607
33988
|
clearTimeout(this.win32SubmitTimer);
|
|
33608
33989
|
this.win32SubmitTimer = null;
|
|
33609
33990
|
}
|
|
33991
|
+
const startedAt = Date.now();
|
|
33610
33992
|
const fire = (attempt) => {
|
|
33611
33993
|
this.win32SubmitTimer = null;
|
|
33612
33994
|
this.adapter.send_keys(submitKey);
|
|
@@ -33619,8 +34001,20 @@ var FsmDriver = class {
|
|
|
33619
34001
|
fire(attempt + 1);
|
|
33620
34002
|
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
33621
34003
|
};
|
|
33622
|
-
|
|
33623
|
-
|
|
34004
|
+
const waitForSettle = () => {
|
|
34005
|
+
this.win32SubmitTimer = null;
|
|
34006
|
+
const now = Date.now();
|
|
34007
|
+
const quietFor = now - this.lastWin32InputActivityAt();
|
|
34008
|
+
const waited = now - startedAt;
|
|
34009
|
+
if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
|
|
34010
|
+
fire(0);
|
|
34011
|
+
return;
|
|
34012
|
+
}
|
|
34013
|
+
const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
|
|
34014
|
+
this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
|
|
34015
|
+
};
|
|
34016
|
+
if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
|
|
34017
|
+
else waitForSettle();
|
|
33624
34018
|
}
|
|
33625
34019
|
handleClickControl(controlId, payload) {
|
|
33626
34020
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
|
|
@@ -33733,7 +34127,8 @@ function summarizeTransition(t) {
|
|
|
33733
34127
|
return out;
|
|
33734
34128
|
}
|
|
33735
34129
|
function flattenCond(c, out, depth) {
|
|
33736
|
-
|
|
34130
|
+
const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
|
|
34131
|
+
out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
|
|
33737
34132
|
for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
|
|
33738
34133
|
}
|
|
33739
34134
|
function findStable(c) {
|
|
@@ -34451,8 +34846,8 @@ function projectToolBlock(block2, role, tmap) {
|
|
|
34451
34846
|
}
|
|
34452
34847
|
return null;
|
|
34453
34848
|
}
|
|
34454
|
-
function oneLine(
|
|
34455
|
-
const flat =
|
|
34849
|
+
function oneLine(s2, max) {
|
|
34850
|
+
const flat = s2.replace(/\s+/g, " ").trim();
|
|
34456
34851
|
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
34457
34852
|
}
|
|
34458
34853
|
function parseTimestamp(v) {
|
|
@@ -34472,10 +34867,10 @@ function parseTimestamp(v) {
|
|
|
34472
34867
|
return null;
|
|
34473
34868
|
}
|
|
34474
34869
|
function normalizeRole(r) {
|
|
34475
|
-
const
|
|
34476
|
-
if (
|
|
34477
|
-
if (
|
|
34478
|
-
if (
|
|
34870
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
34871
|
+
if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
|
|
34872
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
34873
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
34479
34874
|
return "system";
|
|
34480
34875
|
}
|
|
34481
34876
|
function stringifyContent(v) {
|
|
@@ -34523,18 +34918,18 @@ function compileWhere(src) {
|
|
|
34523
34918
|
return (record) => ors.some((ands) => ands.every((t) => evalTerm(t, record)));
|
|
34524
34919
|
}
|
|
34525
34920
|
function parseTerm(src) {
|
|
34526
|
-
let
|
|
34921
|
+
let s2 = src.trim();
|
|
34527
34922
|
let negate = false;
|
|
34528
|
-
if (
|
|
34923
|
+
if (s2.startsWith("!")) {
|
|
34529
34924
|
negate = true;
|
|
34530
|
-
|
|
34925
|
+
s2 = s2.slice(1).trim();
|
|
34531
34926
|
}
|
|
34532
|
-
const fnMatch =
|
|
34927
|
+
const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
|
|
34533
34928
|
if (fnMatch) {
|
|
34534
34929
|
const [, op2, pathExpr, litExpr] = fnMatch;
|
|
34535
34930
|
return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
|
|
34536
34931
|
}
|
|
34537
|
-
const opMatch =
|
|
34932
|
+
const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
|
|
34538
34933
|
if (!opMatch) return null;
|
|
34539
34934
|
const [, lhs, op, rhsRaw] = opMatch;
|
|
34540
34935
|
return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
|
|
@@ -34966,7 +35361,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34966
35361
|
try {
|
|
34967
35362
|
const sections = this.driver.getSections();
|
|
34968
35363
|
if (sectionId && sections) {
|
|
34969
|
-
const hit = sections.find((
|
|
35364
|
+
const hit = sections.find((s2) => s2.id === sectionId);
|
|
34970
35365
|
if (hit) return hit.text;
|
|
34971
35366
|
}
|
|
34972
35367
|
return this.driver.getScreen();
|
|
@@ -34981,7 +35376,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34981
35376
|
screen = this.driver.snapshot();
|
|
34982
35377
|
const driverSections = this.driver.getSections?.();
|
|
34983
35378
|
if (driverSections) {
|
|
34984
|
-
sections = Object.fromEntries(driverSections.map((
|
|
35379
|
+
sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
|
|
34985
35380
|
} else {
|
|
34986
35381
|
sections = this.readCurrentScreenSections(screen);
|
|
34987
35382
|
}
|
|
@@ -35027,6 +35422,10 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35027
35422
|
// answers "why did this rule fire" after the fact, unlike the live
|
|
35028
35423
|
// `fsm` field which only reflects the current instant.
|
|
35029
35424
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35425
|
+
// PTY input/output/resize/cursor event timeline (debug-only) so the
|
|
35426
|
+
// snapshot shows what we typed / what the PTY printed around each
|
|
35427
|
+
// status transition. Null for drivers without the timeline.
|
|
35428
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
35030
35429
|
// Extended fields
|
|
35031
35430
|
name: this.cliName,
|
|
35032
35431
|
status: this.getStatus().status,
|
|
@@ -35391,6 +35790,8 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35391
35790
|
// v4 FSM transition snapshot history — the captured pre-transition
|
|
35392
35791
|
// evaluation table at each transition (null for v3 specs).
|
|
35393
35792
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35793
|
+
// PTY input/output/resize/cursor event timeline (debug-only).
|
|
35794
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
35394
35795
|
messages,
|
|
35395
35796
|
committedMessages: messages
|
|
35396
35797
|
};
|
|
@@ -35435,6 +35836,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
|
|
|
35435
35836
|
|
|
35436
35837
|
// src/providers/cli-provider-instance.ts
|
|
35437
35838
|
init_logger();
|
|
35839
|
+
init_mesh_event_trace();
|
|
35438
35840
|
init_control_effects();
|
|
35439
35841
|
init_approval_utils();
|
|
35440
35842
|
init_provider_patch_state();
|
|
@@ -35737,6 +36139,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35737
36139
|
// a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
|
|
35738
36140
|
// brief generating flip does not immediately wipe the settle clock.
|
|
35739
36141
|
autoApproveInactiveSince = 0;
|
|
36142
|
+
// Provider-common manual-attendance signal: while a human is actively driving
|
|
36143
|
+
// this session from the dashboard, auto-approve holds so they can take manual
|
|
36144
|
+
// control. Background mesh workers are never attended → delegated auto-approve
|
|
36145
|
+
// is unaffected.
|
|
36146
|
+
manualAttendance = new ManualAttendanceTracker();
|
|
35740
36147
|
controlValues = {};
|
|
35741
36148
|
summaryMetadata = void 0;
|
|
35742
36149
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -36012,7 +36419,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36012
36419
|
}
|
|
36013
36420
|
getHotChatSessionState() {
|
|
36014
36421
|
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|
|
36015
|
-
const autoApproveActive = adapterStatus.status
|
|
36422
|
+
const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
|
|
36016
36423
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
|
|
36017
36424
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
|
|
36018
36425
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
@@ -36027,7 +36434,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36027
36434
|
}
|
|
36028
36435
|
getSessionModalState(sessionId) {
|
|
36029
36436
|
const adapterStatus = this.adapter.getStatus({ allowParse: true });
|
|
36030
|
-
const autoApproveActive = adapterStatus.status
|
|
36437
|
+
const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
|
|
36031
36438
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
|
|
36032
36439
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
|
|
36033
36440
|
const dirName = workingDirBasename(this.workingDir);
|
|
@@ -36108,7 +36515,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36108
36515
|
} catch {
|
|
36109
36516
|
return null;
|
|
36110
36517
|
}
|
|
36111
|
-
if (adapterStatus.status === "waiting_approval" && !this.
|
|
36518
|
+
if (adapterStatus.status === "waiting_approval" && !this.autoApproveEffectivelyActive(adapterStatus.status)) {
|
|
36112
36519
|
return "waiting_approval";
|
|
36113
36520
|
}
|
|
36114
36521
|
return null;
|
|
@@ -36481,6 +36888,23 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36481
36888
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
36482
36889
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|
|
36483
36890
|
}
|
|
36891
|
+
// EVTTRACE (observation-only): is this a mesh worker session whose completion
|
|
36892
|
+
// events must route to a coordinator? Used purely to gate trace logging so a
|
|
36893
|
+
// non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
|
|
36894
|
+
isMeshWorkerSession() {
|
|
36895
|
+
return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
|
|
36896
|
+
}
|
|
36897
|
+
// EVTTRACE correlation context for this session's completion lifecycle. taskId is
|
|
36898
|
+
// the primary grep anchor; instanceId is the session fallback.
|
|
36899
|
+
meshTraceCtx(event = "agent:generating_completed") {
|
|
36900
|
+
return {
|
|
36901
|
+
taskId: this.settings.meshActiveTaskId,
|
|
36902
|
+
sessionId: this.instanceId,
|
|
36903
|
+
nodeId: this.settings.meshNodeId,
|
|
36904
|
+
meshId: this.settings.meshNodeFor,
|
|
36905
|
+
event
|
|
36906
|
+
};
|
|
36907
|
+
}
|
|
36484
36908
|
flushCompletedDebounceIfFinalized() {
|
|
36485
36909
|
const pending = this.completedDebouncePending;
|
|
36486
36910
|
if (!pending) {
|
|
@@ -36501,24 +36925,33 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36501
36925
|
if (block2) {
|
|
36502
36926
|
const blockReason = block2.reason;
|
|
36503
36927
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
36504
|
-
|
|
36505
|
-
|
|
36928
|
+
const isTranscriptEvidenceGate = block2.allowTimeout === true;
|
|
36929
|
+
LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
36930
|
+
if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
|
|
36506
36931
|
if (pending.loggedBlockReason !== blockReason) {
|
|
36507
36932
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
36933
|
+
if (this.isMeshWorkerSession()) {
|
|
36934
|
+
traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
|
|
36935
|
+
}
|
|
36508
36936
|
pending.loggedBlockReason = blockReason;
|
|
36509
36937
|
}
|
|
36510
36938
|
this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
|
|
36511
36939
|
return;
|
|
36512
36940
|
}
|
|
36941
|
+
const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
|
|
36513
36942
|
const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
|
|
36514
36943
|
blockReason,
|
|
36515
36944
|
latestStatus,
|
|
36516
36945
|
latestVisibleStatus,
|
|
36517
36946
|
waitedMs,
|
|
36518
36947
|
pending,
|
|
36519
|
-
emittedAfterFinalizationTimeout
|
|
36948
|
+
emittedAfterFinalizationTimeout
|
|
36520
36949
|
});
|
|
36521
|
-
|
|
36950
|
+
completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
|
|
36951
|
+
LOG.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
|
|
36952
|
+
if (this.isMeshWorkerSession()) {
|
|
36953
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
|
|
36954
|
+
}
|
|
36522
36955
|
this.pushEvent({
|
|
36523
36956
|
event: "agent:generating_completed",
|
|
36524
36957
|
chatTitle: pending.chatTitle,
|
|
@@ -36541,6 +36974,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36541
36974
|
return;
|
|
36542
36975
|
}
|
|
36543
36976
|
LOG.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
|
|
36977
|
+
if (this.isMeshWorkerSession()) {
|
|
36978
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
|
|
36979
|
+
}
|
|
36544
36980
|
this.pushEvent({
|
|
36545
36981
|
event: "agent:generating_completed",
|
|
36546
36982
|
chatTitle: pending.chatTitle,
|
|
@@ -36554,6 +36990,18 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36554
36990
|
this.lastApprovalEventFingerprint = "";
|
|
36555
36991
|
}
|
|
36556
36992
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
36993
|
+
if (adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove() && this.manualAttendance.isAttended(now)) {
|
|
36994
|
+
this.lastAutoApprovalSignature = "";
|
|
36995
|
+
this.pendingAutoApprovalSignature = "";
|
|
36996
|
+
this.pendingAutoApprovalSince = 0;
|
|
36997
|
+
this.autoApproveInactiveSince = 0;
|
|
36998
|
+
if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
|
|
36999
|
+
this.autoApproveSettleTimer = setTimeout(() => {
|
|
37000
|
+
this.autoApproveSettleTimer = null;
|
|
37001
|
+
this.recheckAutoApproveSettled();
|
|
37002
|
+
}, this.manualAttendance.remainingMs(now) + 20);
|
|
37003
|
+
return false;
|
|
37004
|
+
}
|
|
36557
37005
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
36558
37006
|
if (!autoApproveActive) {
|
|
36559
37007
|
this.lastAutoApprovalSignature = "";
|
|
@@ -36767,6 +37215,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36767
37215
|
if (missingEvidence && !hasMeshContext) {
|
|
36768
37216
|
LOG.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
|
|
36769
37217
|
} else {
|
|
37218
|
+
if (this.isMeshWorkerSession()) {
|
|
37219
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
|
|
37220
|
+
}
|
|
36770
37221
|
this.pushEvent({
|
|
36771
37222
|
event: "agent:generating_completed",
|
|
36772
37223
|
chatTitle,
|
|
@@ -36843,6 +37294,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36843
37294
|
const monitorParsedStatus = parsedStatus;
|
|
36844
37295
|
for (const me of monitorEvents) {
|
|
36845
37296
|
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
37297
|
+
if (this.isMeshWorkerSession()) {
|
|
37298
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
|
|
37299
|
+
}
|
|
36846
37300
|
this.pushEvent({
|
|
36847
37301
|
event: "agent:generating_completed",
|
|
36848
37302
|
chatTitle,
|
|
@@ -37019,6 +37473,21 @@ ${effect.notification.body || ""}`.trim();
|
|
|
37019
37473
|
}
|
|
37020
37474
|
return false;
|
|
37021
37475
|
}
|
|
37476
|
+
/** @see ProviderInstance.noteManualInteraction */
|
|
37477
|
+
noteManualInteraction(now = Date.now()) {
|
|
37478
|
+
this.manualAttendance.note(now);
|
|
37479
|
+
}
|
|
37480
|
+
/**
|
|
37481
|
+
* Whether auto-approve should be treated as active *right now* for display
|
|
37482
|
+
* and firing decisions: the configured intent AND the user is not currently
|
|
37483
|
+
* attending this session by hand. When a human is attending, auto-approve is
|
|
37484
|
+
* held so the modal stays visible and they can drive it via the controlbar.
|
|
37485
|
+
* Provider-agnostic — the attendance signal is the command set, never any
|
|
37486
|
+
* CLI-specific modal text.
|
|
37487
|
+
*/
|
|
37488
|
+
autoApproveEffectivelyActive(status, now = Date.now()) {
|
|
37489
|
+
return status === "waiting_approval" && this.shouldAutoApprove() && !this.manualAttendance.isAttended(now);
|
|
37490
|
+
}
|
|
37022
37491
|
recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
|
|
37023
37492
|
this.appendRuntimeSystemMessage(
|
|
37024
37493
|
formatAutoApprovalMessage(modalMessage, buttonLabel),
|
|
@@ -37964,7 +38433,7 @@ var AcpProviderInstance = class {
|
|
|
37964
38433
|
input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
|
|
37965
38434
|
});
|
|
37966
38435
|
}
|
|
37967
|
-
if (this.settings.autoApprove !== false) {
|
|
38436
|
+
if (this.settings.autoApprove !== false && !this.manualAttendance.isAttended()) {
|
|
37968
38437
|
const toolTitle = tc.title || tc.toolCallId || "tool call";
|
|
37969
38438
|
this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
|
|
37970
38439
|
this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
|
|
@@ -38195,6 +38664,15 @@ var AcpProviderInstance = class {
|
|
|
38195
38664
|
this.detectStatusTransition();
|
|
38196
38665
|
}
|
|
38197
38666
|
permissionResolvers = [];
|
|
38667
|
+
// Provider-common manual-attendance signal: while a human is actively driving
|
|
38668
|
+
// this session from the dashboard, auto-approve holds so they can decide on
|
|
38669
|
+
// the permission request themselves. Background workers are never attended →
|
|
38670
|
+
// delegated auto-approve is unaffected.
|
|
38671
|
+
manualAttendance = new ManualAttendanceTracker();
|
|
38672
|
+
/** @see ProviderInstance.noteManualInteraction */
|
|
38673
|
+
noteManualInteraction(now = Date.now()) {
|
|
38674
|
+
this.manualAttendance.note(now);
|
|
38675
|
+
}
|
|
38198
38676
|
async resolvePermission(approved) {
|
|
38199
38677
|
const resolver = this.permissionResolvers.shift();
|
|
38200
38678
|
if (resolver) {
|
|
@@ -39352,6 +39830,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
39352
39830
|
);
|
|
39353
39831
|
continue;
|
|
39354
39832
|
}
|
|
39833
|
+
const restoredSettings = { ...this.providerLoader.getSettings(normalizedType) };
|
|
39834
|
+
const coordinatorEntry = getCoordinatorForSession(record.runtimeId);
|
|
39835
|
+
if (coordinatorEntry?.meshId) {
|
|
39836
|
+
restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
|
|
39837
|
+
}
|
|
39355
39838
|
try {
|
|
39356
39839
|
await this.registerCliInstance(
|
|
39357
39840
|
record.runtimeId,
|
|
@@ -39360,7 +39843,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
39360
39843
|
record.workspace,
|
|
39361
39844
|
record.cliArgs,
|
|
39362
39845
|
resolvedProvider,
|
|
39363
|
-
|
|
39846
|
+
restoredSettings,
|
|
39364
39847
|
true,
|
|
39365
39848
|
{
|
|
39366
39849
|
providerSessionId: sessionBinding.providerSessionId,
|
|
@@ -40677,7 +41160,7 @@ function parsePbFile(filePath, sessionId) {
|
|
|
40677
41160
|
}
|
|
40678
41161
|
if (buf.length === 0) return null;
|
|
40679
41162
|
const strings = extractStringsFromBuffer(buf);
|
|
40680
|
-
const meaningful = strings.filter((
|
|
41163
|
+
const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
|
|
40681
41164
|
if (meaningful.length === 0) return null;
|
|
40682
41165
|
const content = meaningful.join("\n");
|
|
40683
41166
|
const sourceMtimeMs = statMtimeMs3(filePath);
|
|
@@ -40885,10 +41368,10 @@ function readSession4(sessionPath) {
|
|
|
40885
41368
|
};
|
|
40886
41369
|
}
|
|
40887
41370
|
function normalizeHermesRole(r) {
|
|
40888
|
-
const
|
|
40889
|
-
if (
|
|
40890
|
-
if (
|
|
40891
|
-
if (
|
|
41371
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41372
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41373
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41374
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
40892
41375
|
return "system";
|
|
40893
41376
|
}
|
|
40894
41377
|
|
|
@@ -41114,10 +41597,10 @@ function safeMtime(p) {
|
|
|
41114
41597
|
}
|
|
41115
41598
|
}
|
|
41116
41599
|
function normalizeRole2(r) {
|
|
41117
|
-
const
|
|
41118
|
-
if (
|
|
41119
|
-
if (
|
|
41120
|
-
if (
|
|
41600
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41601
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41602
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41603
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
41121
41604
|
return "system";
|
|
41122
41605
|
}
|
|
41123
41606
|
|
|
@@ -41137,7 +41620,7 @@ function synthesizeControlsFromControlBar(specControls) {
|
|
|
41137
41620
|
const actionType = ctl?.action?.type;
|
|
41138
41621
|
if (!id || !actionType) return;
|
|
41139
41622
|
const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
|
|
41140
|
-
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((
|
|
41623
|
+
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
|
|
41141
41624
|
if (actionType === "open_picker") {
|
|
41142
41625
|
out.push({
|
|
41143
41626
|
id,
|
|
@@ -48053,7 +48536,7 @@ var DaemonCommandRouter = class {
|
|
|
48053
48536
|
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.";
|
|
48054
48537
|
if (!firstFailedCmd) return base;
|
|
48055
48538
|
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 : "";
|
|
48056
|
-
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((
|
|
48539
|
+
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|
|
48057
48540
|
const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
|
|
48058
48541
|
return [
|
|
48059
48542
|
base,
|
|
@@ -48804,7 +49287,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
48804
49287
|
convergence = "blocked_review";
|
|
48805
49288
|
}
|
|
48806
49289
|
const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
|
|
48807
|
-
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((
|
|
49290
|
+
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
|
|
48808
49291
|
results.push({
|
|
48809
49292
|
nodeId: node.id,
|
|
48810
49293
|
workspace: node.workspace,
|
|
@@ -49801,7 +50284,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
49801
50284
|
return {
|
|
49802
50285
|
success: true,
|
|
49803
50286
|
screenLineCount: lines.length,
|
|
49804
|
-
sections: resolved.map((
|
|
50287
|
+
sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
|
|
49805
50288
|
};
|
|
49806
50289
|
} catch (e) {
|
|
49807
50290
|
return { success: false, error: `resolve failed: ${e.message}` };
|
|
@@ -50370,7 +50853,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50370
50853
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
50371
50854
|
try {
|
|
50372
50855
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
50373
|
-
const status = Array.isArray(args?.status) ? args.status.map((
|
|
50856
|
+
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
50374
50857
|
const rawQueue = getQueue2(meshId, { status });
|
|
50375
50858
|
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
50376
50859
|
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
@@ -50651,7 +51134,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50651
51134
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50652
51135
|
}
|
|
50653
51136
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50654
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
51137
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50655
51138
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50656
51139
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
50657
51140
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50685,7 +51168,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50685
51168
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50686
51169
|
}
|
|
50687
51170
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50688
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
51171
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50689
51172
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50690
51173
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
50691
51174
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50733,7 +51216,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50733
51216
|
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
50734
51217
|
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
50735
51218
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50736
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
51219
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50737
51220
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50738
51221
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
50739
51222
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
@@ -50820,7 +51303,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50820
51303
|
let worktreeCleanup;
|
|
50821
51304
|
if (node?.isLocalWorktree) {
|
|
50822
51305
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50823
|
-
const isRemoteWorktree = nodeDaemonId && nodeDaemonId
|
|
51306
|
+
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
50824
51307
|
if (isRemoteWorktree) {
|
|
50825
51308
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
50826
51309
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50902,7 +51385,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50902
51385
|
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
50903
51386
|
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
50904
51387
|
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
50905
|
-
if (sourceDaemonId && sourceDaemonId
|
|
51388
|
+
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50906
51389
|
const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
50907
51390
|
...typeof args === "object" && args !== null ? args : {},
|
|
50908
51391
|
_meshDirectDispatch: true
|
|
@@ -51144,7 +51627,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
51144
51627
|
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
51145
51628
|
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
51146
51629
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
51147
|
-
if (nodeDaemonId && nodeDaemonId
|
|
51630
|
+
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
51148
51631
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
51149
51632
|
...typeof args === "object" && args !== null ? args : {},
|
|
51150
51633
|
_meshDirectDispatch: true
|
|
@@ -52354,16 +52837,16 @@ var DaemonStatusReporter = class {
|
|
|
52354
52837
|
const now = this.lastStatusSentAt;
|
|
52355
52838
|
const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
|
|
52356
52839
|
const allStates = this.deps.instanceManager.collectAllStates();
|
|
52357
|
-
const ideStates = allStates.filter((
|
|
52358
|
-
const cliStates = allStates.filter((
|
|
52359
|
-
const acpStates = allStates.filter((
|
|
52360
|
-
const ideSummary = ideStates.map((
|
|
52361
|
-
const msgs =
|
|
52362
|
-
const exts =
|
|
52363
|
-
return `${
|
|
52840
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
52841
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
52842
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
52843
|
+
const ideSummary = ideStates.map((s2) => {
|
|
52844
|
+
const msgs = s2.activeChat?.messages?.length || 0;
|
|
52845
|
+
const exts = s2.extensions.length;
|
|
52846
|
+
return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
|
|
52364
52847
|
}).join(", ");
|
|
52365
|
-
const cliSummary = cliStates.map((
|
|
52366
|
-
const acpSummary = acpStates.map((
|
|
52848
|
+
const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52849
|
+
const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52367
52850
|
const logLevel = opts?.p2pOnly ? "debug" : "info";
|
|
52368
52851
|
const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
|
|
52369
52852
|
const summaryChanged = baseSummary !== this.lastStatusSummary;
|
|
@@ -52474,10 +52957,10 @@ var DaemonStatusReporter = class {
|
|
|
52474
52957
|
}
|
|
52475
52958
|
return false;
|
|
52476
52959
|
}
|
|
52477
|
-
simpleHash(
|
|
52960
|
+
simpleHash(s2) {
|
|
52478
52961
|
let h = 2166136261;
|
|
52479
|
-
for (let i = 0; i <
|
|
52480
|
-
h ^=
|
|
52962
|
+
for (let i = 0; i < s2.length; i++) {
|
|
52963
|
+
h ^= s2.charCodeAt(i);
|
|
52481
52964
|
h = h * 16777619 >>> 0;
|
|
52482
52965
|
}
|
|
52483
52966
|
return h.toString(36);
|
|
@@ -53703,7 +54186,7 @@ var ProviderInstanceManager = class {
|
|
|
53703
54186
|
* Per-category status collect
|
|
53704
54187
|
*/
|
|
53705
54188
|
collectStatesByCategory(category) {
|
|
53706
|
-
return this.collectAllStates().filter((
|
|
54189
|
+
return this.collectAllStates().filter((s2) => s2.category === category);
|
|
53707
54190
|
}
|
|
53708
54191
|
// ─── Tick engine ─────────────────────────────────
|
|
53709
54192
|
/**
|
|
@@ -55603,9 +56086,9 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
|
|
|
55603
56086
|
function findCliTarget(ctx, type, instanceId) {
|
|
55604
56087
|
if (!ctx.instanceManager) return null;
|
|
55605
56088
|
const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
|
|
55606
|
-
if (instanceId) return cliStates.find((
|
|
56089
|
+
if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
|
|
55607
56090
|
if (!type) return cliStates[cliStates.length - 1] || null;
|
|
55608
|
-
const matches = cliStates.filter((
|
|
56091
|
+
const matches = cliStates.filter((s2) => s2.type === type);
|
|
55609
56092
|
return matches[matches.length - 1] || null;
|
|
55610
56093
|
}
|
|
55611
56094
|
function getCliTargetBundle(ctx, type, instanceId) {
|
|
@@ -55968,20 +56451,20 @@ async function handleCliStatus(ctx, _req, res) {
|
|
|
55968
56451
|
return;
|
|
55969
56452
|
}
|
|
55970
56453
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55971
|
-
const cliStates = allStates.filter((
|
|
55972
|
-
const result = cliStates.map((
|
|
55973
|
-
instanceId:
|
|
55974
|
-
type:
|
|
55975
|
-
name:
|
|
55976
|
-
category:
|
|
55977
|
-
status:
|
|
55978
|
-
mode:
|
|
55979
|
-
workspace:
|
|
55980
|
-
messageCount:
|
|
55981
|
-
lastMessage:
|
|
55982
|
-
activeModal:
|
|
55983
|
-
pendingEvents:
|
|
55984
|
-
settings:
|
|
56454
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56455
|
+
const result = cliStates.map((s2) => ({
|
|
56456
|
+
instanceId: s2.instanceId,
|
|
56457
|
+
type: s2.type,
|
|
56458
|
+
name: s2.name,
|
|
56459
|
+
category: s2.category,
|
|
56460
|
+
status: s2.status,
|
|
56461
|
+
mode: s2.mode,
|
|
56462
|
+
workspace: s2.workspace,
|
|
56463
|
+
messageCount: s2.activeChat?.messages?.length || 0,
|
|
56464
|
+
lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
|
|
56465
|
+
activeModal: s2.activeChat?.activeModal || null,
|
|
56466
|
+
pendingEvents: s2.pendingEvents || [],
|
|
56467
|
+
settings: s2.settings
|
|
55985
56468
|
}));
|
|
55986
56469
|
ctx.json(res, 200, { instances: result, count: result.length });
|
|
55987
56470
|
}
|
|
@@ -56070,9 +56553,9 @@ function handleCliSSE(ctx, cliSSEClients, _req, res) {
|
|
|
56070
56553
|
}
|
|
56071
56554
|
if (ctx.instanceManager) {
|
|
56072
56555
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56073
|
-
const cliStates = allStates.filter((
|
|
56074
|
-
for (const
|
|
56075
|
-
ctx.sendCliSSE({ event: "snapshot", providerType:
|
|
56556
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56557
|
+
for (const s2 of cliStates) {
|
|
56558
|
+
ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
|
|
56076
56559
|
}
|
|
56077
56560
|
}
|
|
56078
56561
|
_req.on("close", () => {
|
|
@@ -56088,7 +56571,7 @@ async function handleCliDebug(ctx, type, _req, res) {
|
|
|
56088
56571
|
const target = findCliTarget(ctx, type);
|
|
56089
56572
|
if (!target) {
|
|
56090
56573
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56091
|
-
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((
|
|
56574
|
+
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
|
|
56092
56575
|
return;
|
|
56093
56576
|
}
|
|
56094
56577
|
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
@@ -56134,7 +56617,7 @@ async function handleCliTrace(ctx, type, req, res) {
|
|
|
56134
56617
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56135
56618
|
ctx.json(res, 404, {
|
|
56136
56619
|
error: `No running instance for: ${type}`,
|
|
56137
|
-
available: allStates.filter((
|
|
56620
|
+
available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
|
|
56138
56621
|
});
|
|
56139
56622
|
return;
|
|
56140
56623
|
}
|
|
@@ -56939,7 +57422,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56939
57422
|
child.write("\x1B[12;1R");
|
|
56940
57423
|
ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
|
|
56941
57424
|
}
|
|
56942
|
-
checkAutoApproval(data, (
|
|
57425
|
+
checkAutoApproval(data, (s2) => child.write(s2));
|
|
56943
57426
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
|
|
56944
57427
|
scheduleAutoStopForVerification();
|
|
56945
57428
|
});
|
|
@@ -56952,7 +57435,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56952
57435
|
stdout += chunk;
|
|
56953
57436
|
clearAutoStopTimer();
|
|
56954
57437
|
if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
|
|
56955
|
-
checkAutoApproval(chunk, (
|
|
57438
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
56956
57439
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
|
|
56957
57440
|
scheduleAutoStopForVerification();
|
|
56958
57441
|
});
|
|
@@ -56960,7 +57443,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56960
57443
|
const chunk = d.toString();
|
|
56961
57444
|
stderr += chunk;
|
|
56962
57445
|
clearAutoStopTimer();
|
|
56963
|
-
checkAutoApproval(chunk, (
|
|
57446
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
56964
57447
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
|
|
56965
57448
|
scheduleAutoStopForVerification();
|
|
56966
57449
|
});
|
|
@@ -57775,59 +58258,59 @@ var DevServer = class _DevServer {
|
|
|
57775
58258
|
// ─── Route Table ─────────────────────────────────────
|
|
57776
58259
|
routes = [
|
|
57777
58260
|
// Static routes
|
|
57778
|
-
{ method: "GET", pattern: "/api/providers", handler: (q,
|
|
57779
|
-
{ method: "GET", pattern: "/api/providers/source-config", handler: (q,
|
|
57780
|
-
{ method: "POST", pattern: "/api/providers/source-config", handler: (q,
|
|
57781
|
-
{ method: "GET", pattern: "/api/providers/versions", handler: (q,
|
|
57782
|
-
{ method: "POST", pattern: "/api/providers/reload", handler: (q,
|
|
57783
|
-
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q,
|
|
57784
|
-
{ method: "POST", pattern: "/api/cdp/click", handler: (q,
|
|
57785
|
-
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q,
|
|
57786
|
-
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q,
|
|
57787
|
-
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q,
|
|
57788
|
-
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q,
|
|
57789
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q,
|
|
57790
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q,
|
|
57791
|
-
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q,
|
|
57792
|
-
{ method: "GET", pattern: "/api/cdp/targets", handler: (q,
|
|
57793
|
-
{ method: "POST", pattern: "/api/scripts/run", handler: (q,
|
|
57794
|
-
{ method: "GET", pattern: "/api/status", handler: (q,
|
|
57795
|
-
{ method: "POST", pattern: "/api/watch/start", handler: (q,
|
|
57796
|
-
{ method: "POST", pattern: "/api/watch/stop", handler: (q,
|
|
57797
|
-
{ method: "GET", pattern: "/api/watch/events", handler: (q,
|
|
57798
|
-
{ method: "POST", pattern: "/api/scaffold", handler: (q,
|
|
58261
|
+
{ method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
|
|
58262
|
+
{ method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
|
|
58263
|
+
{ method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
|
|
58264
|
+
{ method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
|
|
58265
|
+
{ method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
|
|
58266
|
+
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
|
|
58267
|
+
{ method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
|
|
58268
|
+
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
|
|
58269
|
+
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
|
|
58270
|
+
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
|
|
58271
|
+
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
|
|
58272
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
|
|
58273
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
|
|
58274
|
+
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
|
|
58275
|
+
{ method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
|
|
58276
|
+
{ method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
|
|
58277
|
+
{ method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
|
|
58278
|
+
{ method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
|
|
58279
|
+
{ method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
|
|
58280
|
+
{ method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
|
|
58281
|
+
{ method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
|
|
57799
58282
|
// CLI Debug routes
|
|
57800
|
-
{ method: "GET", pattern: "/api/cli/status", handler: (q,
|
|
57801
|
-
{ method: "POST", pattern: "/api/cli/launch", handler: (q,
|
|
57802
|
-
{ method: "POST", pattern: "/api/cli/send", handler: (q,
|
|
57803
|
-
{ method: "POST", pattern: "/api/cli/exercise", handler: (q,
|
|
57804
|
-
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q,
|
|
57805
|
-
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q,
|
|
57806
|
-
{ method: "POST", pattern: "/api/cli/resolve", handler: (q,
|
|
57807
|
-
{ method: "POST", pattern: "/api/cli/raw", handler: (q,
|
|
57808
|
-
{ method: "POST", pattern: "/api/cli/stop", handler: (q,
|
|
57809
|
-
{ method: "GET", pattern: "/api/cli/events", handler: (q,
|
|
57810
|
-
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q,
|
|
57811
|
-
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q,
|
|
57812
|
-
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q,
|
|
58283
|
+
{ method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
|
|
58284
|
+
{ method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
|
|
58285
|
+
{ method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
|
|
58286
|
+
{ method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
|
|
58287
|
+
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
|
|
58288
|
+
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
|
|
58289
|
+
{ method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
|
|
58290
|
+
{ method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
|
|
58291
|
+
{ method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
|
|
58292
|
+
{ method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
|
|
58293
|
+
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
|
|
58294
|
+
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
|
|
58295
|
+
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
|
|
57813
58296
|
// Dynamic routes (provider :type param)
|
|
57814
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q,
|
|
57815
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q,
|
|
57816
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57817
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57818
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q,
|
|
57819
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q,
|
|
57820
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q,
|
|
57821
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q,
|
|
57822
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q,
|
|
57823
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q,
|
|
57824
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q,
|
|
57825
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q,
|
|
57826
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q,
|
|
57827
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q,
|
|
57828
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q,
|
|
57829
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q,
|
|
57830
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q,
|
|
58297
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
|
|
58298
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
|
|
58299
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
|
|
58300
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
|
|
58301
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
|
|
58302
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
|
|
58303
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
|
|
58304
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
|
|
58305
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
|
|
58306
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
|
|
58307
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
|
|
58308
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
|
|
58309
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
|
|
58310
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
|
|
58311
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
|
|
58312
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
|
|
58313
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
|
|
57831
58314
|
];
|
|
57832
58315
|
matchRoute(method, pathname) {
|
|
57833
58316
|
for (const route of this.routes) {
|
|
@@ -58422,14 +58905,14 @@ var DevServer = class _DevServer {
|
|
|
58422
58905
|
warnings.push(...validation.warnings);
|
|
58423
58906
|
if (config.settings) {
|
|
58424
58907
|
for (const [key, val] of Object.entries(config.settings)) {
|
|
58425
|
-
const
|
|
58426
|
-
if (!
|
|
58427
|
-
else if (!["boolean", "number", "string", "select"].includes(
|
|
58428
|
-
errors.push(`settings.${key}: invalid type '${
|
|
58429
|
-
if (
|
|
58430
|
-
if (
|
|
58431
|
-
errors.push(`settings.${key}: min (${
|
|
58432
|
-
if (
|
|
58908
|
+
const s2 = val;
|
|
58909
|
+
if (!s2.type) errors.push(`settings.${key}: missing type`);
|
|
58910
|
+
else if (!["boolean", "number", "string", "select"].includes(s2.type))
|
|
58911
|
+
errors.push(`settings.${key}: invalid type '${s2.type}'`);
|
|
58912
|
+
if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
|
|
58913
|
+
if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
|
|
58914
|
+
errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
|
|
58915
|
+
if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
|
|
58433
58916
|
errors.push(`settings.${key}: select type requires options[]`);
|
|
58434
58917
|
}
|
|
58435
58918
|
}
|