@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.mjs
CHANGED
|
@@ -311,10 +311,10 @@ function readInjected(value) {
|
|
|
311
311
|
}
|
|
312
312
|
function getDaemonBuildInfo() {
|
|
313
313
|
if (cached) return cached;
|
|
314
|
-
const commit = readInjected(true ? "
|
|
315
|
-
const commitShort = readInjected(true ? "
|
|
316
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
317
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
314
|
+
const commit = readInjected(true ? "a45106605e2ae1c10c0bc6cbe48c2cac4e862ded" : void 0) ?? "unknown";
|
|
315
|
+
const commitShort = readInjected(true ? "a4510660" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
316
|
+
const version = readInjected(true ? "0.9.82-rc.355" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
317
|
+
const builtAt = readInjected(true ? "2026-06-22T15:21:19.981Z" : void 0);
|
|
318
318
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
319
319
|
return cached;
|
|
320
320
|
}
|
|
@@ -1067,6 +1067,9 @@ __export(git_diff_exports, {
|
|
|
1067
1067
|
});
|
|
1068
1068
|
import { readFile, realpath as realpath2 } from "fs/promises";
|
|
1069
1069
|
import * as path2 from "path";
|
|
1070
|
+
function withCollectionTimeout(options) {
|
|
1071
|
+
return options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
|
|
1072
|
+
}
|
|
1070
1073
|
function validateBaseRef(ref) {
|
|
1071
1074
|
const trimmed = ref.trim();
|
|
1072
1075
|
if (!trimmed || trimmed.startsWith("-") || trimmed.includes("..") || !/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(trimmed)) {
|
|
@@ -1076,14 +1079,15 @@ function validateBaseRef(ref) {
|
|
|
1076
1079
|
}
|
|
1077
1080
|
async function getGitDiffSummary(workspace, options = {}) {
|
|
1078
1081
|
const lastCheckedAt = Date.now();
|
|
1082
|
+
const effectiveOptions = withCollectionTimeout(options);
|
|
1079
1083
|
try {
|
|
1080
|
-
const repo = await resolveGitRepository(workspace,
|
|
1084
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
1081
1085
|
const repoRoot = repo.repoRoot;
|
|
1082
1086
|
if (options.baseRef) {
|
|
1083
1087
|
const range = `${validateBaseRef(options.baseRef)}...HEAD`;
|
|
1084
1088
|
const [nameStatus, numstat] = await Promise.all([
|
|
1085
|
-
runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...
|
|
1086
|
-
runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...
|
|
1089
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1090
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...effectiveOptions, cwd: repoRoot })
|
|
1087
1091
|
]);
|
|
1088
1092
|
const outputBytes2 = byteLength(nameStatus.stdout + numstat.stdout);
|
|
1089
1093
|
const changes2 = combineDiffEntries(nameStatus.stdout, numstat.stdout, false);
|
|
@@ -1102,11 +1106,11 @@ async function getGitDiffSummary(workspace, options = {}) {
|
|
|
1102
1106
|
};
|
|
1103
1107
|
}
|
|
1104
1108
|
const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
|
|
1105
|
-
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...
|
|
1106
|
-
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...
|
|
1107
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...
|
|
1108
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...
|
|
1109
|
-
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...
|
|
1109
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1110
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1111
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1112
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
|
|
1113
|
+
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...effectiveOptions, cwd: repoRoot })
|
|
1110
1114
|
]);
|
|
1111
1115
|
const outputBytes = byteLength(
|
|
1112
1116
|
unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
|
|
@@ -1148,13 +1152,14 @@ async function getGitDiffSummary(workspace, options = {}) {
|
|
|
1148
1152
|
}
|
|
1149
1153
|
async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
1150
1154
|
const lastCheckedAt = Date.now();
|
|
1151
|
-
const
|
|
1155
|
+
const effectiveOptions = withCollectionTimeout(options);
|
|
1156
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
1152
1157
|
const repoRoot = repo.repoRoot;
|
|
1153
1158
|
const selected = await resolveRepoFilePath(repoRoot, filePath);
|
|
1154
1159
|
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
1155
1160
|
if (options.baseRef) {
|
|
1156
1161
|
const range = `${validateBaseRef(options.baseRef)}...HEAD`;
|
|
1157
|
-
const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...
|
|
1162
|
+
const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot });
|
|
1158
1163
|
const bounded2 = truncateText(result.stdout, maxBytes);
|
|
1159
1164
|
return {
|
|
1160
1165
|
workspace: repo.workspace,
|
|
@@ -1167,13 +1172,13 @@ async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
|
1167
1172
|
};
|
|
1168
1173
|
}
|
|
1169
1174
|
const [unstaged, staged] = await Promise.all([
|
|
1170
|
-
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...
|
|
1171
|
-
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...
|
|
1175
|
+
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot }),
|
|
1176
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot })
|
|
1172
1177
|
]);
|
|
1173
1178
|
let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
|
|
1174
1179
|
if (!diff) {
|
|
1175
1180
|
const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
|
|
1176
|
-
...
|
|
1181
|
+
...effectiveOptions,
|
|
1177
1182
|
cwd: repoRoot
|
|
1178
1183
|
});
|
|
1179
1184
|
const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
|
|
@@ -4817,9 +4822,12 @@ function getActiveDirectDispatches(meshId) {
|
|
|
4817
4822
|
return [];
|
|
4818
4823
|
}
|
|
4819
4824
|
}
|
|
4820
|
-
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
4825
|
+
function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
4821
4826
|
try {
|
|
4822
|
-
|
|
4827
|
+
if (!taskId) {
|
|
4828
|
+
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)`);
|
|
4829
|
+
}
|
|
4830
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
|
|
4823
4831
|
} catch {
|
|
4824
4832
|
}
|
|
4825
4833
|
}
|
|
@@ -5651,9 +5659,25 @@ var init_mesh_runtime_store = __esm({
|
|
|
5651
5659
|
updatedAt: r.updated_at
|
|
5652
5660
|
}));
|
|
5653
5661
|
}
|
|
5654
|
-
|
|
5655
|
-
|
|
5662
|
+
// CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
|
|
5663
|
+
// single session can host several sequential direct dispatches (re-dispatch / nudge), so
|
|
5664
|
+
// matching a status flip by session_id alone hits EVERY non-terminal row for that session
|
|
5665
|
+
// — flipping a sibling task's row and stranding the one whose event actually fired (the
|
|
5666
|
+
// assigned-stranded watchdog then requeues a task that is really still generating). When
|
|
5667
|
+
// the firing event carries a taskId, target the single PK row; the session_id match is the
|
|
5668
|
+
// legacy fallback only for events that arrive without a taskId.
|
|
5669
|
+
updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
5656
5670
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5671
|
+
if (taskId) {
|
|
5672
|
+
this.db.prepare(`
|
|
5673
|
+
UPDATE mesh_direct_dispatches
|
|
5674
|
+
SET status = @status, updated_at = @updatedAt
|
|
5675
|
+
WHERE mesh_id = @meshId AND task_id = @taskId
|
|
5676
|
+
AND status NOT IN ('completed', 'failed')
|
|
5677
|
+
`).run({ status, meshId, taskId, updatedAt: now });
|
|
5678
|
+
return;
|
|
5679
|
+
}
|
|
5680
|
+
if (!sessionId) return;
|
|
5657
5681
|
this.db.prepare(`
|
|
5658
5682
|
UPDATE mesh_direct_dispatches
|
|
5659
5683
|
SET status = @status, updated_at = @updatedAt
|
|
@@ -7382,7 +7406,7 @@ function resolveWin32Executable(command) {
|
|
|
7382
7406
|
windowsHide: true
|
|
7383
7407
|
}).trim();
|
|
7384
7408
|
if (out) {
|
|
7385
|
-
const matches = out.split(/\r?\n/).map((
|
|
7409
|
+
const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
|
|
7386
7410
|
const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
|
|
7387
7411
|
return direct || matches[0] || command;
|
|
7388
7412
|
}
|
|
@@ -8734,11 +8758,29 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
8734
8758
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
8735
8759
|
);
|
|
8736
8760
|
}
|
|
8761
|
+
function isWeakCompletionMetadata(metadata) {
|
|
8762
|
+
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
8763
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
8764
|
+
if (metadata.reviewRecommended === true) return true;
|
|
8765
|
+
const diag = readRecord4(metadata.completionDiagnostic);
|
|
8766
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
8767
|
+
}
|
|
8737
8768
|
function buildPendingEventFingerprint(event) {
|
|
8738
8769
|
const metadata = readRecord4(event.metadataEvent) || {};
|
|
8739
8770
|
if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
|
|
8740
8771
|
return [event.meshId, event.event, event.nodeId || ""].join("::");
|
|
8741
8772
|
}
|
|
8773
|
+
if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
|
|
8774
|
+
const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
8775
|
+
if (terminalTaskId) {
|
|
8776
|
+
return [
|
|
8777
|
+
event.meshId,
|
|
8778
|
+
event.event,
|
|
8779
|
+
terminalTaskId,
|
|
8780
|
+
isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
|
|
8781
|
+
].join("::");
|
|
8782
|
+
}
|
|
8783
|
+
}
|
|
8742
8784
|
const sessionId = resolveEventSessionId(metadata);
|
|
8743
8785
|
const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
|
|
8744
8786
|
const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
@@ -9097,7 +9139,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
9097
9139
|
}
|
|
9098
9140
|
}
|
|
9099
9141
|
}
|
|
9100
|
-
var REFINE_TERMINAL_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9142
|
+
var REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9101
9143
|
var init_mesh_events_pending = __esm({
|
|
9102
9144
|
"src/mesh/mesh-events-pending.ts"() {
|
|
9103
9145
|
"use strict";
|
|
@@ -9107,6 +9149,7 @@ var init_mesh_events_pending = __esm({
|
|
|
9107
9149
|
init_mesh_events_utils();
|
|
9108
9150
|
init_dist();
|
|
9109
9151
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
9152
|
+
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
9110
9153
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
9111
9154
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
9112
9155
|
}
|
|
@@ -9436,7 +9479,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
|
|
|
9436
9479
|
evidence
|
|
9437
9480
|
}
|
|
9438
9481
|
});
|
|
9439
|
-
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9482
|
+
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
|
|
9440
9483
|
markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9441
9484
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
9442
9485
|
queuePendingMeshCoordinatorEvent({
|
|
@@ -9731,8 +9774,8 @@ function parsePatternEntry(x) {
|
|
|
9731
9774
|
if (x instanceof RegExp) return x;
|
|
9732
9775
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
9733
9776
|
try {
|
|
9734
|
-
const
|
|
9735
|
-
return new RegExp(
|
|
9777
|
+
const s2 = x;
|
|
9778
|
+
return new RegExp(s2.source, s2.flags || "");
|
|
9736
9779
|
} catch {
|
|
9737
9780
|
return null;
|
|
9738
9781
|
}
|
|
@@ -10300,6 +10343,38 @@ var init_mesh_unresolved_forward_outbox = __esm({
|
|
|
10300
10343
|
}
|
|
10301
10344
|
});
|
|
10302
10345
|
|
|
10346
|
+
// src/mesh/mesh-event-trace.ts
|
|
10347
|
+
function s(v) {
|
|
10348
|
+
return typeof v === "string" && v.trim() ? v.trim() : "";
|
|
10349
|
+
}
|
|
10350
|
+
function meshEventTraceKey(ctx) {
|
|
10351
|
+
const segs = [`task=${s(ctx.taskId) || "-"}`];
|
|
10352
|
+
const eventId = s(ctx.eventId);
|
|
10353
|
+
if (eventId) segs.push(`evt=${eventId}`);
|
|
10354
|
+
segs.push(`sess=${s(ctx.sessionId) || "-"}`);
|
|
10355
|
+
const nodeId = s(ctx.nodeId);
|
|
10356
|
+
if (nodeId) segs.push(`node=${nodeId}`);
|
|
10357
|
+
const meshId = s(ctx.meshId);
|
|
10358
|
+
if (meshId) segs.push(`mesh=${meshId}`);
|
|
10359
|
+
const event = s(ctx.event);
|
|
10360
|
+
if (event) segs.push(`event=${event}`);
|
|
10361
|
+
return segs.join(" ");
|
|
10362
|
+
}
|
|
10363
|
+
function traceMeshEventStage(stage, ctx, detail) {
|
|
10364
|
+
LOG.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10365
|
+
}
|
|
10366
|
+
function traceMeshEventDrop(reason, ctx, detail) {
|
|
10367
|
+
LOG.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10368
|
+
}
|
|
10369
|
+
var CAT;
|
|
10370
|
+
var init_mesh_event_trace = __esm({
|
|
10371
|
+
"src/mesh/mesh-event-trace.ts"() {
|
|
10372
|
+
"use strict";
|
|
10373
|
+
init_logger();
|
|
10374
|
+
CAT = "EvtTrace";
|
|
10375
|
+
}
|
|
10376
|
+
});
|
|
10377
|
+
|
|
10303
10378
|
// src/config/state-store.ts
|
|
10304
10379
|
import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
10305
10380
|
import { join as join18 } from "path";
|
|
@@ -12085,9 +12160,9 @@ function buildAcpSession(state, options) {
|
|
|
12085
12160
|
}
|
|
12086
12161
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
12087
12162
|
const sessions = [];
|
|
12088
|
-
const ideStates = allStates.filter((
|
|
12089
|
-
const cliStates = allStates.filter((
|
|
12090
|
-
const acpStates = allStates.filter((
|
|
12163
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
12164
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
12165
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
12091
12166
|
for (const state of ideStates) {
|
|
12092
12167
|
sessions.push(buildWorkspaceSession(state, cdpManagers, options));
|
|
12093
12168
|
for (const ext of state.extensions) {
|
|
@@ -12572,6 +12647,15 @@ function getCachedMeshByWorkspace(workspace) {
|
|
|
12572
12647
|
meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
|
|
12573
12648
|
return mesh;
|
|
12574
12649
|
}
|
|
12650
|
+
function recoverMeshIdByNodeId(nodeId) {
|
|
12651
|
+
if (!nodeId) return "";
|
|
12652
|
+
for (const mesh of listMeshes()) {
|
|
12653
|
+
if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
|
|
12654
|
+
return readNonEmptyString2(mesh.id);
|
|
12655
|
+
}
|
|
12656
|
+
}
|
|
12657
|
+
return "";
|
|
12658
|
+
}
|
|
12575
12659
|
function __resetIdleAutoFastForwardForTests() {
|
|
12576
12660
|
idleAutoFastForwardLastAttempt.clear();
|
|
12577
12661
|
}
|
|
@@ -13474,6 +13558,13 @@ function shouldForceInjectMeshEvent(eventName) {
|
|
|
13474
13558
|
function injectMeshSystemMessage(components, args) {
|
|
13475
13559
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
13476
13560
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13561
|
+
const traceCtx = {
|
|
13562
|
+
taskId: args.metadataEvent.taskId,
|
|
13563
|
+
sessionId: eventSessionId,
|
|
13564
|
+
nodeId: eventNodeId,
|
|
13565
|
+
meshId: args.meshId,
|
|
13566
|
+
event: args.event
|
|
13567
|
+
};
|
|
13477
13568
|
const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
|
|
13478
13569
|
const workerCoordinatorDaemonId = readNonEmptyString2(
|
|
13479
13570
|
sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
|
|
@@ -13527,6 +13618,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13527
13618
|
}
|
|
13528
13619
|
}
|
|
13529
13620
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
13621
|
+
traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
|
|
13530
13622
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
13531
13623
|
}
|
|
13532
13624
|
if (args.event === "monitor:no_progress") {
|
|
@@ -13547,6 +13639,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13547
13639
|
}
|
|
13548
13640
|
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
13549
13641
|
LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
13642
|
+
traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
|
|
13550
13643
|
return {
|
|
13551
13644
|
success: true,
|
|
13552
13645
|
forwarded: 0,
|
|
@@ -13558,6 +13651,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13558
13651
|
}
|
|
13559
13652
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
13560
13653
|
LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
13654
|
+
traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
|
|
13561
13655
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
13562
13656
|
}
|
|
13563
13657
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
@@ -13572,6 +13666,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13572
13666
|
});
|
|
13573
13667
|
if (duplicateApproval) {
|
|
13574
13668
|
LOG.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13669
|
+
traceMeshEventDrop("duplicate_approval", traceCtx);
|
|
13575
13670
|
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
13576
13671
|
}
|
|
13577
13672
|
}
|
|
@@ -13591,6 +13686,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13591
13686
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
13592
13687
|
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
13593
13688
|
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13689
|
+
traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
|
|
13594
13690
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
13595
13691
|
}
|
|
13596
13692
|
}
|
|
@@ -13609,6 +13705,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13609
13705
|
});
|
|
13610
13706
|
if (duplicateCompletion) {
|
|
13611
13707
|
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13708
|
+
traceMeshEventDrop("duplicate_completion", traceCtx);
|
|
13612
13709
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
13613
13710
|
}
|
|
13614
13711
|
}
|
|
@@ -13627,6 +13724,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13627
13724
|
});
|
|
13628
13725
|
if (duplicateStopped) {
|
|
13629
13726
|
LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13727
|
+
traceMeshEventDrop("duplicate_stopped", traceCtx);
|
|
13630
13728
|
return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
|
|
13631
13729
|
}
|
|
13632
13730
|
}
|
|
@@ -13638,7 +13736,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13638
13736
|
});
|
|
13639
13737
|
const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
|
|
13640
13738
|
if (!leaveDirectDispatchActive) {
|
|
13641
|
-
updateDirectDispatchStatus(args.meshId, sessionId, outcome);
|
|
13739
|
+
updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
|
|
13642
13740
|
}
|
|
13643
13741
|
markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
|
|
13644
13742
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
@@ -13651,7 +13749,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13651
13749
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13652
13750
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
13653
13751
|
if (sessionId) {
|
|
13654
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13752
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13655
13753
|
const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
|
|
13656
13754
|
completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
|
|
13657
13755
|
if (nodeId && providerType) {
|
|
@@ -13734,7 +13832,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13734
13832
|
}
|
|
13735
13833
|
}
|
|
13736
13834
|
if (sessionId) {
|
|
13737
|
-
|
|
13835
|
+
const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
|
|
13836
|
+
updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
|
|
13738
13837
|
const activeDeliveries = (() => {
|
|
13739
13838
|
try {
|
|
13740
13839
|
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
|
|
@@ -13742,7 +13841,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13742
13841
|
return [];
|
|
13743
13842
|
}
|
|
13744
13843
|
})();
|
|
13745
|
-
|
|
13844
|
+
const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
|
|
13845
|
+
for (const d of deliveriesToAck) {
|
|
13746
13846
|
updateSessionDeliveryStatus(d.id, "acked");
|
|
13747
13847
|
}
|
|
13748
13848
|
}
|
|
@@ -13756,7 +13856,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13756
13856
|
}
|
|
13757
13857
|
}
|
|
13758
13858
|
if (sessionId) {
|
|
13759
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13859
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13760
13860
|
completedTaskForLedger = markSessionTerminal(sessionId, "failed");
|
|
13761
13861
|
}
|
|
13762
13862
|
}
|
|
@@ -13902,6 +14002,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13902
14002
|
};
|
|
13903
14003
|
if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
|
|
13904
14004
|
LOG.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
|
|
14005
|
+
traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
|
|
14006
|
+
} else {
|
|
14007
|
+
traceMeshEventDrop("queue_dedup", traceCtx);
|
|
13905
14008
|
}
|
|
13906
14009
|
return { success: true, forwarded: 0 };
|
|
13907
14010
|
}
|
|
@@ -13912,8 +14015,23 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
13912
14015
|
}
|
|
13913
14016
|
const nodeId = readNonEmptyString2(payload.nodeId);
|
|
13914
14017
|
const workspace = readNonEmptyString2(payload.workspace);
|
|
13915
|
-
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
|
|
13916
|
-
if (!meshId)
|
|
14018
|
+
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
|
|
14019
|
+
if (!meshId) {
|
|
14020
|
+
traceMeshEventDrop("meshId_required", {
|
|
14021
|
+
taskId: payload.taskId,
|
|
14022
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14023
|
+
nodeId,
|
|
14024
|
+
event: eventName
|
|
14025
|
+
}, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
|
|
14026
|
+
return { success: false, error: "meshId required" };
|
|
14027
|
+
}
|
|
14028
|
+
traceMeshEventStage("received", {
|
|
14029
|
+
taskId: payload.taskId,
|
|
14030
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14031
|
+
nodeId,
|
|
14032
|
+
meshId,
|
|
14033
|
+
event: eventName
|
|
14034
|
+
});
|
|
13917
14035
|
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
13918
14036
|
const relayModalMessage = readNonEmptyString2(payload.modalMessage);
|
|
13919
14037
|
const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
|
|
@@ -13994,9 +14112,18 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
|
13994
14112
|
workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
|
|
13995
14113
|
};
|
|
13996
14114
|
const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
|
|
14115
|
+
const fwdTraceCtx = {
|
|
14116
|
+
taskId: payload.taskId,
|
|
14117
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14118
|
+
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
|
|
14119
|
+
event: eventName
|
|
14120
|
+
};
|
|
14121
|
+
traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
|
|
14122
|
+
traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
|
|
13997
14123
|
Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
|
|
13998
14124
|
if (result && result.success === false) {
|
|
13999
14125
|
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
|
|
14126
|
+
traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14000
14127
|
return;
|
|
14001
14128
|
}
|
|
14002
14129
|
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
@@ -14064,6 +14191,14 @@ function setupMeshEventForwarding(components) {
|
|
|
14064
14191
|
if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
|
|
14065
14192
|
return;
|
|
14066
14193
|
}
|
|
14194
|
+
if (isUnroutableDelegateRejection(routing)) {
|
|
14195
|
+
traceMeshEventDrop("unroutable", {
|
|
14196
|
+
taskId: event.meshActiveTaskId ?? event.taskId,
|
|
14197
|
+
sessionId: routing.sessionId,
|
|
14198
|
+
nodeId: routing.nodeId,
|
|
14199
|
+
event: event.event
|
|
14200
|
+
}, "no coordinator anchor / mesh_unresolved");
|
|
14201
|
+
}
|
|
14067
14202
|
recordUnroutableDelegateEvent(routing, event.event);
|
|
14068
14203
|
return;
|
|
14069
14204
|
}
|
|
@@ -14093,6 +14228,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
14093
14228
|
init_mesh_events_pending();
|
|
14094
14229
|
init_mesh_routing();
|
|
14095
14230
|
init_mesh_unresolved_forward_outbox();
|
|
14231
|
+
init_mesh_event_trace();
|
|
14096
14232
|
init_snapshot();
|
|
14097
14233
|
init_repo_mesh_types();
|
|
14098
14234
|
init_dist();
|
|
@@ -14204,6 +14340,13 @@ function findLiveCoordinators(components) {
|
|
|
14204
14340
|
function injectPendingIntoCoordinator(coordinator, pending) {
|
|
14205
14341
|
if (!coordinator || !pending.coordinatorMessage) return;
|
|
14206
14342
|
const force = shouldForceInjectMeshEvent(pending.event);
|
|
14343
|
+
traceMeshEventStage("surfaced", {
|
|
14344
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14345
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
|
|
14346
|
+
nodeId: pending.nodeId,
|
|
14347
|
+
meshId: pending.meshId,
|
|
14348
|
+
event: pending.event
|
|
14349
|
+
}, force ? "force-inject" : "inject");
|
|
14207
14350
|
coordinator.onEvent("send_message", {
|
|
14208
14351
|
input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
|
|
14209
14352
|
...force ? { force: true } : {}
|
|
@@ -14262,6 +14405,13 @@ function recoverStrandedAssignedDispatches(meshId, store) {
|
|
|
14262
14405
|
});
|
|
14263
14406
|
if (reclaimed) {
|
|
14264
14407
|
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})`);
|
|
14408
|
+
traceMeshEventDrop("assigned_stranded_reclaim", {
|
|
14409
|
+
taskId: row.id,
|
|
14410
|
+
sessionId: row.assignedSessionId,
|
|
14411
|
+
nodeId: row.assignedNodeId,
|
|
14412
|
+
meshId,
|
|
14413
|
+
event: "agent:generating_completed"
|
|
14414
|
+
}, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
|
|
14265
14415
|
}
|
|
14266
14416
|
}
|
|
14267
14417
|
}
|
|
@@ -14421,6 +14571,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14421
14571
|
try {
|
|
14422
14572
|
queuePendingMeshCoordinatorEvent(pending);
|
|
14423
14573
|
LOG.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
|
|
14574
|
+
traceMeshEventDrop("strict_route_hold", {
|
|
14575
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14576
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14577
|
+
nodeId: pending.nodeId,
|
|
14578
|
+
meshId,
|
|
14579
|
+
event: pending.event
|
|
14580
|
+
}, `coordinatorSession=${wantSession} not live`);
|
|
14424
14581
|
} catch (e) {
|
|
14425
14582
|
LOG.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
|
|
14426
14583
|
}
|
|
@@ -14444,6 +14601,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14444
14601
|
}
|
|
14445
14602
|
});
|
|
14446
14603
|
LOG.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
|
|
14604
|
+
traceMeshEventDrop("strict_route_expired", {
|
|
14605
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14606
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14607
|
+
nodeId: pending.nodeId,
|
|
14608
|
+
meshId,
|
|
14609
|
+
event: pending.event
|
|
14610
|
+
}, `coordinatorSession=${wantSession} never returned`);
|
|
14447
14611
|
} catch (e) {
|
|
14448
14612
|
LOG.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
14449
14613
|
}
|
|
@@ -14455,15 +14619,24 @@ async function retryUnresolvedDelegateForwards(components) {
|
|
|
14455
14619
|
const entries = peekUnresolvedDelegateForwards();
|
|
14456
14620
|
if (entries.length === 0) return;
|
|
14457
14621
|
for (const entry of entries) {
|
|
14622
|
+
const entryTraceCtx = {
|
|
14623
|
+
taskId: entry.payload.taskId,
|
|
14624
|
+
sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
|
|
14625
|
+
nodeId: readNonEmptyString2(entry.payload.nodeId),
|
|
14626
|
+
event: readNonEmptyString2(entry.payload.event)
|
|
14627
|
+
};
|
|
14458
14628
|
let result;
|
|
14459
14629
|
try {
|
|
14630
|
+
traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
|
|
14460
14631
|
result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
|
|
14461
14632
|
} catch (e) {
|
|
14462
14633
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
|
|
14634
|
+
traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
|
|
14463
14635
|
continue;
|
|
14464
14636
|
}
|
|
14465
14637
|
if (result && result.success === false) {
|
|
14466
14638
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
|
|
14639
|
+
traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14467
14640
|
continue;
|
|
14468
14641
|
}
|
|
14469
14642
|
ackUnresolvedDelegateForward(entry.id);
|
|
@@ -14705,6 +14878,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14705
14878
|
init_mesh_events_coordinator();
|
|
14706
14879
|
init_mesh_unresolved_forward_outbox();
|
|
14707
14880
|
init_mesh_events_utils();
|
|
14881
|
+
init_mesh_event_trace();
|
|
14708
14882
|
init_dist();
|
|
14709
14883
|
init_mesh_work_queue();
|
|
14710
14884
|
init_mesh_ledger();
|
|
@@ -15543,8 +15717,8 @@ function saveProvidersActive(file) {
|
|
|
15543
15717
|
}
|
|
15544
15718
|
function isValidSource(x) {
|
|
15545
15719
|
if (!x || typeof x !== "object") return false;
|
|
15546
|
-
const
|
|
15547
|
-
return typeof
|
|
15720
|
+
const s2 = x;
|
|
15721
|
+
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";
|
|
15548
15722
|
}
|
|
15549
15723
|
function deriveSourceName(url) {
|
|
15550
15724
|
const m = url.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -15600,7 +15774,7 @@ function inventoryExternalSources() {
|
|
|
15600
15774
|
}
|
|
15601
15775
|
function sourcesProviding(category, type) {
|
|
15602
15776
|
const inventory = inventoryExternalSources();
|
|
15603
|
-
return inventory.filter((
|
|
15777
|
+
return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
|
|
15604
15778
|
}
|
|
15605
15779
|
function resolveActiveSource(category, type, activeFile) {
|
|
15606
15780
|
const candidates = sourcesProviding(category, type);
|
|
@@ -15804,10 +15978,10 @@ function compileSettledPromptMatchers(spec) {
|
|
|
15804
15978
|
const footers = (spec.withFooter ?? []).map((f) => {
|
|
15805
15979
|
if (f.kind === "regex") {
|
|
15806
15980
|
const re = compile2(f.pattern, f.flags ?? "i");
|
|
15807
|
-
return { test: (
|
|
15981
|
+
return { test: (s2) => re.test(s2) };
|
|
15808
15982
|
}
|
|
15809
15983
|
const needle = f.pattern.toLowerCase();
|
|
15810
|
-
return { test: (
|
|
15984
|
+
return { test: (s2) => s2.toLowerCase().includes(needle) };
|
|
15811
15985
|
});
|
|
15812
15986
|
return { prompt, footers };
|
|
15813
15987
|
}
|
|
@@ -16681,7 +16855,7 @@ var init_cli_state_engine = __esm({
|
|
|
16681
16855
|
}
|
|
16682
16856
|
resolveModal(buttonIndex) {
|
|
16683
16857
|
const snap = this.transport.getSnapshot();
|
|
16684
|
-
const parseApproval = typeof this.transport.runParseApproval === "function" ? (
|
|
16858
|
+
const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
|
|
16685
16859
|
let modal = this.activeModal ?? parseApproval(snap);
|
|
16686
16860
|
if (!modal && this.runner.hasParseSession()) {
|
|
16687
16861
|
try {
|
|
@@ -19369,22 +19543,23 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19369
19543
|
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]));
|
|
19370
19544
|
let idx = -1;
|
|
19371
19545
|
for (const c of candidates) {
|
|
19546
|
+
let candIdx = -1;
|
|
19372
19547
|
if (sec.anchor_last) {
|
|
19373
19548
|
for (let i = total - 1; i >= 0; i--) {
|
|
19374
19549
|
if (matchesCandidate(c, i)) {
|
|
19375
|
-
|
|
19550
|
+
candIdx = i;
|
|
19376
19551
|
break;
|
|
19377
19552
|
}
|
|
19378
19553
|
}
|
|
19379
19554
|
} else {
|
|
19380
19555
|
for (let i = 0; i < total; i++) {
|
|
19381
19556
|
if (matchesCandidate(c, i)) {
|
|
19382
|
-
|
|
19557
|
+
candIdx = i;
|
|
19383
19558
|
break;
|
|
19384
19559
|
}
|
|
19385
19560
|
}
|
|
19386
19561
|
}
|
|
19387
|
-
if (
|
|
19562
|
+
if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
|
|
19388
19563
|
}
|
|
19389
19564
|
if (idx !== -1) {
|
|
19390
19565
|
from = idx;
|
|
@@ -19436,7 +19611,7 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19436
19611
|
}
|
|
19437
19612
|
function sectionText(sections, sectionId, fullScreen) {
|
|
19438
19613
|
if (!sectionId) return fullScreen;
|
|
19439
|
-
const found = sections.find((
|
|
19614
|
+
const found = sections.find((s2) => s2.id === sectionId);
|
|
19440
19615
|
return found ? found.text : "";
|
|
19441
19616
|
}
|
|
19442
19617
|
function isRegexCondition(c) {
|
|
@@ -19604,10 +19779,10 @@ function isV4Spec(raw) {
|
|
|
19604
19779
|
return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
|
|
19605
19780
|
}
|
|
19606
19781
|
function initialState(spec) {
|
|
19607
|
-
return spec.states.find((
|
|
19782
|
+
return spec.states.find((s2) => s2.initial) ?? spec.states[0];
|
|
19608
19783
|
}
|
|
19609
19784
|
function stateById(spec, id) {
|
|
19610
|
-
return spec.states.find((
|
|
19785
|
+
return spec.states.find((s2) => s2.id === id);
|
|
19611
19786
|
}
|
|
19612
19787
|
function outgoingTransitions(spec, stateId) {
|
|
19613
19788
|
const matches = spec.transitions.filter((t) => {
|
|
@@ -19696,7 +19871,17 @@ function evalCond(cond, sections, fullScreen, cursor, prevLines, clock, legacyTr
|
|
|
19696
19871
|
const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
|
|
19697
19872
|
const kind = isRegex(cond) ? "regex" : "changed";
|
|
19698
19873
|
const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
|
|
19699
|
-
|
|
19874
|
+
let matchedText;
|
|
19875
|
+
if (result && isRegex(cond)) {
|
|
19876
|
+
try {
|
|
19877
|
+
const hay = sectionText(sections, cond.section, fullScreen);
|
|
19878
|
+
const re = new RegExp(cond.matches, cond.flags ?? "i");
|
|
19879
|
+
const m = re.exec(hay);
|
|
19880
|
+
if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
|
|
19881
|
+
} catch {
|
|
19882
|
+
}
|
|
19883
|
+
}
|
|
19884
|
+
return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
|
|
19700
19885
|
}
|
|
19701
19886
|
return { kind: "all", result: false, detail: "unknown condition" };
|
|
19702
19887
|
}
|
|
@@ -19812,17 +19997,17 @@ function validateFsmSpec(raw) {
|
|
|
19812
19997
|
}
|
|
19813
19998
|
const ids = /* @__PURE__ */ new Set();
|
|
19814
19999
|
let initialCount = 0;
|
|
19815
|
-
for (const [i,
|
|
19816
|
-
if (!
|
|
20000
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20001
|
+
if (!s2.id) {
|
|
19817
20002
|
errs.push(`states[${i}].id is required`);
|
|
19818
20003
|
continue;
|
|
19819
20004
|
}
|
|
19820
|
-
if (ids.has(
|
|
19821
|
-
ids.add(
|
|
19822
|
-
if (!
|
|
19823
|
-
if (
|
|
19824
|
-
if (
|
|
19825
|
-
errs.push(`states[${i}].status "${
|
|
20005
|
+
if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
|
|
20006
|
+
ids.add(s2.id);
|
|
20007
|
+
if (!s2.label) errs.push(`states[${i}].label is required`);
|
|
20008
|
+
if (s2.initial) initialCount += 1;
|
|
20009
|
+
if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
|
|
20010
|
+
errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
|
|
19826
20011
|
}
|
|
19827
20012
|
}
|
|
19828
20013
|
if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
|
|
@@ -19838,10 +20023,10 @@ function validateFsmSpec(raw) {
|
|
|
19838
20023
|
else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
|
|
19839
20024
|
if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
|
|
19840
20025
|
}
|
|
19841
|
-
for (const [i,
|
|
19842
|
-
const sec =
|
|
20026
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20027
|
+
const sec = s2.extract?.title?.section;
|
|
19843
20028
|
if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
|
|
19844
|
-
const bsec =
|
|
20029
|
+
const bsec = s2.extract?.buttons?.section;
|
|
19845
20030
|
if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
|
|
19846
20031
|
}
|
|
19847
20032
|
return errs;
|
|
@@ -27072,6 +27257,42 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
27072
27257
|
return fn() || null;
|
|
27073
27258
|
}
|
|
27074
27259
|
|
|
27260
|
+
// src/providers/manual-attendance.ts
|
|
27261
|
+
var AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS = 6e4;
|
|
27262
|
+
var ManualAttendanceTracker = class {
|
|
27263
|
+
constructor(suppressMs = AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS) {
|
|
27264
|
+
this.suppressMs = suppressMs;
|
|
27265
|
+
}
|
|
27266
|
+
lastInteractionAt = 0;
|
|
27267
|
+
/** Record that a human just drove this session by hand. */
|
|
27268
|
+
note(now = Date.now()) {
|
|
27269
|
+
this.lastInteractionAt = now;
|
|
27270
|
+
}
|
|
27271
|
+
/** True while a manual interaction is recent enough to suppress auto-approve. */
|
|
27272
|
+
isAttended(now = Date.now()) {
|
|
27273
|
+
return this.lastInteractionAt > 0 && now - this.lastInteractionAt < this.suppressMs;
|
|
27274
|
+
}
|
|
27275
|
+
/**
|
|
27276
|
+
* Milliseconds remaining in the current suppression window, or 0 when not
|
|
27277
|
+
* attended. Used to re-arm a re-check timer so auto-approve fires the moment
|
|
27278
|
+
* the window lapses even if the PTY/agent has since gone silent.
|
|
27279
|
+
*/
|
|
27280
|
+
remainingMs(now = Date.now()) {
|
|
27281
|
+
if (this.lastInteractionAt <= 0) return 0;
|
|
27282
|
+
return Math.max(0, this.suppressMs - (now - this.lastInteractionAt));
|
|
27283
|
+
}
|
|
27284
|
+
};
|
|
27285
|
+
var MANUAL_ATTENDANCE_COMMANDS = /* @__PURE__ */ new Set([
|
|
27286
|
+
"select_session",
|
|
27287
|
+
"open_panel",
|
|
27288
|
+
"invoke_provider_script",
|
|
27289
|
+
"set_mode",
|
|
27290
|
+
"change_model",
|
|
27291
|
+
"set_thought_level",
|
|
27292
|
+
"resolve_action",
|
|
27293
|
+
"pty_input"
|
|
27294
|
+
]);
|
|
27295
|
+
|
|
27075
27296
|
// src/commands/chat-commands.ts
|
|
27076
27297
|
init_contracts();
|
|
27077
27298
|
init_provider_input_support();
|
|
@@ -31411,11 +31632,38 @@ var DaemonCommandHandler = class {
|
|
|
31411
31632
|
setAgentStreamManager(manager) {
|
|
31412
31633
|
this._agentStream = manager;
|
|
31413
31634
|
}
|
|
31635
|
+
/**
|
|
31636
|
+
* When a command in the manual-attendance set arrives for a session this
|
|
31637
|
+
* daemon hosts, stamp the live instance so auto-approve holds while the user
|
|
31638
|
+
* drives the session by hand. Provider-common: the signal is the command
|
|
31639
|
+
* (foreground select_session / open_panel, controlbar invoke_provider_script
|
|
31640
|
+
* / set_mode / change_model / set_thought_level, manual resolve_action,
|
|
31641
|
+
* pty_input), never any CLI-specific modal text — so it works identically for
|
|
31642
|
+
* every CLI/ACP provider. send_chat is deliberately excluded because a
|
|
31643
|
+
* coordinator delegating a task to a worker also uses send_chat; counting it
|
|
31644
|
+
* would wrongly suppress the worker's delegated auto-approve. For a remote
|
|
31645
|
+
* mesh worker session the controlbar commands are forwarded to the owning
|
|
31646
|
+
* worker daemon, which runs this same hook there, so attendance is recorded
|
|
31647
|
+
* on the daemon that actually hosts the instance.
|
|
31648
|
+
*/
|
|
31649
|
+
noteManualAttendanceIfApplicable(cmd, args) {
|
|
31650
|
+
if (!MANUAL_ATTENDANCE_COMMANDS.has(cmd)) return;
|
|
31651
|
+
const sessionId = this._currentRoute.session?.sessionId || (typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "");
|
|
31652
|
+
if (!sessionId) return;
|
|
31653
|
+
const session = this._ctx.sessionRegistry?.get(sessionId);
|
|
31654
|
+
const instanceKey = session?.adapterKey || session?.instanceKey || sessionId;
|
|
31655
|
+
const instance = this._ctx.instanceManager?.getInstance(instanceKey);
|
|
31656
|
+
try {
|
|
31657
|
+
instance?.noteManualInteraction?.();
|
|
31658
|
+
} catch {
|
|
31659
|
+
}
|
|
31660
|
+
}
|
|
31414
31661
|
// ─── Command Dispatcher ──────────────────────────
|
|
31415
31662
|
async handle(cmd, args) {
|
|
31416
31663
|
this._currentRoute = this.resolveRoute(args);
|
|
31417
31664
|
const startedAt = Date.now();
|
|
31418
31665
|
this.logCommandStart(cmd, args);
|
|
31666
|
+
this.noteManualAttendanceIfApplicable(cmd, args);
|
|
31419
31667
|
let result;
|
|
31420
31668
|
if (isGitCommandName(cmd)) {
|
|
31421
31669
|
result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
|
|
@@ -32150,10 +32398,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32150
32398
|
const path42 = __require("path");
|
|
32151
32399
|
const { spawnSync: spawnSync2 } = __require("child_process");
|
|
32152
32400
|
const file = ext.loadExternalSources();
|
|
32153
|
-
if (file.sources.some((
|
|
32401
|
+
if (file.sources.some((s2) => s2.name === requestedName)) {
|
|
32154
32402
|
return { success: false, error: `source name "${requestedName}" is already registered` };
|
|
32155
32403
|
}
|
|
32156
|
-
if (file.sources.some((
|
|
32404
|
+
if (file.sources.some((s2) => s2.url === url && s2.ref === ref)) {
|
|
32157
32405
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
32158
32406
|
}
|
|
32159
32407
|
const sourceDir = path42.join(ext.externalRoot(), requestedName);
|
|
@@ -32215,7 +32463,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32215
32463
|
const fs32 = __require("fs");
|
|
32216
32464
|
const path42 = __require("path");
|
|
32217
32465
|
const file = ext.loadExternalSources();
|
|
32218
|
-
const match = file.sources.find((
|
|
32466
|
+
const match = file.sources.find((s2) => s2.name === name);
|
|
32219
32467
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
32220
32468
|
const sourceDir = path42.join(ext.externalRoot(), name);
|
|
32221
32469
|
if (fs32.existsSync(sourceDir)) {
|
|
@@ -32227,7 +32475,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32227
32475
|
}
|
|
32228
32476
|
ext.saveExternalSources({
|
|
32229
32477
|
schema: 1,
|
|
32230
|
-
sources: file.sources.filter((
|
|
32478
|
+
sources: file.sources.filter((s2) => s2.name !== name)
|
|
32231
32479
|
});
|
|
32232
32480
|
const active = ext.loadProvidersActive();
|
|
32233
32481
|
const filteredActive = {};
|
|
@@ -32251,10 +32499,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32251
32499
|
const file = ext.loadExternalSources();
|
|
32252
32500
|
const inventory = ext.inventoryExternalSources();
|
|
32253
32501
|
const active = ext.loadProvidersActive();
|
|
32254
|
-
const sources = file.sources.map((
|
|
32255
|
-
const inv = inventory.find((e) => e.sourceName ===
|
|
32502
|
+
const sources = file.sources.map((s2) => {
|
|
32503
|
+
const inv = inventory.find((e) => e.sourceName === s2.name);
|
|
32256
32504
|
return {
|
|
32257
|
-
...
|
|
32505
|
+
...s2,
|
|
32258
32506
|
providers: inv?.providers ?? {}
|
|
32259
32507
|
};
|
|
32260
32508
|
});
|
|
@@ -32431,6 +32679,21 @@ import * as path21 from "path";
|
|
|
32431
32679
|
// src/providers/spec/adapter.ts
|
|
32432
32680
|
init_terminal_screen();
|
|
32433
32681
|
import { DEFAULT_SESSION_HOST_COLS as DEFAULT_SESSION_HOST_COLS5, DEFAULT_SESSION_HOST_ROWS as DEFAULT_SESSION_HOST_ROWS5 } from "@adhdev/session-host-core";
|
|
32682
|
+
var MAX_PTY_EVENTS = 300;
|
|
32683
|
+
var EVENT_CONTENT_CAP = 240;
|
|
32684
|
+
function escapeControl(text) {
|
|
32685
|
+
return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
|
|
32686
|
+
const code = ch.charCodeAt(0);
|
|
32687
|
+
if (ch === "\r") return "\\r";
|
|
32688
|
+
if (ch === "\n") return "\\n";
|
|
32689
|
+
if (ch === " ") return "\\t";
|
|
32690
|
+
if (code === 27) return "\\x1b";
|
|
32691
|
+
return "\\x" + code.toString(16).padStart(2, "0");
|
|
32692
|
+
});
|
|
32693
|
+
}
|
|
32694
|
+
function capPreview(text) {
|
|
32695
|
+
return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
|
|
32696
|
+
}
|
|
32434
32697
|
var TerminalAdapter = class {
|
|
32435
32698
|
constructor(opts, handlers) {
|
|
32436
32699
|
this.opts = opts;
|
|
@@ -32457,6 +32720,9 @@ var TerminalAdapter = class {
|
|
|
32457
32720
|
screenTimer = null;
|
|
32458
32721
|
tickTimer = null;
|
|
32459
32722
|
lastScreen = "";
|
|
32723
|
+
/** Debug-only ring buffer of PTY input/output/resize/cursor events. */
|
|
32724
|
+
events = [];
|
|
32725
|
+
lastCursorKey = "";
|
|
32460
32726
|
start() {
|
|
32461
32727
|
const env = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
|
|
32462
32728
|
this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
|
|
@@ -32465,10 +32731,12 @@ var TerminalAdapter = class {
|
|
|
32465
32731
|
cols: this.cols,
|
|
32466
32732
|
rows: this.rows
|
|
32467
32733
|
});
|
|
32734
|
+
this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
|
|
32468
32735
|
this.handlers.init?.({ pid: this.pty.pid });
|
|
32469
32736
|
this.pty.onData((chunk) => this.onChunk(chunk));
|
|
32470
32737
|
this.pty.onExit((info) => {
|
|
32471
32738
|
this.stopTimers();
|
|
32739
|
+
this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
|
|
32472
32740
|
this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
|
|
32473
32741
|
this.pty = null;
|
|
32474
32742
|
});
|
|
@@ -32479,6 +32747,7 @@ var TerminalAdapter = class {
|
|
|
32479
32747
|
resize(cols, rows) {
|
|
32480
32748
|
this.cols = cols;
|
|
32481
32749
|
this.rows = rows;
|
|
32750
|
+
this.recordEvent("resize", `${cols}x${rows}`);
|
|
32482
32751
|
this.pty?.resize(cols, rows);
|
|
32483
32752
|
this.screen.resize(rows, cols);
|
|
32484
32753
|
}
|
|
@@ -32499,8 +32768,21 @@ var TerminalAdapter = class {
|
|
|
32499
32768
|
return { row: pos.row, col: pos.col };
|
|
32500
32769
|
}
|
|
32501
32770
|
send_keys(text) {
|
|
32771
|
+
this.recordEvent("input", capPreview(escapeControl(text)), text.length);
|
|
32502
32772
|
this.pty?.write(text);
|
|
32503
32773
|
}
|
|
32774
|
+
/** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
|
|
32775
|
+
* first. Pure observation — never consulted by the FSM. */
|
|
32776
|
+
getEventTimeline(limit = MAX_PTY_EVENTS) {
|
|
32777
|
+
const n = Math.max(0, Math.min(limit, this.events.length));
|
|
32778
|
+
return this.events.slice(this.events.length - n);
|
|
32779
|
+
}
|
|
32780
|
+
recordEvent(kind, content, bytes) {
|
|
32781
|
+
const ev = { ts: Date.now(), kind, content };
|
|
32782
|
+
if (typeof bytes === "number") ev.bytes = bytes;
|
|
32783
|
+
this.events.push(ev);
|
|
32784
|
+
if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
|
|
32785
|
+
}
|
|
32504
32786
|
kill() {
|
|
32505
32787
|
this.stopTimers();
|
|
32506
32788
|
try {
|
|
@@ -32511,6 +32793,7 @@ var TerminalAdapter = class {
|
|
|
32511
32793
|
this.screen.dispose();
|
|
32512
32794
|
}
|
|
32513
32795
|
onChunk(chunk) {
|
|
32796
|
+
this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
|
|
32514
32797
|
try {
|
|
32515
32798
|
this.handlers.on_pty_data?.(chunk);
|
|
32516
32799
|
} catch {
|
|
@@ -32520,6 +32803,12 @@ var TerminalAdapter = class {
|
|
|
32520
32803
|
this.screenTimer = setTimeout(() => {
|
|
32521
32804
|
this.screenTimer = null;
|
|
32522
32805
|
const snap = this.computeScreen();
|
|
32806
|
+
const cur = this.screen.getCursorPosition();
|
|
32807
|
+
const curKey = `${cur.row},${cur.col}`;
|
|
32808
|
+
if (curKey !== this.lastCursorKey) {
|
|
32809
|
+
this.lastCursorKey = curKey;
|
|
32810
|
+
this.recordEvent("cursor", `(${cur.row},${cur.col})`);
|
|
32811
|
+
}
|
|
32523
32812
|
if (snap === this.lastScreen) return;
|
|
32524
32813
|
this.lastScreen = snap;
|
|
32525
32814
|
try {
|
|
@@ -32604,20 +32893,40 @@ function applyPreLaunchTrust(trust, workingDir) {
|
|
|
32604
32893
|
|
|
32605
32894
|
// src/providers/spec/fsm-driver.ts
|
|
32606
32895
|
init_logger();
|
|
32607
|
-
function countNewlines(
|
|
32896
|
+
function countNewlines(s2) {
|
|
32608
32897
|
let n = 0;
|
|
32609
|
-
for (let i = 0; i <
|
|
32898
|
+
for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
|
|
32610
32899
|
return n;
|
|
32611
32900
|
}
|
|
32612
32901
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
32613
32902
|
var WIN32_SUBMIT_RESEND_GAP_MS = 350;
|
|
32614
32903
|
var WIN32_SUBMIT_MAX_RESENDS = 14;
|
|
32904
|
+
var WIN32_SUBMIT_SETTLE_MS = 500;
|
|
32905
|
+
var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
|
|
32906
|
+
var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
|
|
32907
|
+
var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
|
|
32908
|
+
var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
|
|
32615
32909
|
function resolveSubmitDelayMs(specBeforeSubmit, text) {
|
|
32616
32910
|
const lines = countNewlines(text);
|
|
32617
32911
|
const linesBonus = Math.min(800, lines * 80);
|
|
32618
32912
|
const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
|
|
32619
32913
|
return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
|
|
32620
32914
|
}
|
|
32915
|
+
function chunkPreservingSurrogates(text, size) {
|
|
32916
|
+
const chunks = [];
|
|
32917
|
+
let offset = 0;
|
|
32918
|
+
while (offset < text.length) {
|
|
32919
|
+
let end = Math.min(text.length, offset + size);
|
|
32920
|
+
if (end < text.length) {
|
|
32921
|
+
const code = text.charCodeAt(end - 1);
|
|
32922
|
+
if (code >= 55296 && code <= 56319) end -= 1;
|
|
32923
|
+
}
|
|
32924
|
+
if (end <= offset) end = Math.min(text.length, offset + size);
|
|
32925
|
+
chunks.push(text.slice(offset, end));
|
|
32926
|
+
offset = end;
|
|
32927
|
+
}
|
|
32928
|
+
return chunks;
|
|
32929
|
+
}
|
|
32621
32930
|
function guessExt(mime) {
|
|
32622
32931
|
if (/png/i.test(mime)) return ".png";
|
|
32623
32932
|
if (/jpe?g/i.test(mime)) return ".jpg";
|
|
@@ -32633,7 +32942,10 @@ var FsmDriver = class {
|
|
|
32633
32942
|
this.buildAdapterOpts(),
|
|
32634
32943
|
{
|
|
32635
32944
|
init: () => this.emitInitialState(),
|
|
32636
|
-
on_pty_data: (chunk) =>
|
|
32945
|
+
on_pty_data: (chunk) => {
|
|
32946
|
+
this.lastPtyDataAt = Date.now();
|
|
32947
|
+
this.emit({ kind: "pty_data", chunk });
|
|
32948
|
+
},
|
|
32637
32949
|
on_screen_changed: () => this.reevaluate(),
|
|
32638
32950
|
on_exit: ({ exitCode }) => this.handleExit(exitCode)
|
|
32639
32951
|
}
|
|
@@ -32667,6 +32979,16 @@ var FsmDriver = class {
|
|
|
32667
32979
|
* WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
|
|
32668
32980
|
* leaves idle (submitted) or the resend budget is spent. */
|
|
32669
32981
|
win32SubmitTimer = null;
|
|
32982
|
+
/** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
|
|
32983
|
+
* on_pty_data — including the echo of text written into the composer — so the
|
|
32984
|
+
* win32 submit settle-gate can tell when input has finished landing. */
|
|
32985
|
+
lastPtyDataAt = 0;
|
|
32986
|
+
/** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
|
|
32987
|
+
* the gap between writing a chunk and its echo so the settle-gate does not
|
|
32988
|
+
* declare "quiet" mid-write. */
|
|
32989
|
+
lastWin32WriteAt = 0;
|
|
32990
|
+
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
32991
|
+
win32WriteTimer = null;
|
|
32670
32992
|
currentEval = null;
|
|
32671
32993
|
stateHistory = [];
|
|
32672
32994
|
prevStateAt = 0;
|
|
@@ -32787,6 +33109,10 @@ var FsmDriver = class {
|
|
|
32787
33109
|
clearTimeout(this.win32SubmitTimer);
|
|
32788
33110
|
this.win32SubmitTimer = null;
|
|
32789
33111
|
}
|
|
33112
|
+
if (this.win32WriteTimer) {
|
|
33113
|
+
clearTimeout(this.win32WriteTimer);
|
|
33114
|
+
this.win32WriteTimer = null;
|
|
33115
|
+
}
|
|
32790
33116
|
this.specWatcher?.close();
|
|
32791
33117
|
this.adapter.kill();
|
|
32792
33118
|
}
|
|
@@ -32817,11 +33143,15 @@ var FsmDriver = class {
|
|
|
32817
33143
|
getFsmSnapshotHistory() {
|
|
32818
33144
|
return this.fsmSnapshotHistory;
|
|
32819
33145
|
}
|
|
33146
|
+
/** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
|
|
33147
|
+
getEventTimeline(limit) {
|
|
33148
|
+
return this.adapter.getEventTimeline(limit);
|
|
33149
|
+
}
|
|
32820
33150
|
getSections() {
|
|
32821
33151
|
try {
|
|
32822
33152
|
const screen = this.adapter.snapshot();
|
|
32823
33153
|
const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
32824
|
-
return resolveSections(this.spec.sections ?? {}, lines).map((
|
|
33154
|
+
return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
|
|
32825
33155
|
} catch {
|
|
32826
33156
|
return null;
|
|
32827
33157
|
}
|
|
@@ -33199,7 +33529,7 @@ var FsmDriver = class {
|
|
|
33199
33529
|
const perChar = sm.delay_ms_per_char ?? 0;
|
|
33200
33530
|
const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
|
|
33201
33531
|
if (process.platform === "win32") {
|
|
33202
|
-
this.
|
|
33532
|
+
this.writeWin32Body(text);
|
|
33203
33533
|
this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
|
|
33204
33534
|
return;
|
|
33205
33535
|
}
|
|
@@ -33225,20 +33555,72 @@ var FsmDriver = class {
|
|
|
33225
33555
|
const st = stateById(this.spec, this.currentStateId);
|
|
33226
33556
|
return st ? statusForState(st) : "idle";
|
|
33227
33557
|
}
|
|
33558
|
+
/** Record a win32 body write so the settle-gate counts it as input activity
|
|
33559
|
+
* even before the echo arrives. */
|
|
33560
|
+
markWin32Write() {
|
|
33561
|
+
this.lastWin32WriteAt = Date.now();
|
|
33562
|
+
}
|
|
33563
|
+
/** Most recent win32 input activity — a write we issued OR a PTY output chunk
|
|
33564
|
+
* (echo). The submit settle-gate waits for this to go quiet. */
|
|
33565
|
+
lastWin32InputActivityAt() {
|
|
33566
|
+
return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
|
|
33567
|
+
}
|
|
33228
33568
|
/**
|
|
33229
|
-
*
|
|
33230
|
-
*
|
|
33231
|
-
* a
|
|
33232
|
-
*
|
|
33233
|
-
*
|
|
33234
|
-
*
|
|
33235
|
-
|
|
33569
|
+
* Write the message body to the PTY for win32, paced into bounded chunks. A
|
|
33570
|
+
* single unbounded ConPTY write can overflow the input pipe and drop leading
|
|
33571
|
+
* bytes; splitting it with a short inter-chunk gap keeps the console input
|
|
33572
|
+
* buffer from overflowing. Small bodies still go out in a single write. Each
|
|
33573
|
+
* chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
|
|
33574
|
+
* the final chunk is out and echoed.
|
|
33575
|
+
*/
|
|
33576
|
+
writeWin32Body(text) {
|
|
33577
|
+
if (this.win32WriteTimer) {
|
|
33578
|
+
clearTimeout(this.win32WriteTimer);
|
|
33579
|
+
this.win32WriteTimer = null;
|
|
33580
|
+
}
|
|
33581
|
+
if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
|
|
33582
|
+
this.markWin32Write();
|
|
33583
|
+
this.adapter.send_keys(text);
|
|
33584
|
+
return;
|
|
33585
|
+
}
|
|
33586
|
+
const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
|
|
33587
|
+
let idx = 0;
|
|
33588
|
+
const writeNext = () => {
|
|
33589
|
+
this.win32WriteTimer = null;
|
|
33590
|
+
if (idx >= chunks.length) return;
|
|
33591
|
+
this.markWin32Write();
|
|
33592
|
+
this.adapter.send_keys(chunks[idx]);
|
|
33593
|
+
idx += 1;
|
|
33594
|
+
if (idx < chunks.length) {
|
|
33595
|
+
this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
|
|
33596
|
+
}
|
|
33597
|
+
};
|
|
33598
|
+
writeNext();
|
|
33599
|
+
}
|
|
33600
|
+
/**
|
|
33601
|
+
* win32 submit. Two phases:
|
|
33602
|
+
*
|
|
33603
|
+
* Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
|
|
33604
|
+
* for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
|
|
33605
|
+
* (possibly multi-KB / multiline) body has finished arriving in the composer
|
|
33606
|
+
* and echoing. Honors an initial minimum delay and is bounded by
|
|
33607
|
+
* WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
|
|
33608
|
+
* This is what stops a long message from being submitted half-arrived (its
|
|
33609
|
+
* leading lines lost). A short message settles almost immediately.
|
|
33610
|
+
*
|
|
33611
|
+
* Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
|
|
33612
|
+
* if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
|
|
33613
|
+
* newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
|
|
33614
|
+
* (a stale/edge status never suppresses it); resends are gated on still being
|
|
33615
|
+
* idle and stop the instant the agent leaves idle (submitted → generating /
|
|
33616
|
+
* approval). This preserves the win32 lone-CR-swallow handling.
|
|
33236
33617
|
*/
|
|
33237
33618
|
scheduleWin32Submit(submitKey, initialDelayMs) {
|
|
33238
33619
|
if (this.win32SubmitTimer) {
|
|
33239
33620
|
clearTimeout(this.win32SubmitTimer);
|
|
33240
33621
|
this.win32SubmitTimer = null;
|
|
33241
33622
|
}
|
|
33623
|
+
const startedAt = Date.now();
|
|
33242
33624
|
const fire = (attempt) => {
|
|
33243
33625
|
this.win32SubmitTimer = null;
|
|
33244
33626
|
this.adapter.send_keys(submitKey);
|
|
@@ -33251,8 +33633,20 @@ var FsmDriver = class {
|
|
|
33251
33633
|
fire(attempt + 1);
|
|
33252
33634
|
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
33253
33635
|
};
|
|
33254
|
-
|
|
33255
|
-
|
|
33636
|
+
const waitForSettle = () => {
|
|
33637
|
+
this.win32SubmitTimer = null;
|
|
33638
|
+
const now = Date.now();
|
|
33639
|
+
const quietFor = now - this.lastWin32InputActivityAt();
|
|
33640
|
+
const waited = now - startedAt;
|
|
33641
|
+
if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
|
|
33642
|
+
fire(0);
|
|
33643
|
+
return;
|
|
33644
|
+
}
|
|
33645
|
+
const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
|
|
33646
|
+
this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
|
|
33647
|
+
};
|
|
33648
|
+
if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
|
|
33649
|
+
else waitForSettle();
|
|
33256
33650
|
}
|
|
33257
33651
|
handleClickControl(controlId, payload) {
|
|
33258
33652
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
|
|
@@ -33365,7 +33759,8 @@ function summarizeTransition(t) {
|
|
|
33365
33759
|
return out;
|
|
33366
33760
|
}
|
|
33367
33761
|
function flattenCond(c, out, depth) {
|
|
33368
|
-
|
|
33762
|
+
const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
|
|
33763
|
+
out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
|
|
33369
33764
|
for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
|
|
33370
33765
|
}
|
|
33371
33766
|
function findStable(c) {
|
|
@@ -34083,8 +34478,8 @@ function projectToolBlock(block2, role, tmap) {
|
|
|
34083
34478
|
}
|
|
34084
34479
|
return null;
|
|
34085
34480
|
}
|
|
34086
|
-
function oneLine(
|
|
34087
|
-
const flat =
|
|
34481
|
+
function oneLine(s2, max) {
|
|
34482
|
+
const flat = s2.replace(/\s+/g, " ").trim();
|
|
34088
34483
|
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
34089
34484
|
}
|
|
34090
34485
|
function parseTimestamp(v) {
|
|
@@ -34104,10 +34499,10 @@ function parseTimestamp(v) {
|
|
|
34104
34499
|
return null;
|
|
34105
34500
|
}
|
|
34106
34501
|
function normalizeRole(r) {
|
|
34107
|
-
const
|
|
34108
|
-
if (
|
|
34109
|
-
if (
|
|
34110
|
-
if (
|
|
34502
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
34503
|
+
if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
|
|
34504
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
34505
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
34111
34506
|
return "system";
|
|
34112
34507
|
}
|
|
34113
34508
|
function stringifyContent(v) {
|
|
@@ -34155,18 +34550,18 @@ function compileWhere(src) {
|
|
|
34155
34550
|
return (record) => ors.some((ands) => ands.every((t) => evalTerm(t, record)));
|
|
34156
34551
|
}
|
|
34157
34552
|
function parseTerm(src) {
|
|
34158
|
-
let
|
|
34553
|
+
let s2 = src.trim();
|
|
34159
34554
|
let negate = false;
|
|
34160
|
-
if (
|
|
34555
|
+
if (s2.startsWith("!")) {
|
|
34161
34556
|
negate = true;
|
|
34162
|
-
|
|
34557
|
+
s2 = s2.slice(1).trim();
|
|
34163
34558
|
}
|
|
34164
|
-
const fnMatch =
|
|
34559
|
+
const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
|
|
34165
34560
|
if (fnMatch) {
|
|
34166
34561
|
const [, op2, pathExpr, litExpr] = fnMatch;
|
|
34167
34562
|
return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
|
|
34168
34563
|
}
|
|
34169
|
-
const opMatch =
|
|
34564
|
+
const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
|
|
34170
34565
|
if (!opMatch) return null;
|
|
34171
34566
|
const [, lhs, op, rhsRaw] = opMatch;
|
|
34172
34567
|
return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
|
|
@@ -34598,7 +34993,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34598
34993
|
try {
|
|
34599
34994
|
const sections = this.driver.getSections();
|
|
34600
34995
|
if (sectionId && sections) {
|
|
34601
|
-
const hit = sections.find((
|
|
34996
|
+
const hit = sections.find((s2) => s2.id === sectionId);
|
|
34602
34997
|
if (hit) return hit.text;
|
|
34603
34998
|
}
|
|
34604
34999
|
return this.driver.getScreen();
|
|
@@ -34613,7 +35008,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34613
35008
|
screen = this.driver.snapshot();
|
|
34614
35009
|
const driverSections = this.driver.getSections?.();
|
|
34615
35010
|
if (driverSections) {
|
|
34616
|
-
sections = Object.fromEntries(driverSections.map((
|
|
35011
|
+
sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
|
|
34617
35012
|
} else {
|
|
34618
35013
|
sections = this.readCurrentScreenSections(screen);
|
|
34619
35014
|
}
|
|
@@ -34659,6 +35054,10 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34659
35054
|
// answers "why did this rule fire" after the fact, unlike the live
|
|
34660
35055
|
// `fsm` field which only reflects the current instant.
|
|
34661
35056
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35057
|
+
// PTY input/output/resize/cursor event timeline (debug-only) so the
|
|
35058
|
+
// snapshot shows what we typed / what the PTY printed around each
|
|
35059
|
+
// status transition. Null for drivers without the timeline.
|
|
35060
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
34662
35061
|
// Extended fields
|
|
34663
35062
|
name: this.cliName,
|
|
34664
35063
|
status: this.getStatus().status,
|
|
@@ -35023,6 +35422,8 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35023
35422
|
// v4 FSM transition snapshot history — the captured pre-transition
|
|
35024
35423
|
// evaluation table at each transition (null for v3 specs).
|
|
35025
35424
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35425
|
+
// PTY input/output/resize/cursor event timeline (debug-only).
|
|
35426
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
35026
35427
|
messages,
|
|
35027
35428
|
committedMessages: messages
|
|
35028
35429
|
};
|
|
@@ -35067,6 +35468,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
|
|
|
35067
35468
|
|
|
35068
35469
|
// src/providers/cli-provider-instance.ts
|
|
35069
35470
|
init_logger();
|
|
35471
|
+
init_mesh_event_trace();
|
|
35070
35472
|
init_control_effects();
|
|
35071
35473
|
init_approval_utils();
|
|
35072
35474
|
init_provider_patch_state();
|
|
@@ -35369,6 +35771,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35369
35771
|
// a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
|
|
35370
35772
|
// brief generating flip does not immediately wipe the settle clock.
|
|
35371
35773
|
autoApproveInactiveSince = 0;
|
|
35774
|
+
// Provider-common manual-attendance signal: while a human is actively driving
|
|
35775
|
+
// this session from the dashboard, auto-approve holds so they can take manual
|
|
35776
|
+
// control. Background mesh workers are never attended → delegated auto-approve
|
|
35777
|
+
// is unaffected.
|
|
35778
|
+
manualAttendance = new ManualAttendanceTracker();
|
|
35372
35779
|
controlValues = {};
|
|
35373
35780
|
summaryMetadata = void 0;
|
|
35374
35781
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -35644,7 +36051,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35644
36051
|
}
|
|
35645
36052
|
getHotChatSessionState() {
|
|
35646
36053
|
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|
|
35647
|
-
const autoApproveActive = adapterStatus.status
|
|
36054
|
+
const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
|
|
35648
36055
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
|
|
35649
36056
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
|
|
35650
36057
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
@@ -35659,7 +36066,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35659
36066
|
}
|
|
35660
36067
|
getSessionModalState(sessionId) {
|
|
35661
36068
|
const adapterStatus = this.adapter.getStatus({ allowParse: true });
|
|
35662
|
-
const autoApproveActive = adapterStatus.status
|
|
36069
|
+
const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
|
|
35663
36070
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
|
|
35664
36071
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
|
|
35665
36072
|
const dirName = workingDirBasename(this.workingDir);
|
|
@@ -35740,7 +36147,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
35740
36147
|
} catch {
|
|
35741
36148
|
return null;
|
|
35742
36149
|
}
|
|
35743
|
-
if (adapterStatus.status === "waiting_approval" && !this.
|
|
36150
|
+
if (adapterStatus.status === "waiting_approval" && !this.autoApproveEffectivelyActive(adapterStatus.status)) {
|
|
35744
36151
|
return "waiting_approval";
|
|
35745
36152
|
}
|
|
35746
36153
|
return null;
|
|
@@ -36113,6 +36520,23 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36113
36520
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
36114
36521
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|
|
36115
36522
|
}
|
|
36523
|
+
// EVTTRACE (observation-only): is this a mesh worker session whose completion
|
|
36524
|
+
// events must route to a coordinator? Used purely to gate trace logging so a
|
|
36525
|
+
// non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
|
|
36526
|
+
isMeshWorkerSession() {
|
|
36527
|
+
return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
|
|
36528
|
+
}
|
|
36529
|
+
// EVTTRACE correlation context for this session's completion lifecycle. taskId is
|
|
36530
|
+
// the primary grep anchor; instanceId is the session fallback.
|
|
36531
|
+
meshTraceCtx(event = "agent:generating_completed") {
|
|
36532
|
+
return {
|
|
36533
|
+
taskId: this.settings.meshActiveTaskId,
|
|
36534
|
+
sessionId: this.instanceId,
|
|
36535
|
+
nodeId: this.settings.meshNodeId,
|
|
36536
|
+
meshId: this.settings.meshNodeFor,
|
|
36537
|
+
event
|
|
36538
|
+
};
|
|
36539
|
+
}
|
|
36116
36540
|
flushCompletedDebounceIfFinalized() {
|
|
36117
36541
|
const pending = this.completedDebouncePending;
|
|
36118
36542
|
if (!pending) {
|
|
@@ -36133,24 +36557,33 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36133
36557
|
if (block2) {
|
|
36134
36558
|
const blockReason = block2.reason;
|
|
36135
36559
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
36136
|
-
|
|
36137
|
-
|
|
36560
|
+
const isTranscriptEvidenceGate = block2.allowTimeout === true;
|
|
36561
|
+
LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
36562
|
+
if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
|
|
36138
36563
|
if (pending.loggedBlockReason !== blockReason) {
|
|
36139
36564
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
36565
|
+
if (this.isMeshWorkerSession()) {
|
|
36566
|
+
traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
|
|
36567
|
+
}
|
|
36140
36568
|
pending.loggedBlockReason = blockReason;
|
|
36141
36569
|
}
|
|
36142
36570
|
this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
|
|
36143
36571
|
return;
|
|
36144
36572
|
}
|
|
36573
|
+
const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
|
|
36145
36574
|
const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
|
|
36146
36575
|
blockReason,
|
|
36147
36576
|
latestStatus,
|
|
36148
36577
|
latestVisibleStatus,
|
|
36149
36578
|
waitedMs,
|
|
36150
36579
|
pending,
|
|
36151
|
-
emittedAfterFinalizationTimeout
|
|
36580
|
+
emittedAfterFinalizationTimeout
|
|
36152
36581
|
});
|
|
36153
|
-
|
|
36582
|
+
completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
|
|
36583
|
+
LOG.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
|
|
36584
|
+
if (this.isMeshWorkerSession()) {
|
|
36585
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
|
|
36586
|
+
}
|
|
36154
36587
|
this.pushEvent({
|
|
36155
36588
|
event: "agent:generating_completed",
|
|
36156
36589
|
chatTitle: pending.chatTitle,
|
|
@@ -36173,6 +36606,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36173
36606
|
return;
|
|
36174
36607
|
}
|
|
36175
36608
|
LOG.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
|
|
36609
|
+
if (this.isMeshWorkerSession()) {
|
|
36610
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
|
|
36611
|
+
}
|
|
36176
36612
|
this.pushEvent({
|
|
36177
36613
|
event: "agent:generating_completed",
|
|
36178
36614
|
chatTitle: pending.chatTitle,
|
|
@@ -36186,6 +36622,18 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36186
36622
|
this.lastApprovalEventFingerprint = "";
|
|
36187
36623
|
}
|
|
36188
36624
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
36625
|
+
if (adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove() && this.manualAttendance.isAttended(now)) {
|
|
36626
|
+
this.lastAutoApprovalSignature = "";
|
|
36627
|
+
this.pendingAutoApprovalSignature = "";
|
|
36628
|
+
this.pendingAutoApprovalSince = 0;
|
|
36629
|
+
this.autoApproveInactiveSince = 0;
|
|
36630
|
+
if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
|
|
36631
|
+
this.autoApproveSettleTimer = setTimeout(() => {
|
|
36632
|
+
this.autoApproveSettleTimer = null;
|
|
36633
|
+
this.recheckAutoApproveSettled();
|
|
36634
|
+
}, this.manualAttendance.remainingMs(now) + 20);
|
|
36635
|
+
return false;
|
|
36636
|
+
}
|
|
36189
36637
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
36190
36638
|
if (!autoApproveActive) {
|
|
36191
36639
|
this.lastAutoApprovalSignature = "";
|
|
@@ -36399,6 +36847,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36399
36847
|
if (missingEvidence && !hasMeshContext) {
|
|
36400
36848
|
LOG.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
|
|
36401
36849
|
} else {
|
|
36850
|
+
if (this.isMeshWorkerSession()) {
|
|
36851
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
|
|
36852
|
+
}
|
|
36402
36853
|
this.pushEvent({
|
|
36403
36854
|
event: "agent:generating_completed",
|
|
36404
36855
|
chatTitle,
|
|
@@ -36475,6 +36926,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36475
36926
|
const monitorParsedStatus = parsedStatus;
|
|
36476
36927
|
for (const me of monitorEvents) {
|
|
36477
36928
|
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
36929
|
+
if (this.isMeshWorkerSession()) {
|
|
36930
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
|
|
36931
|
+
}
|
|
36478
36932
|
this.pushEvent({
|
|
36479
36933
|
event: "agent:generating_completed",
|
|
36480
36934
|
chatTitle,
|
|
@@ -36651,6 +37105,21 @@ ${effect.notification.body || ""}`.trim();
|
|
|
36651
37105
|
}
|
|
36652
37106
|
return false;
|
|
36653
37107
|
}
|
|
37108
|
+
/** @see ProviderInstance.noteManualInteraction */
|
|
37109
|
+
noteManualInteraction(now = Date.now()) {
|
|
37110
|
+
this.manualAttendance.note(now);
|
|
37111
|
+
}
|
|
37112
|
+
/**
|
|
37113
|
+
* Whether auto-approve should be treated as active *right now* for display
|
|
37114
|
+
* and firing decisions: the configured intent AND the user is not currently
|
|
37115
|
+
* attending this session by hand. When a human is attending, auto-approve is
|
|
37116
|
+
* held so the modal stays visible and they can drive it via the controlbar.
|
|
37117
|
+
* Provider-agnostic — the attendance signal is the command set, never any
|
|
37118
|
+
* CLI-specific modal text.
|
|
37119
|
+
*/
|
|
37120
|
+
autoApproveEffectivelyActive(status, now = Date.now()) {
|
|
37121
|
+
return status === "waiting_approval" && this.shouldAutoApprove() && !this.manualAttendance.isAttended(now);
|
|
37122
|
+
}
|
|
36654
37123
|
recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
|
|
36655
37124
|
this.appendRuntimeSystemMessage(
|
|
36656
37125
|
formatAutoApprovalMessage(modalMessage, buttonLabel),
|
|
@@ -37601,7 +38070,7 @@ var AcpProviderInstance = class {
|
|
|
37601
38070
|
input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
|
|
37602
38071
|
});
|
|
37603
38072
|
}
|
|
37604
|
-
if (this.settings.autoApprove !== false) {
|
|
38073
|
+
if (this.settings.autoApprove !== false && !this.manualAttendance.isAttended()) {
|
|
37605
38074
|
const toolTitle = tc.title || tc.toolCallId || "tool call";
|
|
37606
38075
|
this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
|
|
37607
38076
|
this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
|
|
@@ -37832,6 +38301,15 @@ var AcpProviderInstance = class {
|
|
|
37832
38301
|
this.detectStatusTransition();
|
|
37833
38302
|
}
|
|
37834
38303
|
permissionResolvers = [];
|
|
38304
|
+
// Provider-common manual-attendance signal: while a human is actively driving
|
|
38305
|
+
// this session from the dashboard, auto-approve holds so they can decide on
|
|
38306
|
+
// the permission request themselves. Background workers are never attended →
|
|
38307
|
+
// delegated auto-approve is unaffected.
|
|
38308
|
+
manualAttendance = new ManualAttendanceTracker();
|
|
38309
|
+
/** @see ProviderInstance.noteManualInteraction */
|
|
38310
|
+
noteManualInteraction(now = Date.now()) {
|
|
38311
|
+
this.manualAttendance.note(now);
|
|
38312
|
+
}
|
|
37835
38313
|
async resolvePermission(approved) {
|
|
37836
38314
|
const resolver = this.permissionResolvers.shift();
|
|
37837
38315
|
if (resolver) {
|
|
@@ -38989,6 +39467,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
38989
39467
|
);
|
|
38990
39468
|
continue;
|
|
38991
39469
|
}
|
|
39470
|
+
const restoredSettings = { ...this.providerLoader.getSettings(normalizedType) };
|
|
39471
|
+
const coordinatorEntry = getCoordinatorForSession(record.runtimeId);
|
|
39472
|
+
if (coordinatorEntry?.meshId) {
|
|
39473
|
+
restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
|
|
39474
|
+
}
|
|
38992
39475
|
try {
|
|
38993
39476
|
await this.registerCliInstance(
|
|
38994
39477
|
record.runtimeId,
|
|
@@ -38997,7 +39480,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
38997
39480
|
record.workspace,
|
|
38998
39481
|
record.cliArgs,
|
|
38999
39482
|
resolvedProvider,
|
|
39000
|
-
|
|
39483
|
+
restoredSettings,
|
|
39001
39484
|
true,
|
|
39002
39485
|
{
|
|
39003
39486
|
providerSessionId: sessionBinding.providerSessionId,
|
|
@@ -40314,7 +40797,7 @@ function parsePbFile(filePath, sessionId) {
|
|
|
40314
40797
|
}
|
|
40315
40798
|
if (buf.length === 0) return null;
|
|
40316
40799
|
const strings = extractStringsFromBuffer(buf);
|
|
40317
|
-
const meaningful = strings.filter((
|
|
40800
|
+
const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
|
|
40318
40801
|
if (meaningful.length === 0) return null;
|
|
40319
40802
|
const content = meaningful.join("\n");
|
|
40320
40803
|
const sourceMtimeMs = statMtimeMs3(filePath);
|
|
@@ -40522,10 +41005,10 @@ function readSession4(sessionPath) {
|
|
|
40522
41005
|
};
|
|
40523
41006
|
}
|
|
40524
41007
|
function normalizeHermesRole(r) {
|
|
40525
|
-
const
|
|
40526
|
-
if (
|
|
40527
|
-
if (
|
|
40528
|
-
if (
|
|
41008
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41009
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41010
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41011
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
40529
41012
|
return "system";
|
|
40530
41013
|
}
|
|
40531
41014
|
|
|
@@ -40751,10 +41234,10 @@ function safeMtime(p) {
|
|
|
40751
41234
|
}
|
|
40752
41235
|
}
|
|
40753
41236
|
function normalizeRole2(r) {
|
|
40754
|
-
const
|
|
40755
|
-
if (
|
|
40756
|
-
if (
|
|
40757
|
-
if (
|
|
41237
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41238
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41239
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41240
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
40758
41241
|
return "system";
|
|
40759
41242
|
}
|
|
40760
41243
|
|
|
@@ -40774,7 +41257,7 @@ function synthesizeControlsFromControlBar(specControls) {
|
|
|
40774
41257
|
const actionType = ctl?.action?.type;
|
|
40775
41258
|
if (!id || !actionType) return;
|
|
40776
41259
|
const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
|
|
40777
|
-
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((
|
|
41260
|
+
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
|
|
40778
41261
|
if (actionType === "open_picker") {
|
|
40779
41262
|
out.push({
|
|
40780
41263
|
id,
|
|
@@ -47690,7 +48173,7 @@ var DaemonCommandRouter = class {
|
|
|
47690
48173
|
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.";
|
|
47691
48174
|
if (!firstFailedCmd) return base;
|
|
47692
48175
|
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 : "";
|
|
47693
|
-
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((
|
|
48176
|
+
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|
|
47694
48177
|
const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
|
|
47695
48178
|
return [
|
|
47696
48179
|
base,
|
|
@@ -48441,7 +48924,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
48441
48924
|
convergence = "blocked_review";
|
|
48442
48925
|
}
|
|
48443
48926
|
const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
|
|
48444
|
-
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((
|
|
48927
|
+
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
|
|
48445
48928
|
results.push({
|
|
48446
48929
|
nodeId: node.id,
|
|
48447
48930
|
workspace: node.workspace,
|
|
@@ -49438,7 +49921,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
49438
49921
|
return {
|
|
49439
49922
|
success: true,
|
|
49440
49923
|
screenLineCount: lines.length,
|
|
49441
|
-
sections: resolved.map((
|
|
49924
|
+
sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
|
|
49442
49925
|
};
|
|
49443
49926
|
} catch (e) {
|
|
49444
49927
|
return { success: false, error: `resolve failed: ${e.message}` };
|
|
@@ -50007,7 +50490,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50007
50490
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
50008
50491
|
try {
|
|
50009
50492
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
50010
|
-
const status = Array.isArray(args?.status) ? args.status.map((
|
|
50493
|
+
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
50011
50494
|
const rawQueue = getQueue2(meshId, { status });
|
|
50012
50495
|
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
50013
50496
|
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
@@ -50288,7 +50771,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50288
50771
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50289
50772
|
}
|
|
50290
50773
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50291
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
50774
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50292
50775
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50293
50776
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
50294
50777
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50322,7 +50805,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50322
50805
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50323
50806
|
}
|
|
50324
50807
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50325
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
50808
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50326
50809
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50327
50810
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
50328
50811
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50370,7 +50853,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50370
50853
|
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
50371
50854
|
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
50372
50855
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50373
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
50856
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50374
50857
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50375
50858
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
50376
50859
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
@@ -50457,7 +50940,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50457
50940
|
let worktreeCleanup;
|
|
50458
50941
|
if (node?.isLocalWorktree) {
|
|
50459
50942
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50460
|
-
const isRemoteWorktree = nodeDaemonId && nodeDaemonId
|
|
50943
|
+
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
50461
50944
|
if (isRemoteWorktree) {
|
|
50462
50945
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
50463
50946
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50539,7 +51022,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50539
51022
|
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
50540
51023
|
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
50541
51024
|
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
50542
|
-
if (sourceDaemonId && sourceDaemonId
|
|
51025
|
+
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50543
51026
|
const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
50544
51027
|
...typeof args === "object" && args !== null ? args : {},
|
|
50545
51028
|
_meshDirectDispatch: true
|
|
@@ -50781,7 +51264,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50781
51264
|
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
50782
51265
|
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
50783
51266
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50784
|
-
if (nodeDaemonId && nodeDaemonId
|
|
51267
|
+
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50785
51268
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
50786
51269
|
...typeof args === "object" && args !== null ? args : {},
|
|
50787
51270
|
_meshDirectDispatch: true
|
|
@@ -51991,16 +52474,16 @@ var DaemonStatusReporter = class {
|
|
|
51991
52474
|
const now = this.lastStatusSentAt;
|
|
51992
52475
|
const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
|
|
51993
52476
|
const allStates = this.deps.instanceManager.collectAllStates();
|
|
51994
|
-
const ideStates = allStates.filter((
|
|
51995
|
-
const cliStates = allStates.filter((
|
|
51996
|
-
const acpStates = allStates.filter((
|
|
51997
|
-
const ideSummary = ideStates.map((
|
|
51998
|
-
const msgs =
|
|
51999
|
-
const exts =
|
|
52000
|
-
return `${
|
|
52477
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
52478
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
52479
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
52480
|
+
const ideSummary = ideStates.map((s2) => {
|
|
52481
|
+
const msgs = s2.activeChat?.messages?.length || 0;
|
|
52482
|
+
const exts = s2.extensions.length;
|
|
52483
|
+
return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
|
|
52001
52484
|
}).join(", ");
|
|
52002
|
-
const cliSummary = cliStates.map((
|
|
52003
|
-
const acpSummary = acpStates.map((
|
|
52485
|
+
const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52486
|
+
const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52004
52487
|
const logLevel = opts?.p2pOnly ? "debug" : "info";
|
|
52005
52488
|
const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
|
|
52006
52489
|
const summaryChanged = baseSummary !== this.lastStatusSummary;
|
|
@@ -52111,10 +52594,10 @@ var DaemonStatusReporter = class {
|
|
|
52111
52594
|
}
|
|
52112
52595
|
return false;
|
|
52113
52596
|
}
|
|
52114
|
-
simpleHash(
|
|
52597
|
+
simpleHash(s2) {
|
|
52115
52598
|
let h = 2166136261;
|
|
52116
|
-
for (let i = 0; i <
|
|
52117
|
-
h ^=
|
|
52599
|
+
for (let i = 0; i < s2.length; i++) {
|
|
52600
|
+
h ^= s2.charCodeAt(i);
|
|
52118
52601
|
h = h * 16777619 >>> 0;
|
|
52119
52602
|
}
|
|
52120
52603
|
return h.toString(36);
|
|
@@ -53340,7 +53823,7 @@ var ProviderInstanceManager = class {
|
|
|
53340
53823
|
* Per-category status collect
|
|
53341
53824
|
*/
|
|
53342
53825
|
collectStatesByCategory(category) {
|
|
53343
|
-
return this.collectAllStates().filter((
|
|
53826
|
+
return this.collectAllStates().filter((s2) => s2.category === category);
|
|
53344
53827
|
}
|
|
53345
53828
|
// ─── Tick engine ─────────────────────────────────
|
|
53346
53829
|
/**
|
|
@@ -55240,9 +55723,9 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
|
|
|
55240
55723
|
function findCliTarget(ctx, type, instanceId) {
|
|
55241
55724
|
if (!ctx.instanceManager) return null;
|
|
55242
55725
|
const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
|
|
55243
|
-
if (instanceId) return cliStates.find((
|
|
55726
|
+
if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
|
|
55244
55727
|
if (!type) return cliStates[cliStates.length - 1] || null;
|
|
55245
|
-
const matches = cliStates.filter((
|
|
55728
|
+
const matches = cliStates.filter((s2) => s2.type === type);
|
|
55246
55729
|
return matches[matches.length - 1] || null;
|
|
55247
55730
|
}
|
|
55248
55731
|
function getCliTargetBundle(ctx, type, instanceId) {
|
|
@@ -55605,20 +56088,20 @@ async function handleCliStatus(ctx, _req, res) {
|
|
|
55605
56088
|
return;
|
|
55606
56089
|
}
|
|
55607
56090
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55608
|
-
const cliStates = allStates.filter((
|
|
55609
|
-
const result = cliStates.map((
|
|
55610
|
-
instanceId:
|
|
55611
|
-
type:
|
|
55612
|
-
name:
|
|
55613
|
-
category:
|
|
55614
|
-
status:
|
|
55615
|
-
mode:
|
|
55616
|
-
workspace:
|
|
55617
|
-
messageCount:
|
|
55618
|
-
lastMessage:
|
|
55619
|
-
activeModal:
|
|
55620
|
-
pendingEvents:
|
|
55621
|
-
settings:
|
|
56091
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56092
|
+
const result = cliStates.map((s2) => ({
|
|
56093
|
+
instanceId: s2.instanceId,
|
|
56094
|
+
type: s2.type,
|
|
56095
|
+
name: s2.name,
|
|
56096
|
+
category: s2.category,
|
|
56097
|
+
status: s2.status,
|
|
56098
|
+
mode: s2.mode,
|
|
56099
|
+
workspace: s2.workspace,
|
|
56100
|
+
messageCount: s2.activeChat?.messages?.length || 0,
|
|
56101
|
+
lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
|
|
56102
|
+
activeModal: s2.activeChat?.activeModal || null,
|
|
56103
|
+
pendingEvents: s2.pendingEvents || [],
|
|
56104
|
+
settings: s2.settings
|
|
55622
56105
|
}));
|
|
55623
56106
|
ctx.json(res, 200, { instances: result, count: result.length });
|
|
55624
56107
|
}
|
|
@@ -55707,9 +56190,9 @@ function handleCliSSE(ctx, cliSSEClients, _req, res) {
|
|
|
55707
56190
|
}
|
|
55708
56191
|
if (ctx.instanceManager) {
|
|
55709
56192
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55710
|
-
const cliStates = allStates.filter((
|
|
55711
|
-
for (const
|
|
55712
|
-
ctx.sendCliSSE({ event: "snapshot", providerType:
|
|
56193
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56194
|
+
for (const s2 of cliStates) {
|
|
56195
|
+
ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
|
|
55713
56196
|
}
|
|
55714
56197
|
}
|
|
55715
56198
|
_req.on("close", () => {
|
|
@@ -55725,7 +56208,7 @@ async function handleCliDebug(ctx, type, _req, res) {
|
|
|
55725
56208
|
const target = findCliTarget(ctx, type);
|
|
55726
56209
|
if (!target) {
|
|
55727
56210
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55728
|
-
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((
|
|
56211
|
+
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
|
|
55729
56212
|
return;
|
|
55730
56213
|
}
|
|
55731
56214
|
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
@@ -55771,7 +56254,7 @@ async function handleCliTrace(ctx, type, req, res) {
|
|
|
55771
56254
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55772
56255
|
ctx.json(res, 404, {
|
|
55773
56256
|
error: `No running instance for: ${type}`,
|
|
55774
|
-
available: allStates.filter((
|
|
56257
|
+
available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
|
|
55775
56258
|
});
|
|
55776
56259
|
return;
|
|
55777
56260
|
}
|
|
@@ -56576,7 +57059,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56576
57059
|
child.write("\x1B[12;1R");
|
|
56577
57060
|
ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
|
|
56578
57061
|
}
|
|
56579
|
-
checkAutoApproval(data, (
|
|
57062
|
+
checkAutoApproval(data, (s2) => child.write(s2));
|
|
56580
57063
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
|
|
56581
57064
|
scheduleAutoStopForVerification();
|
|
56582
57065
|
});
|
|
@@ -56589,7 +57072,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56589
57072
|
stdout += chunk;
|
|
56590
57073
|
clearAutoStopTimer();
|
|
56591
57074
|
if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
|
|
56592
|
-
checkAutoApproval(chunk, (
|
|
57075
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
56593
57076
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
|
|
56594
57077
|
scheduleAutoStopForVerification();
|
|
56595
57078
|
});
|
|
@@ -56597,7 +57080,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56597
57080
|
const chunk = d.toString();
|
|
56598
57081
|
stderr += chunk;
|
|
56599
57082
|
clearAutoStopTimer();
|
|
56600
|
-
checkAutoApproval(chunk, (
|
|
57083
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
56601
57084
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
|
|
56602
57085
|
scheduleAutoStopForVerification();
|
|
56603
57086
|
});
|
|
@@ -57412,59 +57895,59 @@ var DevServer = class _DevServer {
|
|
|
57412
57895
|
// ─── Route Table ─────────────────────────────────────
|
|
57413
57896
|
routes = [
|
|
57414
57897
|
// Static routes
|
|
57415
|
-
{ method: "GET", pattern: "/api/providers", handler: (q,
|
|
57416
|
-
{ method: "GET", pattern: "/api/providers/source-config", handler: (q,
|
|
57417
|
-
{ method: "POST", pattern: "/api/providers/source-config", handler: (q,
|
|
57418
|
-
{ method: "GET", pattern: "/api/providers/versions", handler: (q,
|
|
57419
|
-
{ method: "POST", pattern: "/api/providers/reload", handler: (q,
|
|
57420
|
-
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q,
|
|
57421
|
-
{ method: "POST", pattern: "/api/cdp/click", handler: (q,
|
|
57422
|
-
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q,
|
|
57423
|
-
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q,
|
|
57424
|
-
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q,
|
|
57425
|
-
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q,
|
|
57426
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q,
|
|
57427
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q,
|
|
57428
|
-
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q,
|
|
57429
|
-
{ method: "GET", pattern: "/api/cdp/targets", handler: (q,
|
|
57430
|
-
{ method: "POST", pattern: "/api/scripts/run", handler: (q,
|
|
57431
|
-
{ method: "GET", pattern: "/api/status", handler: (q,
|
|
57432
|
-
{ method: "POST", pattern: "/api/watch/start", handler: (q,
|
|
57433
|
-
{ method: "POST", pattern: "/api/watch/stop", handler: (q,
|
|
57434
|
-
{ method: "GET", pattern: "/api/watch/events", handler: (q,
|
|
57435
|
-
{ method: "POST", pattern: "/api/scaffold", handler: (q,
|
|
57898
|
+
{ method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
|
|
57899
|
+
{ method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
|
|
57900
|
+
{ method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
|
|
57901
|
+
{ method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
|
|
57902
|
+
{ method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
|
|
57903
|
+
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
|
|
57904
|
+
{ method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
|
|
57905
|
+
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
|
|
57906
|
+
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
|
|
57907
|
+
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
|
|
57908
|
+
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
|
|
57909
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
|
|
57910
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
|
|
57911
|
+
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
|
|
57912
|
+
{ method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
|
|
57913
|
+
{ method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
|
|
57914
|
+
{ method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
|
|
57915
|
+
{ method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
|
|
57916
|
+
{ method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
|
|
57917
|
+
{ method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
|
|
57918
|
+
{ method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
|
|
57436
57919
|
// CLI Debug routes
|
|
57437
|
-
{ method: "GET", pattern: "/api/cli/status", handler: (q,
|
|
57438
|
-
{ method: "POST", pattern: "/api/cli/launch", handler: (q,
|
|
57439
|
-
{ method: "POST", pattern: "/api/cli/send", handler: (q,
|
|
57440
|
-
{ method: "POST", pattern: "/api/cli/exercise", handler: (q,
|
|
57441
|
-
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q,
|
|
57442
|
-
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q,
|
|
57443
|
-
{ method: "POST", pattern: "/api/cli/resolve", handler: (q,
|
|
57444
|
-
{ method: "POST", pattern: "/api/cli/raw", handler: (q,
|
|
57445
|
-
{ method: "POST", pattern: "/api/cli/stop", handler: (q,
|
|
57446
|
-
{ method: "GET", pattern: "/api/cli/events", handler: (q,
|
|
57447
|
-
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q,
|
|
57448
|
-
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q,
|
|
57449
|
-
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q,
|
|
57920
|
+
{ method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
|
|
57921
|
+
{ method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
|
|
57922
|
+
{ method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
|
|
57923
|
+
{ method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
|
|
57924
|
+
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
|
|
57925
|
+
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
|
|
57926
|
+
{ method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
|
|
57927
|
+
{ method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
|
|
57928
|
+
{ method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
|
|
57929
|
+
{ method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
|
|
57930
|
+
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
|
|
57931
|
+
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
|
|
57932
|
+
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
|
|
57450
57933
|
// Dynamic routes (provider :type param)
|
|
57451
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q,
|
|
57452
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q,
|
|
57453
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57454
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57455
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q,
|
|
57456
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q,
|
|
57457
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q,
|
|
57458
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q,
|
|
57459
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q,
|
|
57460
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q,
|
|
57461
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q,
|
|
57462
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q,
|
|
57463
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q,
|
|
57464
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q,
|
|
57465
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q,
|
|
57466
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q,
|
|
57467
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q,
|
|
57934
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
|
|
57935
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
|
|
57936
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
|
|
57937
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
|
|
57938
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
|
|
57939
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
|
|
57940
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
|
|
57941
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
|
|
57942
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
|
|
57943
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
|
|
57944
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
|
|
57945
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
|
|
57946
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
|
|
57947
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
|
|
57948
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
|
|
57949
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
|
|
57950
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
|
|
57468
57951
|
];
|
|
57469
57952
|
matchRoute(method, pathname) {
|
|
57470
57953
|
for (const route of this.routes) {
|
|
@@ -58059,14 +58542,14 @@ var DevServer = class _DevServer {
|
|
|
58059
58542
|
warnings.push(...validation.warnings);
|
|
58060
58543
|
if (config.settings) {
|
|
58061
58544
|
for (const [key, val] of Object.entries(config.settings)) {
|
|
58062
|
-
const
|
|
58063
|
-
if (!
|
|
58064
|
-
else if (!["boolean", "number", "string", "select"].includes(
|
|
58065
|
-
errors.push(`settings.${key}: invalid type '${
|
|
58066
|
-
if (
|
|
58067
|
-
if (
|
|
58068
|
-
errors.push(`settings.${key}: min (${
|
|
58069
|
-
if (
|
|
58545
|
+
const s2 = val;
|
|
58546
|
+
if (!s2.type) errors.push(`settings.${key}: missing type`);
|
|
58547
|
+
else if (!["boolean", "number", "string", "select"].includes(s2.type))
|
|
58548
|
+
errors.push(`settings.${key}: invalid type '${s2.type}'`);
|
|
58549
|
+
if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
|
|
58550
|
+
if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
|
|
58551
|
+
errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
|
|
58552
|
+
if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
|
|
58070
58553
|
errors.push(`settings.${key}: select type requires options[]`);
|
|
58071
58554
|
}
|
|
58072
58555
|
}
|