@adhdev/daemon-core 0.9.82-rc.354 → 0.9.82-rc.356
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +637 -209
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +637 -209
- 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/cli-provider-instance.d.ts +2 -0
- package/dist/providers/spec/adapter.d.ts +22 -0
- package/dist/providers/spec/cli-adapter.d.ts +6 -0
- package/dist/providers/spec/evaluator.d.ts +1 -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 +47 -5
- package/package.json +2 -2
- package/src/commands/router.ts +19 -6
- 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/cli-provider-instance.ts +86 -4
- package/src/providers/spec/adapter.ts +67 -0
- package/src/providers/spec/cli-adapter.ts +63 -7
- package/src/providers/spec/evaluator.ts +38 -13
- package/src/providers/spec/fsm-driver.ts +158 -14
- package/src/providers/spec/fsm-evaluator.ts +19 -2
- package/src/providers/spec/types.ts +41 -5
package/dist/index.js
CHANGED
|
@@ -316,10 +316,10 @@ function readInjected(value) {
|
|
|
316
316
|
}
|
|
317
317
|
function getDaemonBuildInfo() {
|
|
318
318
|
if (cached) return cached;
|
|
319
|
-
const commit = readInjected(true ? "
|
|
320
|
-
const commitShort = readInjected(true ? "
|
|
321
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
322
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
319
|
+
const commit = readInjected(true ? "91500e054cf2b6258f6041f90c18be03ad05a8ad" : void 0) ?? "unknown";
|
|
320
|
+
const commitShort = readInjected(true ? "91500e05" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
321
|
+
const version = readInjected(true ? "0.9.82-rc.356" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
322
|
+
const builtAt = readInjected(true ? "2026-06-22T22:47:29.082Z" : void 0);
|
|
323
323
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
324
324
|
return cached;
|
|
325
325
|
}
|
|
@@ -4827,9 +4827,12 @@ function getActiveDirectDispatches(meshId) {
|
|
|
4827
4827
|
return [];
|
|
4828
4828
|
}
|
|
4829
4829
|
}
|
|
4830
|
-
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
4830
|
+
function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
4831
4831
|
try {
|
|
4832
|
-
|
|
4832
|
+
if (!taskId) {
|
|
4833
|
+
LOG.warn("MeshQueue", `updateDirectDispatchStatus(${status}) for mesh ${meshId} session ${sessionId} has no taskId \u2014 falling back to session_id match (may flip a sibling dispatch row)`);
|
|
4834
|
+
}
|
|
4835
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
|
|
4833
4836
|
} catch {
|
|
4834
4837
|
}
|
|
4835
4838
|
}
|
|
@@ -5662,9 +5665,25 @@ var init_mesh_runtime_store = __esm({
|
|
|
5662
5665
|
updatedAt: r.updated_at
|
|
5663
5666
|
}));
|
|
5664
5667
|
}
|
|
5665
|
-
|
|
5666
|
-
|
|
5668
|
+
// CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
|
|
5669
|
+
// single session can host several sequential direct dispatches (re-dispatch / nudge), so
|
|
5670
|
+
// matching a status flip by session_id alone hits EVERY non-terminal row for that session
|
|
5671
|
+
// — flipping a sibling task's row and stranding the one whose event actually fired (the
|
|
5672
|
+
// assigned-stranded watchdog then requeues a task that is really still generating). When
|
|
5673
|
+
// the firing event carries a taskId, target the single PK row; the session_id match is the
|
|
5674
|
+
// legacy fallback only for events that arrive without a taskId.
|
|
5675
|
+
updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
5667
5676
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5677
|
+
if (taskId) {
|
|
5678
|
+
this.db.prepare(`
|
|
5679
|
+
UPDATE mesh_direct_dispatches
|
|
5680
|
+
SET status = @status, updated_at = @updatedAt
|
|
5681
|
+
WHERE mesh_id = @meshId AND task_id = @taskId
|
|
5682
|
+
AND status NOT IN ('completed', 'failed')
|
|
5683
|
+
`).run({ status, meshId, taskId, updatedAt: now });
|
|
5684
|
+
return;
|
|
5685
|
+
}
|
|
5686
|
+
if (!sessionId) return;
|
|
5668
5687
|
this.db.prepare(`
|
|
5669
5688
|
UPDATE mesh_direct_dispatches
|
|
5670
5689
|
SET status = @status, updated_at = @updatedAt
|
|
@@ -7390,7 +7409,7 @@ function resolveWin32Executable(command) {
|
|
|
7390
7409
|
windowsHide: true
|
|
7391
7410
|
}).trim();
|
|
7392
7411
|
if (out) {
|
|
7393
|
-
const matches = out.split(/\r?\n/).map((
|
|
7412
|
+
const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
|
|
7394
7413
|
const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
|
|
7395
7414
|
return direct || matches[0] || command;
|
|
7396
7415
|
}
|
|
@@ -8742,11 +8761,29 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
8742
8761
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
8743
8762
|
);
|
|
8744
8763
|
}
|
|
8764
|
+
function isWeakCompletionMetadata(metadata) {
|
|
8765
|
+
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
8766
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
8767
|
+
if (metadata.reviewRecommended === true) return true;
|
|
8768
|
+
const diag = readRecord4(metadata.completionDiagnostic);
|
|
8769
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
8770
|
+
}
|
|
8745
8771
|
function buildPendingEventFingerprint(event) {
|
|
8746
8772
|
const metadata = readRecord4(event.metadataEvent) || {};
|
|
8747
8773
|
if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
|
|
8748
8774
|
return [event.meshId, event.event, event.nodeId || ""].join("::");
|
|
8749
8775
|
}
|
|
8776
|
+
if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
|
|
8777
|
+
const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
8778
|
+
if (terminalTaskId) {
|
|
8779
|
+
return [
|
|
8780
|
+
event.meshId,
|
|
8781
|
+
event.event,
|
|
8782
|
+
terminalTaskId,
|
|
8783
|
+
isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
|
|
8784
|
+
].join("::");
|
|
8785
|
+
}
|
|
8786
|
+
}
|
|
8750
8787
|
const sessionId = resolveEventSessionId(metadata);
|
|
8751
8788
|
const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
|
|
8752
8789
|
const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
@@ -9105,7 +9142,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
9105
9142
|
}
|
|
9106
9143
|
}
|
|
9107
9144
|
}
|
|
9108
|
-
var import_fs10, import_path9, import_crypto7, REFINE_TERMINAL_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9145
|
+
var import_fs10, import_path9, import_crypto7, REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9109
9146
|
var init_mesh_events_pending = __esm({
|
|
9110
9147
|
"src/mesh/mesh-events-pending.ts"() {
|
|
9111
9148
|
"use strict";
|
|
@@ -9118,6 +9155,7 @@ var init_mesh_events_pending = __esm({
|
|
|
9118
9155
|
init_mesh_events_utils();
|
|
9119
9156
|
init_dist();
|
|
9120
9157
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
9158
|
+
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
9121
9159
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
9122
9160
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
9123
9161
|
}
|
|
@@ -9447,7 +9485,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
|
|
|
9447
9485
|
evidence
|
|
9448
9486
|
}
|
|
9449
9487
|
});
|
|
9450
|
-
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9488
|
+
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
|
|
9451
9489
|
markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9452
9490
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
9453
9491
|
queuePendingMeshCoordinatorEvent({
|
|
@@ -9737,8 +9775,8 @@ function parsePatternEntry(x) {
|
|
|
9737
9775
|
if (x instanceof RegExp) return x;
|
|
9738
9776
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
9739
9777
|
try {
|
|
9740
|
-
const
|
|
9741
|
-
return new RegExp(
|
|
9778
|
+
const s2 = x;
|
|
9779
|
+
return new RegExp(s2.source, s2.flags || "");
|
|
9742
9780
|
} catch {
|
|
9743
9781
|
return null;
|
|
9744
9782
|
}
|
|
@@ -10309,6 +10347,38 @@ var init_mesh_unresolved_forward_outbox = __esm({
|
|
|
10309
10347
|
}
|
|
10310
10348
|
});
|
|
10311
10349
|
|
|
10350
|
+
// src/mesh/mesh-event-trace.ts
|
|
10351
|
+
function s(v) {
|
|
10352
|
+
return typeof v === "string" && v.trim() ? v.trim() : "";
|
|
10353
|
+
}
|
|
10354
|
+
function meshEventTraceKey(ctx) {
|
|
10355
|
+
const segs = [`task=${s(ctx.taskId) || "-"}`];
|
|
10356
|
+
const eventId = s(ctx.eventId);
|
|
10357
|
+
if (eventId) segs.push(`evt=${eventId}`);
|
|
10358
|
+
segs.push(`sess=${s(ctx.sessionId) || "-"}`);
|
|
10359
|
+
const nodeId = s(ctx.nodeId);
|
|
10360
|
+
if (nodeId) segs.push(`node=${nodeId}`);
|
|
10361
|
+
const meshId = s(ctx.meshId);
|
|
10362
|
+
if (meshId) segs.push(`mesh=${meshId}`);
|
|
10363
|
+
const event = s(ctx.event);
|
|
10364
|
+
if (event) segs.push(`event=${event}`);
|
|
10365
|
+
return segs.join(" ");
|
|
10366
|
+
}
|
|
10367
|
+
function traceMeshEventStage(stage, ctx, detail) {
|
|
10368
|
+
LOG.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10369
|
+
}
|
|
10370
|
+
function traceMeshEventDrop(reason, ctx, detail) {
|
|
10371
|
+
LOG.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10372
|
+
}
|
|
10373
|
+
var CAT;
|
|
10374
|
+
var init_mesh_event_trace = __esm({
|
|
10375
|
+
"src/mesh/mesh-event-trace.ts"() {
|
|
10376
|
+
"use strict";
|
|
10377
|
+
init_logger();
|
|
10378
|
+
CAT = "EvtTrace";
|
|
10379
|
+
}
|
|
10380
|
+
});
|
|
10381
|
+
|
|
10312
10382
|
// src/config/state-store.ts
|
|
10313
10383
|
function isPlainObject2(value) {
|
|
10314
10384
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -12094,9 +12164,9 @@ function buildAcpSession(state, options) {
|
|
|
12094
12164
|
}
|
|
12095
12165
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
12096
12166
|
const sessions = [];
|
|
12097
|
-
const ideStates = allStates.filter((
|
|
12098
|
-
const cliStates = allStates.filter((
|
|
12099
|
-
const acpStates = allStates.filter((
|
|
12167
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
12168
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
12169
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
12100
12170
|
for (const state of ideStates) {
|
|
12101
12171
|
sessions.push(buildWorkspaceSession(state, cdpManagers, options));
|
|
12102
12172
|
for (const ext of state.extensions) {
|
|
@@ -12580,6 +12650,15 @@ function getCachedMeshByWorkspace(workspace) {
|
|
|
12580
12650
|
meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
|
|
12581
12651
|
return mesh;
|
|
12582
12652
|
}
|
|
12653
|
+
function recoverMeshIdByNodeId(nodeId) {
|
|
12654
|
+
if (!nodeId) return "";
|
|
12655
|
+
for (const mesh of listMeshes()) {
|
|
12656
|
+
if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
|
|
12657
|
+
return readNonEmptyString2(mesh.id);
|
|
12658
|
+
}
|
|
12659
|
+
}
|
|
12660
|
+
return "";
|
|
12661
|
+
}
|
|
12583
12662
|
function __resetIdleAutoFastForwardForTests() {
|
|
12584
12663
|
idleAutoFastForwardLastAttempt.clear();
|
|
12585
12664
|
}
|
|
@@ -13482,6 +13561,13 @@ function shouldForceInjectMeshEvent(eventName) {
|
|
|
13482
13561
|
function injectMeshSystemMessage(components, args) {
|
|
13483
13562
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
13484
13563
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13564
|
+
const traceCtx = {
|
|
13565
|
+
taskId: args.metadataEvent.taskId,
|
|
13566
|
+
sessionId: eventSessionId,
|
|
13567
|
+
nodeId: eventNodeId,
|
|
13568
|
+
meshId: args.meshId,
|
|
13569
|
+
event: args.event
|
|
13570
|
+
};
|
|
13485
13571
|
const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
|
|
13486
13572
|
const workerCoordinatorDaemonId = readNonEmptyString2(
|
|
13487
13573
|
sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
|
|
@@ -13535,6 +13621,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13535
13621
|
}
|
|
13536
13622
|
}
|
|
13537
13623
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
13624
|
+
traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
|
|
13538
13625
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
13539
13626
|
}
|
|
13540
13627
|
if (args.event === "monitor:no_progress") {
|
|
@@ -13555,6 +13642,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13555
13642
|
}
|
|
13556
13643
|
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
13557
13644
|
LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
13645
|
+
traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
|
|
13558
13646
|
return {
|
|
13559
13647
|
success: true,
|
|
13560
13648
|
forwarded: 0,
|
|
@@ -13566,6 +13654,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13566
13654
|
}
|
|
13567
13655
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
13568
13656
|
LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
13657
|
+
traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
|
|
13569
13658
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
13570
13659
|
}
|
|
13571
13660
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
@@ -13580,6 +13669,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13580
13669
|
});
|
|
13581
13670
|
if (duplicateApproval) {
|
|
13582
13671
|
LOG.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13672
|
+
traceMeshEventDrop("duplicate_approval", traceCtx);
|
|
13583
13673
|
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
13584
13674
|
}
|
|
13585
13675
|
}
|
|
@@ -13599,6 +13689,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13599
13689
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
13600
13690
|
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
13601
13691
|
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13692
|
+
traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
|
|
13602
13693
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
13603
13694
|
}
|
|
13604
13695
|
}
|
|
@@ -13617,6 +13708,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13617
13708
|
});
|
|
13618
13709
|
if (duplicateCompletion) {
|
|
13619
13710
|
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13711
|
+
traceMeshEventDrop("duplicate_completion", traceCtx);
|
|
13620
13712
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
13621
13713
|
}
|
|
13622
13714
|
}
|
|
@@ -13635,6 +13727,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13635
13727
|
});
|
|
13636
13728
|
if (duplicateStopped) {
|
|
13637
13729
|
LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13730
|
+
traceMeshEventDrop("duplicate_stopped", traceCtx);
|
|
13638
13731
|
return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
|
|
13639
13732
|
}
|
|
13640
13733
|
}
|
|
@@ -13646,7 +13739,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13646
13739
|
});
|
|
13647
13740
|
const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
|
|
13648
13741
|
if (!leaveDirectDispatchActive) {
|
|
13649
|
-
updateDirectDispatchStatus(args.meshId, sessionId, outcome);
|
|
13742
|
+
updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
|
|
13650
13743
|
}
|
|
13651
13744
|
markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
|
|
13652
13745
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
@@ -13659,7 +13752,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13659
13752
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13660
13753
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
13661
13754
|
if (sessionId) {
|
|
13662
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13755
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13663
13756
|
const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
|
|
13664
13757
|
completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
|
|
13665
13758
|
if (nodeId && providerType) {
|
|
@@ -13742,7 +13835,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13742
13835
|
}
|
|
13743
13836
|
}
|
|
13744
13837
|
if (sessionId) {
|
|
13745
|
-
|
|
13838
|
+
const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
|
|
13839
|
+
updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
|
|
13746
13840
|
const activeDeliveries = (() => {
|
|
13747
13841
|
try {
|
|
13748
13842
|
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
|
|
@@ -13750,7 +13844,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13750
13844
|
return [];
|
|
13751
13845
|
}
|
|
13752
13846
|
})();
|
|
13753
|
-
|
|
13847
|
+
const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
|
|
13848
|
+
for (const d of deliveriesToAck) {
|
|
13754
13849
|
updateSessionDeliveryStatus(d.id, "acked");
|
|
13755
13850
|
}
|
|
13756
13851
|
}
|
|
@@ -13764,7 +13859,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13764
13859
|
}
|
|
13765
13860
|
}
|
|
13766
13861
|
if (sessionId) {
|
|
13767
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13862
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13768
13863
|
completedTaskForLedger = markSessionTerminal(sessionId, "failed");
|
|
13769
13864
|
}
|
|
13770
13865
|
}
|
|
@@ -13910,6 +14005,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13910
14005
|
};
|
|
13911
14006
|
if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
|
|
13912
14007
|
LOG.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
|
|
14008
|
+
traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
|
|
14009
|
+
} else {
|
|
14010
|
+
traceMeshEventDrop("queue_dedup", traceCtx);
|
|
13913
14011
|
}
|
|
13914
14012
|
return { success: true, forwarded: 0 };
|
|
13915
14013
|
}
|
|
@@ -13920,8 +14018,23 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
13920
14018
|
}
|
|
13921
14019
|
const nodeId = readNonEmptyString2(payload.nodeId);
|
|
13922
14020
|
const workspace = readNonEmptyString2(payload.workspace);
|
|
13923
|
-
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
|
|
13924
|
-
if (!meshId)
|
|
14021
|
+
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
|
|
14022
|
+
if (!meshId) {
|
|
14023
|
+
traceMeshEventDrop("meshId_required", {
|
|
14024
|
+
taskId: payload.taskId,
|
|
14025
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14026
|
+
nodeId,
|
|
14027
|
+
event: eventName
|
|
14028
|
+
}, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
|
|
14029
|
+
return { success: false, error: "meshId required" };
|
|
14030
|
+
}
|
|
14031
|
+
traceMeshEventStage("received", {
|
|
14032
|
+
taskId: payload.taskId,
|
|
14033
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14034
|
+
nodeId,
|
|
14035
|
+
meshId,
|
|
14036
|
+
event: eventName
|
|
14037
|
+
});
|
|
13925
14038
|
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
13926
14039
|
const relayModalMessage = readNonEmptyString2(payload.modalMessage);
|
|
13927
14040
|
const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
|
|
@@ -14002,9 +14115,18 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
|
14002
14115
|
workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
|
|
14003
14116
|
};
|
|
14004
14117
|
const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
|
|
14118
|
+
const fwdTraceCtx = {
|
|
14119
|
+
taskId: payload.taskId,
|
|
14120
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14121
|
+
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
|
|
14122
|
+
event: eventName
|
|
14123
|
+
};
|
|
14124
|
+
traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
|
|
14125
|
+
traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
|
|
14005
14126
|
Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
|
|
14006
14127
|
if (result && result.success === false) {
|
|
14007
14128
|
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
|
|
14129
|
+
traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14008
14130
|
return;
|
|
14009
14131
|
}
|
|
14010
14132
|
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
@@ -14072,6 +14194,14 @@ function setupMeshEventForwarding(components) {
|
|
|
14072
14194
|
if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
|
|
14073
14195
|
return;
|
|
14074
14196
|
}
|
|
14197
|
+
if (isUnroutableDelegateRejection(routing)) {
|
|
14198
|
+
traceMeshEventDrop("unroutable", {
|
|
14199
|
+
taskId: event.meshActiveTaskId ?? event.taskId,
|
|
14200
|
+
sessionId: routing.sessionId,
|
|
14201
|
+
nodeId: routing.nodeId,
|
|
14202
|
+
event: event.event
|
|
14203
|
+
}, "no coordinator anchor / mesh_unresolved");
|
|
14204
|
+
}
|
|
14075
14205
|
recordUnroutableDelegateEvent(routing, event.event);
|
|
14076
14206
|
return;
|
|
14077
14207
|
}
|
|
@@ -14102,6 +14232,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
14102
14232
|
init_mesh_events_pending();
|
|
14103
14233
|
init_mesh_routing();
|
|
14104
14234
|
init_mesh_unresolved_forward_outbox();
|
|
14235
|
+
init_mesh_event_trace();
|
|
14105
14236
|
init_snapshot();
|
|
14106
14237
|
init_repo_mesh_types();
|
|
14107
14238
|
init_dist();
|
|
@@ -14213,6 +14344,13 @@ function findLiveCoordinators(components) {
|
|
|
14213
14344
|
function injectPendingIntoCoordinator(coordinator, pending) {
|
|
14214
14345
|
if (!coordinator || !pending.coordinatorMessage) return;
|
|
14215
14346
|
const force = shouldForceInjectMeshEvent(pending.event);
|
|
14347
|
+
traceMeshEventStage("surfaced", {
|
|
14348
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14349
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
|
|
14350
|
+
nodeId: pending.nodeId,
|
|
14351
|
+
meshId: pending.meshId,
|
|
14352
|
+
event: pending.event
|
|
14353
|
+
}, force ? "force-inject" : "inject");
|
|
14216
14354
|
coordinator.onEvent("send_message", {
|
|
14217
14355
|
input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
|
|
14218
14356
|
...force ? { force: true } : {}
|
|
@@ -14271,6 +14409,13 @@ function recoverStrandedAssignedDispatches(meshId, store) {
|
|
|
14271
14409
|
});
|
|
14272
14410
|
if (reclaimed) {
|
|
14273
14411
|
LOG.warn("MeshReconcile", `Reclaimed stranded assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, dispatched ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s ago, never confirmed delivered \u2192 ${reclaimed.status})`);
|
|
14412
|
+
traceMeshEventDrop("assigned_stranded_reclaim", {
|
|
14413
|
+
taskId: row.id,
|
|
14414
|
+
sessionId: row.assignedSessionId,
|
|
14415
|
+
nodeId: row.assignedNodeId,
|
|
14416
|
+
meshId,
|
|
14417
|
+
event: "agent:generating_completed"
|
|
14418
|
+
}, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
|
|
14274
14419
|
}
|
|
14275
14420
|
}
|
|
14276
14421
|
}
|
|
@@ -14430,6 +14575,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14430
14575
|
try {
|
|
14431
14576
|
queuePendingMeshCoordinatorEvent(pending);
|
|
14432
14577
|
LOG.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
|
|
14578
|
+
traceMeshEventDrop("strict_route_hold", {
|
|
14579
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14580
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14581
|
+
nodeId: pending.nodeId,
|
|
14582
|
+
meshId,
|
|
14583
|
+
event: pending.event
|
|
14584
|
+
}, `coordinatorSession=${wantSession} not live`);
|
|
14433
14585
|
} catch (e) {
|
|
14434
14586
|
LOG.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
|
|
14435
14587
|
}
|
|
@@ -14453,6 +14605,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14453
14605
|
}
|
|
14454
14606
|
});
|
|
14455
14607
|
LOG.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
|
|
14608
|
+
traceMeshEventDrop("strict_route_expired", {
|
|
14609
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14610
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14611
|
+
nodeId: pending.nodeId,
|
|
14612
|
+
meshId,
|
|
14613
|
+
event: pending.event
|
|
14614
|
+
}, `coordinatorSession=${wantSession} never returned`);
|
|
14456
14615
|
} catch (e) {
|
|
14457
14616
|
LOG.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
14458
14617
|
}
|
|
@@ -14464,15 +14623,24 @@ async function retryUnresolvedDelegateForwards(components) {
|
|
|
14464
14623
|
const entries = peekUnresolvedDelegateForwards();
|
|
14465
14624
|
if (entries.length === 0) return;
|
|
14466
14625
|
for (const entry of entries) {
|
|
14626
|
+
const entryTraceCtx = {
|
|
14627
|
+
taskId: entry.payload.taskId,
|
|
14628
|
+
sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
|
|
14629
|
+
nodeId: readNonEmptyString2(entry.payload.nodeId),
|
|
14630
|
+
event: readNonEmptyString2(entry.payload.event)
|
|
14631
|
+
};
|
|
14467
14632
|
let result;
|
|
14468
14633
|
try {
|
|
14634
|
+
traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
|
|
14469
14635
|
result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
|
|
14470
14636
|
} catch (e) {
|
|
14471
14637
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
|
|
14638
|
+
traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
|
|
14472
14639
|
continue;
|
|
14473
14640
|
}
|
|
14474
14641
|
if (result && result.success === false) {
|
|
14475
14642
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
|
|
14643
|
+
traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14476
14644
|
continue;
|
|
14477
14645
|
}
|
|
14478
14646
|
ackUnresolvedDelegateForward(entry.id);
|
|
@@ -14714,6 +14882,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14714
14882
|
init_mesh_events_coordinator();
|
|
14715
14883
|
init_mesh_unresolved_forward_outbox();
|
|
14716
14884
|
init_mesh_events_utils();
|
|
14885
|
+
init_mesh_event_trace();
|
|
14717
14886
|
init_dist();
|
|
14718
14887
|
init_mesh_work_queue();
|
|
14719
14888
|
init_mesh_ledger();
|
|
@@ -15549,8 +15718,8 @@ function saveProvidersActive(file) {
|
|
|
15549
15718
|
}
|
|
15550
15719
|
function isValidSource(x) {
|
|
15551
15720
|
if (!x || typeof x !== "object") return false;
|
|
15552
|
-
const
|
|
15553
|
-
return typeof
|
|
15721
|
+
const s2 = x;
|
|
15722
|
+
return typeof s2.name === "string" && s2.name.length > 0 && typeof s2.url === "string" && s2.url.length > 0 && typeof s2.ref === "string" && s2.ref.length > 0 && typeof s2.addedAt === "string";
|
|
15554
15723
|
}
|
|
15555
15724
|
function deriveSourceName(url) {
|
|
15556
15725
|
const m = url.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -15606,7 +15775,7 @@ function inventoryExternalSources() {
|
|
|
15606
15775
|
}
|
|
15607
15776
|
function sourcesProviding(category, type) {
|
|
15608
15777
|
const inventory = inventoryExternalSources();
|
|
15609
|
-
return inventory.filter((
|
|
15778
|
+
return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
|
|
15610
15779
|
}
|
|
15611
15780
|
function resolveActiveSource(category, type, activeFile) {
|
|
15612
15781
|
const candidates = sourcesProviding(category, type);
|
|
@@ -15813,10 +15982,10 @@ function compileSettledPromptMatchers(spec) {
|
|
|
15813
15982
|
const footers = (spec.withFooter ?? []).map((f) => {
|
|
15814
15983
|
if (f.kind === "regex") {
|
|
15815
15984
|
const re = compile2(f.pattern, f.flags ?? "i");
|
|
15816
|
-
return { test: (
|
|
15985
|
+
return { test: (s2) => re.test(s2) };
|
|
15817
15986
|
}
|
|
15818
15987
|
const needle = f.pattern.toLowerCase();
|
|
15819
|
-
return { test: (
|
|
15988
|
+
return { test: (s2) => s2.toLowerCase().includes(needle) };
|
|
15820
15989
|
});
|
|
15821
15990
|
return { prompt, footers };
|
|
15822
15991
|
}
|
|
@@ -16690,7 +16859,7 @@ var init_cli_state_engine = __esm({
|
|
|
16690
16859
|
}
|
|
16691
16860
|
resolveModal(buttonIndex) {
|
|
16692
16861
|
const snap = this.transport.getSnapshot();
|
|
16693
|
-
const parseApproval = typeof this.transport.runParseApproval === "function" ? (
|
|
16862
|
+
const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
|
|
16694
16863
|
let modal = this.activeModal ?? parseApproval(snap);
|
|
16695
16864
|
if (!modal && this.runner.hasParseSession()) {
|
|
16696
16865
|
try {
|
|
@@ -19379,22 +19548,23 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19379
19548
|
const matchesCandidate = (c, i) => c.re.test(lines[i]) && (c.prevRe === null || i > 0 && c.prevRe.test(lines[i - 1])) && (c.nextRe === null || i < total - 1 && c.nextRe.test(lines[i + 1]));
|
|
19380
19549
|
let idx = -1;
|
|
19381
19550
|
for (const c of candidates) {
|
|
19551
|
+
let candIdx = -1;
|
|
19382
19552
|
if (sec.anchor_last) {
|
|
19383
19553
|
for (let i = total - 1; i >= 0; i--) {
|
|
19384
19554
|
if (matchesCandidate(c, i)) {
|
|
19385
|
-
|
|
19555
|
+
candIdx = i;
|
|
19386
19556
|
break;
|
|
19387
19557
|
}
|
|
19388
19558
|
}
|
|
19389
19559
|
} else {
|
|
19390
19560
|
for (let i = 0; i < total; i++) {
|
|
19391
19561
|
if (matchesCandidate(c, i)) {
|
|
19392
|
-
|
|
19562
|
+
candIdx = i;
|
|
19393
19563
|
break;
|
|
19394
19564
|
}
|
|
19395
19565
|
}
|
|
19396
19566
|
}
|
|
19397
|
-
if (
|
|
19567
|
+
if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
|
|
19398
19568
|
}
|
|
19399
19569
|
if (idx !== -1) {
|
|
19400
19570
|
from = idx;
|
|
@@ -19446,7 +19616,7 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19446
19616
|
}
|
|
19447
19617
|
function sectionText(sections, sectionId, fullScreen) {
|
|
19448
19618
|
if (!sectionId) return fullScreen;
|
|
19449
|
-
const found = sections.find((
|
|
19619
|
+
const found = sections.find((s2) => s2.id === sectionId);
|
|
19450
19620
|
return found ? found.text : "";
|
|
19451
19621
|
}
|
|
19452
19622
|
function isRegexCondition(c) {
|
|
@@ -19574,6 +19744,7 @@ function extractButtonsFromRule(rule, hay) {
|
|
|
19574
19744
|
const idx = Number(m[1]);
|
|
19575
19745
|
let label = String(m[2] ?? "").trim();
|
|
19576
19746
|
if (!Number.isFinite(idx) || idx <= 0 || !label) continue;
|
|
19747
|
+
const current = hasCursorMarker(lines[i]);
|
|
19577
19748
|
let j = i + 1;
|
|
19578
19749
|
while (j < lines.length) {
|
|
19579
19750
|
const next = lines[j];
|
|
@@ -19585,7 +19756,7 @@ function extractButtonsFromRule(rule, hay) {
|
|
|
19585
19756
|
}
|
|
19586
19757
|
if (buttons.some((b) => b.index === idx)) continue;
|
|
19587
19758
|
const key = keyTemplate.replace(/\{index\}/g, String(idx));
|
|
19588
|
-
buttons.push({ index: idx, label, key });
|
|
19759
|
+
buttons.push({ index: idx, label, key, current });
|
|
19589
19760
|
i = j - 1;
|
|
19590
19761
|
}
|
|
19591
19762
|
} else {
|
|
@@ -19597,12 +19768,15 @@ function extractButtonsFromRule(rule, hay) {
|
|
|
19597
19768
|
if (!Number.isFinite(idx) || idx <= 0 || !label) continue;
|
|
19598
19769
|
if (buttons.some((b) => b.index === idx)) continue;
|
|
19599
19770
|
const key = keyTemplate.replace(/\{index\}/g, String(idx));
|
|
19600
|
-
buttons.push({ index: idx, label, key });
|
|
19771
|
+
buttons.push({ index: idx, label, key, current: hasCursorMarker(m[0]) });
|
|
19601
19772
|
}
|
|
19602
19773
|
}
|
|
19603
19774
|
buttons.sort((a, b) => a.index - b.index);
|
|
19604
19775
|
return buttons;
|
|
19605
19776
|
}
|
|
19777
|
+
function hasCursorMarker(text) {
|
|
19778
|
+
return /^\s*[❯›>]/.test(text);
|
|
19779
|
+
}
|
|
19606
19780
|
var init_evaluator = __esm({
|
|
19607
19781
|
"src/providers/spec/evaluator.ts"() {
|
|
19608
19782
|
"use strict";
|
|
@@ -19614,10 +19788,10 @@ function isV4Spec(raw) {
|
|
|
19614
19788
|
return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
|
|
19615
19789
|
}
|
|
19616
19790
|
function initialState(spec) {
|
|
19617
|
-
return spec.states.find((
|
|
19791
|
+
return spec.states.find((s2) => s2.initial) ?? spec.states[0];
|
|
19618
19792
|
}
|
|
19619
19793
|
function stateById(spec, id) {
|
|
19620
|
-
return spec.states.find((
|
|
19794
|
+
return spec.states.find((s2) => s2.id === id);
|
|
19621
19795
|
}
|
|
19622
19796
|
function outgoingTransitions(spec, stateId) {
|
|
19623
19797
|
const matches = spec.transitions.filter((t) => {
|
|
@@ -19706,7 +19880,17 @@ function evalCond(cond, sections, fullScreen, cursor, prevLines, clock, legacyTr
|
|
|
19706
19880
|
const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
|
|
19707
19881
|
const kind = isRegex(cond) ? "regex" : "changed";
|
|
19708
19882
|
const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
|
|
19709
|
-
|
|
19883
|
+
let matchedText;
|
|
19884
|
+
if (result && isRegex(cond)) {
|
|
19885
|
+
try {
|
|
19886
|
+
const hay = sectionText(sections, cond.section, fullScreen);
|
|
19887
|
+
const re = new RegExp(cond.matches, cond.flags ?? "i");
|
|
19888
|
+
const m = re.exec(hay);
|
|
19889
|
+
if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
|
|
19890
|
+
} catch {
|
|
19891
|
+
}
|
|
19892
|
+
}
|
|
19893
|
+
return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
|
|
19710
19894
|
}
|
|
19711
19895
|
return { kind: "all", result: false, detail: "unknown condition" };
|
|
19712
19896
|
}
|
|
@@ -19821,17 +20005,17 @@ function validateFsmSpec(raw) {
|
|
|
19821
20005
|
}
|
|
19822
20006
|
const ids = /* @__PURE__ */ new Set();
|
|
19823
20007
|
let initialCount = 0;
|
|
19824
|
-
for (const [i,
|
|
19825
|
-
if (!
|
|
20008
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20009
|
+
if (!s2.id) {
|
|
19826
20010
|
errs.push(`states[${i}].id is required`);
|
|
19827
20011
|
continue;
|
|
19828
20012
|
}
|
|
19829
|
-
if (ids.has(
|
|
19830
|
-
ids.add(
|
|
19831
|
-
if (!
|
|
19832
|
-
if (
|
|
19833
|
-
if (
|
|
19834
|
-
errs.push(`states[${i}].status "${
|
|
20013
|
+
if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
|
|
20014
|
+
ids.add(s2.id);
|
|
20015
|
+
if (!s2.label) errs.push(`states[${i}].label is required`);
|
|
20016
|
+
if (s2.initial) initialCount += 1;
|
|
20017
|
+
if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
|
|
20018
|
+
errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
|
|
19835
20019
|
}
|
|
19836
20020
|
}
|
|
19837
20021
|
if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
|
|
@@ -19847,10 +20031,10 @@ function validateFsmSpec(raw) {
|
|
|
19847
20031
|
else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
|
|
19848
20032
|
if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
|
|
19849
20033
|
}
|
|
19850
|
-
for (const [i,
|
|
19851
|
-
const sec =
|
|
20034
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20035
|
+
const sec = s2.extract?.title?.section;
|
|
19852
20036
|
if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
|
|
19853
|
-
const bsec =
|
|
20037
|
+
const bsec = s2.extract?.buttons?.section;
|
|
19854
20038
|
if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
|
|
19855
20039
|
}
|
|
19856
20040
|
return errs;
|
|
@@ -32586,10 +32770,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32586
32770
|
const path42 = require("path");
|
|
32587
32771
|
const { spawnSync: spawnSync2 } = require("child_process");
|
|
32588
32772
|
const file = ext.loadExternalSources();
|
|
32589
|
-
if (file.sources.some((
|
|
32773
|
+
if (file.sources.some((s2) => s2.name === requestedName)) {
|
|
32590
32774
|
return { success: false, error: `source name "${requestedName}" is already registered` };
|
|
32591
32775
|
}
|
|
32592
|
-
if (file.sources.some((
|
|
32776
|
+
if (file.sources.some((s2) => s2.url === url && s2.ref === ref)) {
|
|
32593
32777
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
32594
32778
|
}
|
|
32595
32779
|
const sourceDir = path42.join(ext.externalRoot(), requestedName);
|
|
@@ -32651,7 +32835,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32651
32835
|
const fs32 = require("fs");
|
|
32652
32836
|
const path42 = require("path");
|
|
32653
32837
|
const file = ext.loadExternalSources();
|
|
32654
|
-
const match = file.sources.find((
|
|
32838
|
+
const match = file.sources.find((s2) => s2.name === name);
|
|
32655
32839
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
32656
32840
|
const sourceDir = path42.join(ext.externalRoot(), name);
|
|
32657
32841
|
if (fs32.existsSync(sourceDir)) {
|
|
@@ -32663,7 +32847,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32663
32847
|
}
|
|
32664
32848
|
ext.saveExternalSources({
|
|
32665
32849
|
schema: 1,
|
|
32666
|
-
sources: file.sources.filter((
|
|
32850
|
+
sources: file.sources.filter((s2) => s2.name !== name)
|
|
32667
32851
|
});
|
|
32668
32852
|
const active = ext.loadProvidersActive();
|
|
32669
32853
|
const filteredActive = {};
|
|
@@ -32687,10 +32871,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32687
32871
|
const file = ext.loadExternalSources();
|
|
32688
32872
|
const inventory = ext.inventoryExternalSources();
|
|
32689
32873
|
const active = ext.loadProvidersActive();
|
|
32690
|
-
const sources = file.sources.map((
|
|
32691
|
-
const inv = inventory.find((e) => e.sourceName ===
|
|
32874
|
+
const sources = file.sources.map((s2) => {
|
|
32875
|
+
const inv = inventory.find((e) => e.sourceName === s2.name);
|
|
32692
32876
|
return {
|
|
32693
|
-
...
|
|
32877
|
+
...s2,
|
|
32694
32878
|
providers: inv?.providers ?? {}
|
|
32695
32879
|
};
|
|
32696
32880
|
});
|
|
@@ -32867,6 +33051,21 @@ var path21 = __toESM(require("path"));
|
|
|
32867
33051
|
// src/providers/spec/adapter.ts
|
|
32868
33052
|
init_terminal_screen();
|
|
32869
33053
|
var import_session_host_core6 = require("@adhdev/session-host-core");
|
|
33054
|
+
var MAX_PTY_EVENTS = 300;
|
|
33055
|
+
var EVENT_CONTENT_CAP = 240;
|
|
33056
|
+
function escapeControl(text) {
|
|
33057
|
+
return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
|
|
33058
|
+
const code = ch.charCodeAt(0);
|
|
33059
|
+
if (ch === "\r") return "\\r";
|
|
33060
|
+
if (ch === "\n") return "\\n";
|
|
33061
|
+
if (ch === " ") return "\\t";
|
|
33062
|
+
if (code === 27) return "\\x1b";
|
|
33063
|
+
return "\\x" + code.toString(16).padStart(2, "0");
|
|
33064
|
+
});
|
|
33065
|
+
}
|
|
33066
|
+
function capPreview(text) {
|
|
33067
|
+
return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
|
|
33068
|
+
}
|
|
32870
33069
|
var TerminalAdapter = class {
|
|
32871
33070
|
constructor(opts, handlers) {
|
|
32872
33071
|
this.opts = opts;
|
|
@@ -32893,6 +33092,9 @@ var TerminalAdapter = class {
|
|
|
32893
33092
|
screenTimer = null;
|
|
32894
33093
|
tickTimer = null;
|
|
32895
33094
|
lastScreen = "";
|
|
33095
|
+
/** Debug-only ring buffer of PTY input/output/resize/cursor events. */
|
|
33096
|
+
events = [];
|
|
33097
|
+
lastCursorKey = "";
|
|
32896
33098
|
start() {
|
|
32897
33099
|
const env = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
|
|
32898
33100
|
this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
|
|
@@ -32901,10 +33103,12 @@ var TerminalAdapter = class {
|
|
|
32901
33103
|
cols: this.cols,
|
|
32902
33104
|
rows: this.rows
|
|
32903
33105
|
});
|
|
33106
|
+
this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
|
|
32904
33107
|
this.handlers.init?.({ pid: this.pty.pid });
|
|
32905
33108
|
this.pty.onData((chunk) => this.onChunk(chunk));
|
|
32906
33109
|
this.pty.onExit((info) => {
|
|
32907
33110
|
this.stopTimers();
|
|
33111
|
+
this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
|
|
32908
33112
|
this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
|
|
32909
33113
|
this.pty = null;
|
|
32910
33114
|
});
|
|
@@ -32915,6 +33119,7 @@ var TerminalAdapter = class {
|
|
|
32915
33119
|
resize(cols, rows) {
|
|
32916
33120
|
this.cols = cols;
|
|
32917
33121
|
this.rows = rows;
|
|
33122
|
+
this.recordEvent("resize", `${cols}x${rows}`);
|
|
32918
33123
|
this.pty?.resize(cols, rows);
|
|
32919
33124
|
this.screen.resize(rows, cols);
|
|
32920
33125
|
}
|
|
@@ -32935,8 +33140,21 @@ var TerminalAdapter = class {
|
|
|
32935
33140
|
return { row: pos.row, col: pos.col };
|
|
32936
33141
|
}
|
|
32937
33142
|
send_keys(text) {
|
|
33143
|
+
this.recordEvent("input", capPreview(escapeControl(text)), text.length);
|
|
32938
33144
|
this.pty?.write(text);
|
|
32939
33145
|
}
|
|
33146
|
+
/** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
|
|
33147
|
+
* first. Pure observation — never consulted by the FSM. */
|
|
33148
|
+
getEventTimeline(limit = MAX_PTY_EVENTS) {
|
|
33149
|
+
const n = Math.max(0, Math.min(limit, this.events.length));
|
|
33150
|
+
return this.events.slice(this.events.length - n);
|
|
33151
|
+
}
|
|
33152
|
+
recordEvent(kind, content, bytes) {
|
|
33153
|
+
const ev = { ts: Date.now(), kind, content };
|
|
33154
|
+
if (typeof bytes === "number") ev.bytes = bytes;
|
|
33155
|
+
this.events.push(ev);
|
|
33156
|
+
if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
|
|
33157
|
+
}
|
|
32940
33158
|
kill() {
|
|
32941
33159
|
this.stopTimers();
|
|
32942
33160
|
try {
|
|
@@ -32947,6 +33165,7 @@ var TerminalAdapter = class {
|
|
|
32947
33165
|
this.screen.dispose();
|
|
32948
33166
|
}
|
|
32949
33167
|
onChunk(chunk) {
|
|
33168
|
+
this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
|
|
32950
33169
|
try {
|
|
32951
33170
|
this.handlers.on_pty_data?.(chunk);
|
|
32952
33171
|
} catch {
|
|
@@ -32956,6 +33175,12 @@ var TerminalAdapter = class {
|
|
|
32956
33175
|
this.screenTimer = setTimeout(() => {
|
|
32957
33176
|
this.screenTimer = null;
|
|
32958
33177
|
const snap = this.computeScreen();
|
|
33178
|
+
const cur = this.screen.getCursorPosition();
|
|
33179
|
+
const curKey = `${cur.row},${cur.col}`;
|
|
33180
|
+
if (curKey !== this.lastCursorKey) {
|
|
33181
|
+
this.lastCursorKey = curKey;
|
|
33182
|
+
this.recordEvent("cursor", `(${cur.row},${cur.col})`);
|
|
33183
|
+
}
|
|
32959
33184
|
if (snap === this.lastScreen) return;
|
|
32960
33185
|
this.lastScreen = snap;
|
|
32961
33186
|
try {
|
|
@@ -33040,20 +33265,40 @@ function applyPreLaunchTrust(trust, workingDir) {
|
|
|
33040
33265
|
|
|
33041
33266
|
// src/providers/spec/fsm-driver.ts
|
|
33042
33267
|
init_logger();
|
|
33043
|
-
function countNewlines(
|
|
33268
|
+
function countNewlines(s2) {
|
|
33044
33269
|
let n = 0;
|
|
33045
|
-
for (let i = 0; i <
|
|
33270
|
+
for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
|
|
33046
33271
|
return n;
|
|
33047
33272
|
}
|
|
33048
33273
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
33049
33274
|
var WIN32_SUBMIT_RESEND_GAP_MS = 350;
|
|
33050
33275
|
var WIN32_SUBMIT_MAX_RESENDS = 14;
|
|
33276
|
+
var WIN32_SUBMIT_SETTLE_MS = 500;
|
|
33277
|
+
var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
|
|
33278
|
+
var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
|
|
33279
|
+
var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
|
|
33280
|
+
var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
|
|
33051
33281
|
function resolveSubmitDelayMs(specBeforeSubmit, text) {
|
|
33052
33282
|
const lines = countNewlines(text);
|
|
33053
33283
|
const linesBonus = Math.min(800, lines * 80);
|
|
33054
33284
|
const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
|
|
33055
33285
|
return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
|
|
33056
33286
|
}
|
|
33287
|
+
function chunkPreservingSurrogates(text, size) {
|
|
33288
|
+
const chunks = [];
|
|
33289
|
+
let offset = 0;
|
|
33290
|
+
while (offset < text.length) {
|
|
33291
|
+
let end = Math.min(text.length, offset + size);
|
|
33292
|
+
if (end < text.length) {
|
|
33293
|
+
const code = text.charCodeAt(end - 1);
|
|
33294
|
+
if (code >= 55296 && code <= 56319) end -= 1;
|
|
33295
|
+
}
|
|
33296
|
+
if (end <= offset) end = Math.min(text.length, offset + size);
|
|
33297
|
+
chunks.push(text.slice(offset, end));
|
|
33298
|
+
offset = end;
|
|
33299
|
+
}
|
|
33300
|
+
return chunks;
|
|
33301
|
+
}
|
|
33057
33302
|
function guessExt(mime) {
|
|
33058
33303
|
if (/png/i.test(mime)) return ".png";
|
|
33059
33304
|
if (/jpe?g/i.test(mime)) return ".jpg";
|
|
@@ -33069,7 +33314,10 @@ var FsmDriver = class {
|
|
|
33069
33314
|
this.buildAdapterOpts(),
|
|
33070
33315
|
{
|
|
33071
33316
|
init: () => this.emitInitialState(),
|
|
33072
|
-
on_pty_data: (chunk) =>
|
|
33317
|
+
on_pty_data: (chunk) => {
|
|
33318
|
+
this.lastPtyDataAt = Date.now();
|
|
33319
|
+
this.emit({ kind: "pty_data", chunk });
|
|
33320
|
+
},
|
|
33073
33321
|
on_screen_changed: () => this.reevaluate(),
|
|
33074
33322
|
on_exit: ({ exitCode }) => this.handleExit(exitCode)
|
|
33075
33323
|
}
|
|
@@ -33103,6 +33351,16 @@ var FsmDriver = class {
|
|
|
33103
33351
|
* WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
|
|
33104
33352
|
* leaves idle (submitted) or the resend budget is spent. */
|
|
33105
33353
|
win32SubmitTimer = null;
|
|
33354
|
+
/** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
|
|
33355
|
+
* on_pty_data — including the echo of text written into the composer — so the
|
|
33356
|
+
* win32 submit settle-gate can tell when input has finished landing. */
|
|
33357
|
+
lastPtyDataAt = 0;
|
|
33358
|
+
/** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
|
|
33359
|
+
* the gap between writing a chunk and its echo so the settle-gate does not
|
|
33360
|
+
* declare "quiet" mid-write. */
|
|
33361
|
+
lastWin32WriteAt = 0;
|
|
33362
|
+
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
33363
|
+
win32WriteTimer = null;
|
|
33106
33364
|
currentEval = null;
|
|
33107
33365
|
stateHistory = [];
|
|
33108
33366
|
prevStateAt = 0;
|
|
@@ -33223,6 +33481,10 @@ var FsmDriver = class {
|
|
|
33223
33481
|
clearTimeout(this.win32SubmitTimer);
|
|
33224
33482
|
this.win32SubmitTimer = null;
|
|
33225
33483
|
}
|
|
33484
|
+
if (this.win32WriteTimer) {
|
|
33485
|
+
clearTimeout(this.win32WriteTimer);
|
|
33486
|
+
this.win32WriteTimer = null;
|
|
33487
|
+
}
|
|
33226
33488
|
this.specWatcher?.close();
|
|
33227
33489
|
this.adapter.kill();
|
|
33228
33490
|
}
|
|
@@ -33253,11 +33515,15 @@ var FsmDriver = class {
|
|
|
33253
33515
|
getFsmSnapshotHistory() {
|
|
33254
33516
|
return this.fsmSnapshotHistory;
|
|
33255
33517
|
}
|
|
33518
|
+
/** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
|
|
33519
|
+
getEventTimeline(limit) {
|
|
33520
|
+
return this.adapter.getEventTimeline(limit);
|
|
33521
|
+
}
|
|
33256
33522
|
getSections() {
|
|
33257
33523
|
try {
|
|
33258
33524
|
const screen = this.adapter.snapshot();
|
|
33259
33525
|
const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
33260
|
-
return resolveSections(this.spec.sections ?? {}, lines).map((
|
|
33526
|
+
return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
|
|
33261
33527
|
} catch {
|
|
33262
33528
|
return null;
|
|
33263
33529
|
}
|
|
@@ -33635,7 +33901,7 @@ var FsmDriver = class {
|
|
|
33635
33901
|
const perChar = sm.delay_ms_per_char ?? 0;
|
|
33636
33902
|
const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
|
|
33637
33903
|
if (process.platform === "win32") {
|
|
33638
|
-
this.
|
|
33904
|
+
this.writeWin32Body(text);
|
|
33639
33905
|
this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
|
|
33640
33906
|
return;
|
|
33641
33907
|
}
|
|
@@ -33661,20 +33927,72 @@ var FsmDriver = class {
|
|
|
33661
33927
|
const st = stateById(this.spec, this.currentStateId);
|
|
33662
33928
|
return st ? statusForState(st) : "idle";
|
|
33663
33929
|
}
|
|
33930
|
+
/** Record a win32 body write so the settle-gate counts it as input activity
|
|
33931
|
+
* even before the echo arrives. */
|
|
33932
|
+
markWin32Write() {
|
|
33933
|
+
this.lastWin32WriteAt = Date.now();
|
|
33934
|
+
}
|
|
33935
|
+
/** Most recent win32 input activity — a write we issued OR a PTY output chunk
|
|
33936
|
+
* (echo). The submit settle-gate waits for this to go quiet. */
|
|
33937
|
+
lastWin32InputActivityAt() {
|
|
33938
|
+
return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
|
|
33939
|
+
}
|
|
33664
33940
|
/**
|
|
33665
|
-
*
|
|
33666
|
-
*
|
|
33667
|
-
* a
|
|
33668
|
-
*
|
|
33669
|
-
*
|
|
33670
|
-
*
|
|
33671
|
-
|
|
33941
|
+
* Write the message body to the PTY for win32, paced into bounded chunks. A
|
|
33942
|
+
* single unbounded ConPTY write can overflow the input pipe and drop leading
|
|
33943
|
+
* bytes; splitting it with a short inter-chunk gap keeps the console input
|
|
33944
|
+
* buffer from overflowing. Small bodies still go out in a single write. Each
|
|
33945
|
+
* chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
|
|
33946
|
+
* the final chunk is out and echoed.
|
|
33947
|
+
*/
|
|
33948
|
+
writeWin32Body(text) {
|
|
33949
|
+
if (this.win32WriteTimer) {
|
|
33950
|
+
clearTimeout(this.win32WriteTimer);
|
|
33951
|
+
this.win32WriteTimer = null;
|
|
33952
|
+
}
|
|
33953
|
+
if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
|
|
33954
|
+
this.markWin32Write();
|
|
33955
|
+
this.adapter.send_keys(text);
|
|
33956
|
+
return;
|
|
33957
|
+
}
|
|
33958
|
+
const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
|
|
33959
|
+
let idx = 0;
|
|
33960
|
+
const writeNext = () => {
|
|
33961
|
+
this.win32WriteTimer = null;
|
|
33962
|
+
if (idx >= chunks.length) return;
|
|
33963
|
+
this.markWin32Write();
|
|
33964
|
+
this.adapter.send_keys(chunks[idx]);
|
|
33965
|
+
idx += 1;
|
|
33966
|
+
if (idx < chunks.length) {
|
|
33967
|
+
this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
|
|
33968
|
+
}
|
|
33969
|
+
};
|
|
33970
|
+
writeNext();
|
|
33971
|
+
}
|
|
33972
|
+
/**
|
|
33973
|
+
* win32 submit. Two phases:
|
|
33974
|
+
*
|
|
33975
|
+
* Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
|
|
33976
|
+
* for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
|
|
33977
|
+
* (possibly multi-KB / multiline) body has finished arriving in the composer
|
|
33978
|
+
* and echoing. Honors an initial minimum delay and is bounded by
|
|
33979
|
+
* WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
|
|
33980
|
+
* This is what stops a long message from being submitted half-arrived (its
|
|
33981
|
+
* leading lines lost). A short message settles almost immediately.
|
|
33982
|
+
*
|
|
33983
|
+
* Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
|
|
33984
|
+
* if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
|
|
33985
|
+
* newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
|
|
33986
|
+
* (a stale/edge status never suppresses it); resends are gated on still being
|
|
33987
|
+
* idle and stop the instant the agent leaves idle (submitted → generating /
|
|
33988
|
+
* approval). This preserves the win32 lone-CR-swallow handling.
|
|
33672
33989
|
*/
|
|
33673
33990
|
scheduleWin32Submit(submitKey, initialDelayMs) {
|
|
33674
33991
|
if (this.win32SubmitTimer) {
|
|
33675
33992
|
clearTimeout(this.win32SubmitTimer);
|
|
33676
33993
|
this.win32SubmitTimer = null;
|
|
33677
33994
|
}
|
|
33995
|
+
const startedAt = Date.now();
|
|
33678
33996
|
const fire = (attempt) => {
|
|
33679
33997
|
this.win32SubmitTimer = null;
|
|
33680
33998
|
this.adapter.send_keys(submitKey);
|
|
@@ -33687,8 +34005,20 @@ var FsmDriver = class {
|
|
|
33687
34005
|
fire(attempt + 1);
|
|
33688
34006
|
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
33689
34007
|
};
|
|
33690
|
-
|
|
33691
|
-
|
|
34008
|
+
const waitForSettle = () => {
|
|
34009
|
+
this.win32SubmitTimer = null;
|
|
34010
|
+
const now = Date.now();
|
|
34011
|
+
const quietFor = now - this.lastWin32InputActivityAt();
|
|
34012
|
+
const waited = now - startedAt;
|
|
34013
|
+
if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
|
|
34014
|
+
fire(0);
|
|
34015
|
+
return;
|
|
34016
|
+
}
|
|
34017
|
+
const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
|
|
34018
|
+
this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
|
|
34019
|
+
};
|
|
34020
|
+
if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
|
|
34021
|
+
else waitForSettle();
|
|
33692
34022
|
}
|
|
33693
34023
|
handleClickControl(controlId, payload) {
|
|
33694
34024
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
|
|
@@ -33723,6 +34053,19 @@ var FsmDriver = class {
|
|
|
33723
34053
|
if (!m) return;
|
|
33724
34054
|
const btn = m.buttons.find((b) => b.index === index);
|
|
33725
34055
|
if (!btn) return;
|
|
34056
|
+
const rule = stateById(this.spec, this.currentStateId)?.extract?.buttons;
|
|
34057
|
+
if (rule?.select_mode === "arrow_keys") {
|
|
34058
|
+
const from = m.buttons.find((b) => b.current)?.index ?? 1;
|
|
34059
|
+
const up = rule.cursor_keys?.up ?? "\x1B[A";
|
|
34060
|
+
const down = rule.cursor_keys?.down ?? "\x1B[B";
|
|
34061
|
+
const delta = btn.index - from;
|
|
34062
|
+
const step = delta >= 0 ? down : up;
|
|
34063
|
+
const nav = step.repeat(Math.abs(delta));
|
|
34064
|
+
const confirm = (rule.key_for_index || "\r").replace(/\{index\}/g, "") || "\r";
|
|
34065
|
+
if (nav) this.adapter.send_keys(nav);
|
|
34066
|
+
this.adapter.send_keys(confirm);
|
|
34067
|
+
return;
|
|
34068
|
+
}
|
|
33726
34069
|
this.adapter.send_keys(btn.key);
|
|
33727
34070
|
}
|
|
33728
34071
|
handleAttachImage(blob, mime) {
|
|
@@ -33801,7 +34144,8 @@ function summarizeTransition(t) {
|
|
|
33801
34144
|
return out;
|
|
33802
34145
|
}
|
|
33803
34146
|
function flattenCond(c, out, depth) {
|
|
33804
|
-
|
|
34147
|
+
const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
|
|
34148
|
+
out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
|
|
33805
34149
|
for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
|
|
33806
34150
|
}
|
|
33807
34151
|
function findStable(c) {
|
|
@@ -34519,8 +34863,8 @@ function projectToolBlock(block2, role, tmap) {
|
|
|
34519
34863
|
}
|
|
34520
34864
|
return null;
|
|
34521
34865
|
}
|
|
34522
|
-
function oneLine(
|
|
34523
|
-
const flat =
|
|
34866
|
+
function oneLine(s2, max) {
|
|
34867
|
+
const flat = s2.replace(/\s+/g, " ").trim();
|
|
34524
34868
|
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
34525
34869
|
}
|
|
34526
34870
|
function parseTimestamp(v) {
|
|
@@ -34540,10 +34884,10 @@ function parseTimestamp(v) {
|
|
|
34540
34884
|
return null;
|
|
34541
34885
|
}
|
|
34542
34886
|
function normalizeRole(r) {
|
|
34543
|
-
const
|
|
34544
|
-
if (
|
|
34545
|
-
if (
|
|
34546
|
-
if (
|
|
34887
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
34888
|
+
if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
|
|
34889
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
34890
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
34547
34891
|
return "system";
|
|
34548
34892
|
}
|
|
34549
34893
|
function stringifyContent(v) {
|
|
@@ -34591,18 +34935,18 @@ function compileWhere(src) {
|
|
|
34591
34935
|
return (record) => ors.some((ands) => ands.every((t) => evalTerm(t, record)));
|
|
34592
34936
|
}
|
|
34593
34937
|
function parseTerm(src) {
|
|
34594
|
-
let
|
|
34938
|
+
let s2 = src.trim();
|
|
34595
34939
|
let negate = false;
|
|
34596
|
-
if (
|
|
34940
|
+
if (s2.startsWith("!")) {
|
|
34597
34941
|
negate = true;
|
|
34598
|
-
|
|
34942
|
+
s2 = s2.slice(1).trim();
|
|
34599
34943
|
}
|
|
34600
|
-
const fnMatch =
|
|
34944
|
+
const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
|
|
34601
34945
|
if (fnMatch) {
|
|
34602
34946
|
const [, op2, pathExpr, litExpr] = fnMatch;
|
|
34603
34947
|
return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
|
|
34604
34948
|
}
|
|
34605
|
-
const opMatch =
|
|
34949
|
+
const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
|
|
34606
34950
|
if (!opMatch) return null;
|
|
34607
34951
|
const [, lhs, op, rhsRaw] = opMatch;
|
|
34608
34952
|
return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
|
|
@@ -34959,9 +35303,12 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34959
35303
|
* — not this code — decides how a selection is keyed for each CLI.
|
|
34960
35304
|
*/
|
|
34961
35305
|
async selectPickerChoice(ctl, action, choiceIndex, choiceLabel) {
|
|
34962
|
-
|
|
34963
|
-
|
|
34964
|
-
|
|
35306
|
+
let options = this.extractPickerChoicesIfRendered(action);
|
|
35307
|
+
if (!options) {
|
|
35308
|
+
this.driver.dispatch({ kind: "click_control", control_id: ctl.id });
|
|
35309
|
+
await this.waitForPickerRendered(action);
|
|
35310
|
+
options = this.extractPickerChoices(action);
|
|
35311
|
+
}
|
|
34965
35312
|
let index = choiceIndex;
|
|
34966
35313
|
if ((index == null || !Number.isFinite(index)) && choiceLabel) {
|
|
34967
35314
|
const needle = choiceLabel.trim().toLowerCase();
|
|
@@ -34974,8 +35321,27 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34974
35321
|
if (index == null || !Number.isFinite(index)) {
|
|
34975
35322
|
return { ok: false, error: "choiceIndex or choiceLabel required to select" };
|
|
34976
35323
|
}
|
|
34977
|
-
|
|
34978
|
-
|
|
35324
|
+
if (action.select_mode === "arrow_keys") {
|
|
35325
|
+
const current = options.find((o) => o.current);
|
|
35326
|
+
if (current == null) {
|
|
35327
|
+
return {
|
|
35328
|
+
ok: false,
|
|
35329
|
+
error: "arrow-nav picker: current cursor row not detected on screen",
|
|
35330
|
+
controlResult: { options: options.map((o) => ({ value: o.label, label: o.label, current: o.current })) }
|
|
35331
|
+
};
|
|
35332
|
+
}
|
|
35333
|
+
const up = action.cursor_keys?.up ?? "\x1B[A";
|
|
35334
|
+
const down = action.cursor_keys?.down ?? "\x1B[B";
|
|
35335
|
+
const delta = index - current.index;
|
|
35336
|
+
const step = delta >= 0 ? down : up;
|
|
35337
|
+
const nav = step.repeat(Math.abs(delta));
|
|
35338
|
+
const confirm = (action.submit_key || "\r").replace(/\{index\}/g, "") || "\r";
|
|
35339
|
+
if (nav) this.driver.dispatch({ kind: "pty_write", data: nav });
|
|
35340
|
+
this.driver.dispatch({ kind: "pty_write", data: confirm });
|
|
35341
|
+
} else {
|
|
35342
|
+
const keys = (action.submit_key || "{index}\r").replace(/\{index\}/g, String(index));
|
|
35343
|
+
this.driver.dispatch({ kind: "pty_write", data: keys });
|
|
35344
|
+
}
|
|
34979
35345
|
const selected = options.find((o) => o.index === index);
|
|
34980
35346
|
return {
|
|
34981
35347
|
ok: true,
|
|
@@ -34987,6 +35353,20 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34987
35353
|
}
|
|
34988
35354
|
};
|
|
34989
35355
|
}
|
|
35356
|
+
/** Parse the picker choices only if the picker already appears rendered on
|
|
35357
|
+
* the live screen (its `wait_for` condition currently matches and at least
|
|
35358
|
+
* one choice parses). Returns the parsed choices when open, else null so
|
|
35359
|
+
* the caller knows it must send the trigger to open it. Used to de-dup the
|
|
35360
|
+
* picker open in {@link selectPickerChoice}. */
|
|
35361
|
+
extractPickerChoicesIfRendered(action) {
|
|
35362
|
+
const wf = action.wait_for;
|
|
35363
|
+
if (wf?.regex) {
|
|
35364
|
+
const re = new RegExp(wf.regex, wf.flags ?? "i");
|
|
35365
|
+
if (!re.test(this.readScreenSectionText(wf.section))) return null;
|
|
35366
|
+
}
|
|
35367
|
+
const options = this.extractPickerChoices(action);
|
|
35368
|
+
return options.length > 0 ? options : null;
|
|
35369
|
+
}
|
|
34990
35370
|
/** Poll the live screen until the picker's `wait_for` condition matches,
|
|
34991
35371
|
* up to a short budget. Returns true if it rendered, false on timeout. */
|
|
34992
35372
|
async waitForPickerRendered(action) {
|
|
@@ -35034,7 +35414,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35034
35414
|
try {
|
|
35035
35415
|
const sections = this.driver.getSections();
|
|
35036
35416
|
if (sectionId && sections) {
|
|
35037
|
-
const hit = sections.find((
|
|
35417
|
+
const hit = sections.find((s2) => s2.id === sectionId);
|
|
35038
35418
|
if (hit) return hit.text;
|
|
35039
35419
|
}
|
|
35040
35420
|
return this.driver.getScreen();
|
|
@@ -35049,7 +35429,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35049
35429
|
screen = this.driver.snapshot();
|
|
35050
35430
|
const driverSections = this.driver.getSections?.();
|
|
35051
35431
|
if (driverSections) {
|
|
35052
|
-
sections = Object.fromEntries(driverSections.map((
|
|
35432
|
+
sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
|
|
35053
35433
|
} else {
|
|
35054
35434
|
sections = this.readCurrentScreenSections(screen);
|
|
35055
35435
|
}
|
|
@@ -35095,6 +35475,10 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35095
35475
|
// answers "why did this rule fire" after the fact, unlike the live
|
|
35096
35476
|
// `fsm` field which only reflects the current instant.
|
|
35097
35477
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35478
|
+
// PTY input/output/resize/cursor event timeline (debug-only) so the
|
|
35479
|
+
// snapshot shows what we typed / what the PTY printed around each
|
|
35480
|
+
// status transition. Null for drivers without the timeline.
|
|
35481
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
35098
35482
|
// Extended fields
|
|
35099
35483
|
name: this.cliName,
|
|
35100
35484
|
status: this.getStatus().status,
|
|
@@ -35459,6 +35843,8 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35459
35843
|
// v4 FSM transition snapshot history — the captured pre-transition
|
|
35460
35844
|
// evaluation table at each transition (null for v3 specs).
|
|
35461
35845
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35846
|
+
// PTY input/output/resize/cursor event timeline (debug-only).
|
|
35847
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
35462
35848
|
messages,
|
|
35463
35849
|
committedMessages: messages
|
|
35464
35850
|
};
|
|
@@ -35503,6 +35889,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
|
|
|
35503
35889
|
|
|
35504
35890
|
// src/providers/cli-provider-instance.ts
|
|
35505
35891
|
init_logger();
|
|
35892
|
+
init_mesh_event_trace();
|
|
35506
35893
|
init_control_effects();
|
|
35507
35894
|
init_approval_utils();
|
|
35508
35895
|
init_provider_patch_state();
|
|
@@ -36554,6 +36941,23 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36554
36941
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
36555
36942
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|
|
36556
36943
|
}
|
|
36944
|
+
// EVTTRACE (observation-only): is this a mesh worker session whose completion
|
|
36945
|
+
// events must route to a coordinator? Used purely to gate trace logging so a
|
|
36946
|
+
// non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
|
|
36947
|
+
isMeshWorkerSession() {
|
|
36948
|
+
return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
|
|
36949
|
+
}
|
|
36950
|
+
// EVTTRACE correlation context for this session's completion lifecycle. taskId is
|
|
36951
|
+
// the primary grep anchor; instanceId is the session fallback.
|
|
36952
|
+
meshTraceCtx(event = "agent:generating_completed") {
|
|
36953
|
+
return {
|
|
36954
|
+
taskId: this.settings.meshActiveTaskId,
|
|
36955
|
+
sessionId: this.instanceId,
|
|
36956
|
+
nodeId: this.settings.meshNodeId,
|
|
36957
|
+
meshId: this.settings.meshNodeFor,
|
|
36958
|
+
event
|
|
36959
|
+
};
|
|
36960
|
+
}
|
|
36557
36961
|
flushCompletedDebounceIfFinalized() {
|
|
36558
36962
|
const pending = this.completedDebouncePending;
|
|
36559
36963
|
if (!pending) {
|
|
@@ -36574,24 +36978,33 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36574
36978
|
if (block2) {
|
|
36575
36979
|
const blockReason = block2.reason;
|
|
36576
36980
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
36577
|
-
|
|
36578
|
-
|
|
36981
|
+
const isTranscriptEvidenceGate = block2.allowTimeout === true;
|
|
36982
|
+
LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
36983
|
+
if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
|
|
36579
36984
|
if (pending.loggedBlockReason !== blockReason) {
|
|
36580
36985
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
36986
|
+
if (this.isMeshWorkerSession()) {
|
|
36987
|
+
traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
|
|
36988
|
+
}
|
|
36581
36989
|
pending.loggedBlockReason = blockReason;
|
|
36582
36990
|
}
|
|
36583
36991
|
this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
|
|
36584
36992
|
return;
|
|
36585
36993
|
}
|
|
36994
|
+
const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
|
|
36586
36995
|
const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
|
|
36587
36996
|
blockReason,
|
|
36588
36997
|
latestStatus,
|
|
36589
36998
|
latestVisibleStatus,
|
|
36590
36999
|
waitedMs,
|
|
36591
37000
|
pending,
|
|
36592
|
-
emittedAfterFinalizationTimeout
|
|
37001
|
+
emittedAfterFinalizationTimeout
|
|
36593
37002
|
});
|
|
36594
|
-
|
|
37003
|
+
completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
|
|
37004
|
+
LOG.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
|
|
37005
|
+
if (this.isMeshWorkerSession()) {
|
|
37006
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
|
|
37007
|
+
}
|
|
36595
37008
|
this.pushEvent({
|
|
36596
37009
|
event: "agent:generating_completed",
|
|
36597
37010
|
chatTitle: pending.chatTitle,
|
|
@@ -36614,6 +37027,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36614
37027
|
return;
|
|
36615
37028
|
}
|
|
36616
37029
|
LOG.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
|
|
37030
|
+
if (this.isMeshWorkerSession()) {
|
|
37031
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
|
|
37032
|
+
}
|
|
36617
37033
|
this.pushEvent({
|
|
36618
37034
|
event: "agent:generating_completed",
|
|
36619
37035
|
chatTitle: pending.chatTitle,
|
|
@@ -36852,6 +37268,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36852
37268
|
if (missingEvidence && !hasMeshContext) {
|
|
36853
37269
|
LOG.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
|
|
36854
37270
|
} else {
|
|
37271
|
+
if (this.isMeshWorkerSession()) {
|
|
37272
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
|
|
37273
|
+
}
|
|
36855
37274
|
this.pushEvent({
|
|
36856
37275
|
event: "agent:generating_completed",
|
|
36857
37276
|
chatTitle,
|
|
@@ -36928,6 +37347,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36928
37347
|
const monitorParsedStatus = parsedStatus;
|
|
36929
37348
|
for (const me of monitorEvents) {
|
|
36930
37349
|
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
37350
|
+
if (this.isMeshWorkerSession()) {
|
|
37351
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
|
|
37352
|
+
}
|
|
36931
37353
|
this.pushEvent({
|
|
36932
37354
|
event: "agent:generating_completed",
|
|
36933
37355
|
chatTitle,
|
|
@@ -36968,6 +37390,12 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36968
37390
|
workspace: typeof event.workspace === "string" && event.workspace.trim() ? event.workspace : this.workingDir,
|
|
36969
37391
|
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
36970
37392
|
};
|
|
37393
|
+
if (this.isMeshWorkerSession() && this.settings.meshActiveTaskId) {
|
|
37394
|
+
const existingTaskId = typeof enrichedEvent.taskId === "string" && enrichedEvent.taskId.trim() ? enrichedEvent.taskId : void 0;
|
|
37395
|
+
if (!existingTaskId) {
|
|
37396
|
+
enrichedEvent.taskId = this.settings.meshActiveTaskId;
|
|
37397
|
+
}
|
|
37398
|
+
}
|
|
36971
37399
|
if (this.context?.emitProviderEvent) {
|
|
36972
37400
|
this.context.emitProviderEvent(enrichedEvent);
|
|
36973
37401
|
} else {
|
|
@@ -40791,7 +41219,7 @@ function parsePbFile(filePath, sessionId) {
|
|
|
40791
41219
|
}
|
|
40792
41220
|
if (buf.length === 0) return null;
|
|
40793
41221
|
const strings = extractStringsFromBuffer(buf);
|
|
40794
|
-
const meaningful = strings.filter((
|
|
41222
|
+
const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
|
|
40795
41223
|
if (meaningful.length === 0) return null;
|
|
40796
41224
|
const content = meaningful.join("\n");
|
|
40797
41225
|
const sourceMtimeMs = statMtimeMs3(filePath);
|
|
@@ -40999,10 +41427,10 @@ function readSession4(sessionPath) {
|
|
|
40999
41427
|
};
|
|
41000
41428
|
}
|
|
41001
41429
|
function normalizeHermesRole(r) {
|
|
41002
|
-
const
|
|
41003
|
-
if (
|
|
41004
|
-
if (
|
|
41005
|
-
if (
|
|
41430
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41431
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41432
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41433
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
41006
41434
|
return "system";
|
|
41007
41435
|
}
|
|
41008
41436
|
|
|
@@ -41228,10 +41656,10 @@ function safeMtime(p) {
|
|
|
41228
41656
|
}
|
|
41229
41657
|
}
|
|
41230
41658
|
function normalizeRole2(r) {
|
|
41231
|
-
const
|
|
41232
|
-
if (
|
|
41233
|
-
if (
|
|
41234
|
-
if (
|
|
41659
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41660
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41661
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41662
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
41235
41663
|
return "system";
|
|
41236
41664
|
}
|
|
41237
41665
|
|
|
@@ -41251,7 +41679,7 @@ function synthesizeControlsFromControlBar(specControls) {
|
|
|
41251
41679
|
const actionType = ctl?.action?.type;
|
|
41252
41680
|
if (!id || !actionType) return;
|
|
41253
41681
|
const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
|
|
41254
|
-
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((
|
|
41682
|
+
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
|
|
41255
41683
|
if (actionType === "open_picker") {
|
|
41256
41684
|
out.push({
|
|
41257
41685
|
id,
|
|
@@ -48167,7 +48595,7 @@ var DaemonCommandRouter = class {
|
|
|
48167
48595
|
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.";
|
|
48168
48596
|
if (!firstFailedCmd) return base;
|
|
48169
48597
|
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 : "";
|
|
48170
|
-
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((
|
|
48598
|
+
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|
|
48171
48599
|
const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
|
|
48172
48600
|
return [
|
|
48173
48601
|
base,
|
|
@@ -48918,7 +49346,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
48918
49346
|
convergence = "blocked_review";
|
|
48919
49347
|
}
|
|
48920
49348
|
const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
|
|
48921
|
-
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((
|
|
49349
|
+
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
|
|
48922
49350
|
results.push({
|
|
48923
49351
|
nodeId: node.id,
|
|
48924
49352
|
workspace: node.workspace,
|
|
@@ -49915,7 +50343,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
49915
50343
|
return {
|
|
49916
50344
|
success: true,
|
|
49917
50345
|
screenLineCount: lines.length,
|
|
49918
|
-
sections: resolved.map((
|
|
50346
|
+
sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
|
|
49919
50347
|
};
|
|
49920
50348
|
} catch (e) {
|
|
49921
50349
|
return { success: false, error: `resolve failed: ${e.message}` };
|
|
@@ -50484,7 +50912,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50484
50912
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
50485
50913
|
try {
|
|
50486
50914
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
50487
|
-
const status = Array.isArray(args?.status) ? args.status.map((
|
|
50915
|
+
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
50488
50916
|
const rawQueue = getQueue2(meshId, { status });
|
|
50489
50917
|
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
50490
50918
|
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
@@ -50765,7 +51193,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50765
51193
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50766
51194
|
}
|
|
50767
51195
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50768
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
51196
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50769
51197
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50770
51198
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
50771
51199
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50799,7 +51227,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50799
51227
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50800
51228
|
}
|
|
50801
51229
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50802
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
51230
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50803
51231
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50804
51232
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
50805
51233
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50847,7 +51275,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50847
51275
|
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
50848
51276
|
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
50849
51277
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50850
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
51278
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50851
51279
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50852
51280
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
50853
51281
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
@@ -50934,7 +51362,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50934
51362
|
let worktreeCleanup;
|
|
50935
51363
|
if (node?.isLocalWorktree) {
|
|
50936
51364
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50937
|
-
const isRemoteWorktree = nodeDaemonId && nodeDaemonId
|
|
51365
|
+
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
50938
51366
|
if (isRemoteWorktree) {
|
|
50939
51367
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
50940
51368
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -51016,7 +51444,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
51016
51444
|
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
51017
51445
|
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
51018
51446
|
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
51019
|
-
if (sourceDaemonId && sourceDaemonId
|
|
51447
|
+
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
51020
51448
|
const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
51021
51449
|
...typeof args === "object" && args !== null ? args : {},
|
|
51022
51450
|
_meshDirectDispatch: true
|
|
@@ -51258,7 +51686,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
51258
51686
|
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
51259
51687
|
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
51260
51688
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
51261
|
-
if (nodeDaemonId && nodeDaemonId
|
|
51689
|
+
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
51262
51690
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
51263
51691
|
...typeof args === "object" && args !== null ? args : {},
|
|
51264
51692
|
_meshDirectDispatch: true
|
|
@@ -52468,16 +52896,16 @@ var DaemonStatusReporter = class {
|
|
|
52468
52896
|
const now = this.lastStatusSentAt;
|
|
52469
52897
|
const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
|
|
52470
52898
|
const allStates = this.deps.instanceManager.collectAllStates();
|
|
52471
|
-
const ideStates = allStates.filter((
|
|
52472
|
-
const cliStates = allStates.filter((
|
|
52473
|
-
const acpStates = allStates.filter((
|
|
52474
|
-
const ideSummary = ideStates.map((
|
|
52475
|
-
const msgs =
|
|
52476
|
-
const exts =
|
|
52477
|
-
return `${
|
|
52899
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
52900
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
52901
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
52902
|
+
const ideSummary = ideStates.map((s2) => {
|
|
52903
|
+
const msgs = s2.activeChat?.messages?.length || 0;
|
|
52904
|
+
const exts = s2.extensions.length;
|
|
52905
|
+
return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
|
|
52478
52906
|
}).join(", ");
|
|
52479
|
-
const cliSummary = cliStates.map((
|
|
52480
|
-
const acpSummary = acpStates.map((
|
|
52907
|
+
const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52908
|
+
const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52481
52909
|
const logLevel = opts?.p2pOnly ? "debug" : "info";
|
|
52482
52910
|
const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
|
|
52483
52911
|
const summaryChanged = baseSummary !== this.lastStatusSummary;
|
|
@@ -52588,10 +53016,10 @@ var DaemonStatusReporter = class {
|
|
|
52588
53016
|
}
|
|
52589
53017
|
return false;
|
|
52590
53018
|
}
|
|
52591
|
-
simpleHash(
|
|
53019
|
+
simpleHash(s2) {
|
|
52592
53020
|
let h = 2166136261;
|
|
52593
|
-
for (let i = 0; i <
|
|
52594
|
-
h ^=
|
|
53021
|
+
for (let i = 0; i < s2.length; i++) {
|
|
53022
|
+
h ^= s2.charCodeAt(i);
|
|
52595
53023
|
h = h * 16777619 >>> 0;
|
|
52596
53024
|
}
|
|
52597
53025
|
return h.toString(36);
|
|
@@ -53817,7 +54245,7 @@ var ProviderInstanceManager = class {
|
|
|
53817
54245
|
* Per-category status collect
|
|
53818
54246
|
*/
|
|
53819
54247
|
collectStatesByCategory(category) {
|
|
53820
|
-
return this.collectAllStates().filter((
|
|
54248
|
+
return this.collectAllStates().filter((s2) => s2.category === category);
|
|
53821
54249
|
}
|
|
53822
54250
|
// ─── Tick engine ─────────────────────────────────
|
|
53823
54251
|
/**
|
|
@@ -55717,9 +56145,9 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
|
|
|
55717
56145
|
function findCliTarget(ctx, type, instanceId) {
|
|
55718
56146
|
if (!ctx.instanceManager) return null;
|
|
55719
56147
|
const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
|
|
55720
|
-
if (instanceId) return cliStates.find((
|
|
56148
|
+
if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
|
|
55721
56149
|
if (!type) return cliStates[cliStates.length - 1] || null;
|
|
55722
|
-
const matches = cliStates.filter((
|
|
56150
|
+
const matches = cliStates.filter((s2) => s2.type === type);
|
|
55723
56151
|
return matches[matches.length - 1] || null;
|
|
55724
56152
|
}
|
|
55725
56153
|
function getCliTargetBundle(ctx, type, instanceId) {
|
|
@@ -56082,20 +56510,20 @@ async function handleCliStatus(ctx, _req, res) {
|
|
|
56082
56510
|
return;
|
|
56083
56511
|
}
|
|
56084
56512
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56085
|
-
const cliStates = allStates.filter((
|
|
56086
|
-
const result = cliStates.map((
|
|
56087
|
-
instanceId:
|
|
56088
|
-
type:
|
|
56089
|
-
name:
|
|
56090
|
-
category:
|
|
56091
|
-
status:
|
|
56092
|
-
mode:
|
|
56093
|
-
workspace:
|
|
56094
|
-
messageCount:
|
|
56095
|
-
lastMessage:
|
|
56096
|
-
activeModal:
|
|
56097
|
-
pendingEvents:
|
|
56098
|
-
settings:
|
|
56513
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56514
|
+
const result = cliStates.map((s2) => ({
|
|
56515
|
+
instanceId: s2.instanceId,
|
|
56516
|
+
type: s2.type,
|
|
56517
|
+
name: s2.name,
|
|
56518
|
+
category: s2.category,
|
|
56519
|
+
status: s2.status,
|
|
56520
|
+
mode: s2.mode,
|
|
56521
|
+
workspace: s2.workspace,
|
|
56522
|
+
messageCount: s2.activeChat?.messages?.length || 0,
|
|
56523
|
+
lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
|
|
56524
|
+
activeModal: s2.activeChat?.activeModal || null,
|
|
56525
|
+
pendingEvents: s2.pendingEvents || [],
|
|
56526
|
+
settings: s2.settings
|
|
56099
56527
|
}));
|
|
56100
56528
|
ctx.json(res, 200, { instances: result, count: result.length });
|
|
56101
56529
|
}
|
|
@@ -56184,9 +56612,9 @@ function handleCliSSE(ctx, cliSSEClients, _req, res) {
|
|
|
56184
56612
|
}
|
|
56185
56613
|
if (ctx.instanceManager) {
|
|
56186
56614
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56187
|
-
const cliStates = allStates.filter((
|
|
56188
|
-
for (const
|
|
56189
|
-
ctx.sendCliSSE({ event: "snapshot", providerType:
|
|
56615
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56616
|
+
for (const s2 of cliStates) {
|
|
56617
|
+
ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
|
|
56190
56618
|
}
|
|
56191
56619
|
}
|
|
56192
56620
|
_req.on("close", () => {
|
|
@@ -56202,7 +56630,7 @@ async function handleCliDebug(ctx, type, _req, res) {
|
|
|
56202
56630
|
const target = findCliTarget(ctx, type);
|
|
56203
56631
|
if (!target) {
|
|
56204
56632
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56205
|
-
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((
|
|
56633
|
+
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
|
|
56206
56634
|
return;
|
|
56207
56635
|
}
|
|
56208
56636
|
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
@@ -56248,7 +56676,7 @@ async function handleCliTrace(ctx, type, req, res) {
|
|
|
56248
56676
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
56249
56677
|
ctx.json(res, 404, {
|
|
56250
56678
|
error: `No running instance for: ${type}`,
|
|
56251
|
-
available: allStates.filter((
|
|
56679
|
+
available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
|
|
56252
56680
|
});
|
|
56253
56681
|
return;
|
|
56254
56682
|
}
|
|
@@ -57053,7 +57481,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
57053
57481
|
child.write("\x1B[12;1R");
|
|
57054
57482
|
ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
|
|
57055
57483
|
}
|
|
57056
|
-
checkAutoApproval(data, (
|
|
57484
|
+
checkAutoApproval(data, (s2) => child.write(s2));
|
|
57057
57485
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
|
|
57058
57486
|
scheduleAutoStopForVerification();
|
|
57059
57487
|
});
|
|
@@ -57066,7 +57494,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
57066
57494
|
stdout += chunk;
|
|
57067
57495
|
clearAutoStopTimer();
|
|
57068
57496
|
if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
|
|
57069
|
-
checkAutoApproval(chunk, (
|
|
57497
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
57070
57498
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
|
|
57071
57499
|
scheduleAutoStopForVerification();
|
|
57072
57500
|
});
|
|
@@ -57074,7 +57502,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
57074
57502
|
const chunk = d.toString();
|
|
57075
57503
|
stderr += chunk;
|
|
57076
57504
|
clearAutoStopTimer();
|
|
57077
|
-
checkAutoApproval(chunk, (
|
|
57505
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
57078
57506
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
|
|
57079
57507
|
scheduleAutoStopForVerification();
|
|
57080
57508
|
});
|
|
@@ -57889,59 +58317,59 @@ var DevServer = class _DevServer {
|
|
|
57889
58317
|
// ─── Route Table ─────────────────────────────────────
|
|
57890
58318
|
routes = [
|
|
57891
58319
|
// Static routes
|
|
57892
|
-
{ method: "GET", pattern: "/api/providers", handler: (q,
|
|
57893
|
-
{ method: "GET", pattern: "/api/providers/source-config", handler: (q,
|
|
57894
|
-
{ method: "POST", pattern: "/api/providers/source-config", handler: (q,
|
|
57895
|
-
{ method: "GET", pattern: "/api/providers/versions", handler: (q,
|
|
57896
|
-
{ method: "POST", pattern: "/api/providers/reload", handler: (q,
|
|
57897
|
-
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q,
|
|
57898
|
-
{ method: "POST", pattern: "/api/cdp/click", handler: (q,
|
|
57899
|
-
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q,
|
|
57900
|
-
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q,
|
|
57901
|
-
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q,
|
|
57902
|
-
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q,
|
|
57903
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q,
|
|
57904
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q,
|
|
57905
|
-
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q,
|
|
57906
|
-
{ method: "GET", pattern: "/api/cdp/targets", handler: (q,
|
|
57907
|
-
{ method: "POST", pattern: "/api/scripts/run", handler: (q,
|
|
57908
|
-
{ method: "GET", pattern: "/api/status", handler: (q,
|
|
57909
|
-
{ method: "POST", pattern: "/api/watch/start", handler: (q,
|
|
57910
|
-
{ method: "POST", pattern: "/api/watch/stop", handler: (q,
|
|
57911
|
-
{ method: "GET", pattern: "/api/watch/events", handler: (q,
|
|
57912
|
-
{ method: "POST", pattern: "/api/scaffold", handler: (q,
|
|
58320
|
+
{ method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
|
|
58321
|
+
{ method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
|
|
58322
|
+
{ method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
|
|
58323
|
+
{ method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
|
|
58324
|
+
{ method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
|
|
58325
|
+
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
|
|
58326
|
+
{ method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
|
|
58327
|
+
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
|
|
58328
|
+
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
|
|
58329
|
+
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
|
|
58330
|
+
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
|
|
58331
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
|
|
58332
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
|
|
58333
|
+
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
|
|
58334
|
+
{ method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
|
|
58335
|
+
{ method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
|
|
58336
|
+
{ method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
|
|
58337
|
+
{ method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
|
|
58338
|
+
{ method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
|
|
58339
|
+
{ method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
|
|
58340
|
+
{ method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
|
|
57913
58341
|
// CLI Debug routes
|
|
57914
|
-
{ method: "GET", pattern: "/api/cli/status", handler: (q,
|
|
57915
|
-
{ method: "POST", pattern: "/api/cli/launch", handler: (q,
|
|
57916
|
-
{ method: "POST", pattern: "/api/cli/send", handler: (q,
|
|
57917
|
-
{ method: "POST", pattern: "/api/cli/exercise", handler: (q,
|
|
57918
|
-
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q,
|
|
57919
|
-
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q,
|
|
57920
|
-
{ method: "POST", pattern: "/api/cli/resolve", handler: (q,
|
|
57921
|
-
{ method: "POST", pattern: "/api/cli/raw", handler: (q,
|
|
57922
|
-
{ method: "POST", pattern: "/api/cli/stop", handler: (q,
|
|
57923
|
-
{ method: "GET", pattern: "/api/cli/events", handler: (q,
|
|
57924
|
-
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q,
|
|
57925
|
-
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q,
|
|
57926
|
-
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q,
|
|
58342
|
+
{ method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
|
|
58343
|
+
{ method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
|
|
58344
|
+
{ method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
|
|
58345
|
+
{ method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
|
|
58346
|
+
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
|
|
58347
|
+
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
|
|
58348
|
+
{ method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
|
|
58349
|
+
{ method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
|
|
58350
|
+
{ method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
|
|
58351
|
+
{ method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
|
|
58352
|
+
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
|
|
58353
|
+
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
|
|
58354
|
+
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
|
|
57927
58355
|
// Dynamic routes (provider :type param)
|
|
57928
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q,
|
|
57929
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q,
|
|
57930
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57931
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57932
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q,
|
|
57933
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q,
|
|
57934
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q,
|
|
57935
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q,
|
|
57936
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q,
|
|
57937
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q,
|
|
57938
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q,
|
|
57939
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q,
|
|
57940
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q,
|
|
57941
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q,
|
|
57942
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q,
|
|
57943
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q,
|
|
57944
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q,
|
|
58356
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
|
|
58357
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
|
|
58358
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
|
|
58359
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
|
|
58360
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
|
|
58361
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
|
|
58362
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
|
|
58363
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
|
|
58364
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
|
|
58365
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
|
|
58366
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
|
|
58367
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
|
|
58368
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
|
|
58369
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
|
|
58370
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
|
|
58371
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
|
|
58372
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
|
|
57945
58373
|
];
|
|
57946
58374
|
matchRoute(method, pathname) {
|
|
57947
58375
|
for (const route of this.routes) {
|
|
@@ -58536,14 +58964,14 @@ var DevServer = class _DevServer {
|
|
|
58536
58964
|
warnings.push(...validation.warnings);
|
|
58537
58965
|
if (config.settings) {
|
|
58538
58966
|
for (const [key, val] of Object.entries(config.settings)) {
|
|
58539
|
-
const
|
|
58540
|
-
if (!
|
|
58541
|
-
else if (!["boolean", "number", "string", "select"].includes(
|
|
58542
|
-
errors.push(`settings.${key}: invalid type '${
|
|
58543
|
-
if (
|
|
58544
|
-
if (
|
|
58545
|
-
errors.push(`settings.${key}: min (${
|
|
58546
|
-
if (
|
|
58967
|
+
const s2 = val;
|
|
58968
|
+
if (!s2.type) errors.push(`settings.${key}: missing type`);
|
|
58969
|
+
else if (!["boolean", "number", "string", "select"].includes(s2.type))
|
|
58970
|
+
errors.push(`settings.${key}: invalid type '${s2.type}'`);
|
|
58971
|
+
if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
|
|
58972
|
+
if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
|
|
58973
|
+
errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
|
|
58974
|
+
if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
|
|
58547
58975
|
errors.push(`settings.${key}: select type requires options[]`);
|
|
58548
58976
|
}
|
|
58549
58977
|
}
|