@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.mjs
CHANGED
|
@@ -311,10 +311,10 @@ function readInjected(value) {
|
|
|
311
311
|
}
|
|
312
312
|
function getDaemonBuildInfo() {
|
|
313
313
|
if (cached) return cached;
|
|
314
|
-
const commit = readInjected(true ? "
|
|
315
|
-
const commitShort = readInjected(true ? "
|
|
316
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
317
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
314
|
+
const commit = readInjected(true ? "91500e054cf2b6258f6041f90c18be03ad05a8ad" : void 0) ?? "unknown";
|
|
315
|
+
const commitShort = readInjected(true ? "91500e05" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
316
|
+
const version = readInjected(true ? "0.9.82-rc.356" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
317
|
+
const builtAt = readInjected(true ? "2026-06-22T22:47:29.082Z" : void 0);
|
|
318
318
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
319
319
|
return cached;
|
|
320
320
|
}
|
|
@@ -4822,9 +4822,12 @@ function getActiveDirectDispatches(meshId) {
|
|
|
4822
4822
|
return [];
|
|
4823
4823
|
}
|
|
4824
4824
|
}
|
|
4825
|
-
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
4825
|
+
function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
4826
4826
|
try {
|
|
4827
|
-
|
|
4827
|
+
if (!taskId) {
|
|
4828
|
+
LOG.warn("MeshQueue", `updateDirectDispatchStatus(${status}) for mesh ${meshId} session ${sessionId} has no taskId \u2014 falling back to session_id match (may flip a sibling dispatch row)`);
|
|
4829
|
+
}
|
|
4830
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
|
|
4828
4831
|
} catch {
|
|
4829
4832
|
}
|
|
4830
4833
|
}
|
|
@@ -5656,9 +5659,25 @@ var init_mesh_runtime_store = __esm({
|
|
|
5656
5659
|
updatedAt: r.updated_at
|
|
5657
5660
|
}));
|
|
5658
5661
|
}
|
|
5659
|
-
|
|
5660
|
-
|
|
5662
|
+
// CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
|
|
5663
|
+
// single session can host several sequential direct dispatches (re-dispatch / nudge), so
|
|
5664
|
+
// matching a status flip by session_id alone hits EVERY non-terminal row for that session
|
|
5665
|
+
// — flipping a sibling task's row and stranding the one whose event actually fired (the
|
|
5666
|
+
// assigned-stranded watchdog then requeues a task that is really still generating). When
|
|
5667
|
+
// the firing event carries a taskId, target the single PK row; the session_id match is the
|
|
5668
|
+
// legacy fallback only for events that arrive without a taskId.
|
|
5669
|
+
updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
|
|
5661
5670
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5671
|
+
if (taskId) {
|
|
5672
|
+
this.db.prepare(`
|
|
5673
|
+
UPDATE mesh_direct_dispatches
|
|
5674
|
+
SET status = @status, updated_at = @updatedAt
|
|
5675
|
+
WHERE mesh_id = @meshId AND task_id = @taskId
|
|
5676
|
+
AND status NOT IN ('completed', 'failed')
|
|
5677
|
+
`).run({ status, meshId, taskId, updatedAt: now });
|
|
5678
|
+
return;
|
|
5679
|
+
}
|
|
5680
|
+
if (!sessionId) return;
|
|
5662
5681
|
this.db.prepare(`
|
|
5663
5682
|
UPDATE mesh_direct_dispatches
|
|
5664
5683
|
SET status = @status, updated_at = @updatedAt
|
|
@@ -7387,7 +7406,7 @@ function resolveWin32Executable(command) {
|
|
|
7387
7406
|
windowsHide: true
|
|
7388
7407
|
}).trim();
|
|
7389
7408
|
if (out) {
|
|
7390
|
-
const matches = out.split(/\r?\n/).map((
|
|
7409
|
+
const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
|
|
7391
7410
|
const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
|
|
7392
7411
|
return direct || matches[0] || command;
|
|
7393
7412
|
}
|
|
@@ -8739,11 +8758,29 @@ function hasPendingRefineTerminalEventDuplicate(event) {
|
|
|
8739
8758
|
(pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
|
|
8740
8759
|
);
|
|
8741
8760
|
}
|
|
8761
|
+
function isWeakCompletionMetadata(metadata) {
|
|
8762
|
+
const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
|
|
8763
|
+
if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
|
|
8764
|
+
if (metadata.reviewRecommended === true) return true;
|
|
8765
|
+
const diag = readRecord4(metadata.completionDiagnostic);
|
|
8766
|
+
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
8767
|
+
}
|
|
8742
8768
|
function buildPendingEventFingerprint(event) {
|
|
8743
8769
|
const metadata = readRecord4(event.metadataEvent) || {};
|
|
8744
8770
|
if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
|
|
8745
8771
|
return [event.meshId, event.event, event.nodeId || ""].join("::");
|
|
8746
8772
|
}
|
|
8773
|
+
if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
|
|
8774
|
+
const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
8775
|
+
if (terminalTaskId) {
|
|
8776
|
+
return [
|
|
8777
|
+
event.meshId,
|
|
8778
|
+
event.event,
|
|
8779
|
+
terminalTaskId,
|
|
8780
|
+
isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
|
|
8781
|
+
].join("::");
|
|
8782
|
+
}
|
|
8783
|
+
}
|
|
8747
8784
|
const sessionId = resolveEventSessionId(metadata);
|
|
8748
8785
|
const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
|
|
8749
8786
|
const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
|
|
@@ -9102,7 +9139,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
9102
9139
|
}
|
|
9103
9140
|
}
|
|
9104
9141
|
}
|
|
9105
|
-
var REFINE_TERMINAL_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9142
|
+
var REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
|
|
9106
9143
|
var init_mesh_events_pending = __esm({
|
|
9107
9144
|
"src/mesh/mesh-events-pending.ts"() {
|
|
9108
9145
|
"use strict";
|
|
@@ -9112,6 +9149,7 @@ var init_mesh_events_pending = __esm({
|
|
|
9112
9149
|
init_mesh_events_utils();
|
|
9113
9150
|
init_dist();
|
|
9114
9151
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
9152
|
+
TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
|
|
9115
9153
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
9116
9154
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
9117
9155
|
}
|
|
@@ -9441,7 +9479,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
|
|
|
9441
9479
|
evidence
|
|
9442
9480
|
}
|
|
9443
9481
|
});
|
|
9444
|
-
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9482
|
+
updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
|
|
9445
9483
|
markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
|
|
9446
9484
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
9447
9485
|
queuePendingMeshCoordinatorEvent({
|
|
@@ -9736,8 +9774,8 @@ function parsePatternEntry(x) {
|
|
|
9736
9774
|
if (x instanceof RegExp) return x;
|
|
9737
9775
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
9738
9776
|
try {
|
|
9739
|
-
const
|
|
9740
|
-
return new RegExp(
|
|
9777
|
+
const s2 = x;
|
|
9778
|
+
return new RegExp(s2.source, s2.flags || "");
|
|
9741
9779
|
} catch {
|
|
9742
9780
|
return null;
|
|
9743
9781
|
}
|
|
@@ -10305,6 +10343,38 @@ var init_mesh_unresolved_forward_outbox = __esm({
|
|
|
10305
10343
|
}
|
|
10306
10344
|
});
|
|
10307
10345
|
|
|
10346
|
+
// src/mesh/mesh-event-trace.ts
|
|
10347
|
+
function s(v) {
|
|
10348
|
+
return typeof v === "string" && v.trim() ? v.trim() : "";
|
|
10349
|
+
}
|
|
10350
|
+
function meshEventTraceKey(ctx) {
|
|
10351
|
+
const segs = [`task=${s(ctx.taskId) || "-"}`];
|
|
10352
|
+
const eventId = s(ctx.eventId);
|
|
10353
|
+
if (eventId) segs.push(`evt=${eventId}`);
|
|
10354
|
+
segs.push(`sess=${s(ctx.sessionId) || "-"}`);
|
|
10355
|
+
const nodeId = s(ctx.nodeId);
|
|
10356
|
+
if (nodeId) segs.push(`node=${nodeId}`);
|
|
10357
|
+
const meshId = s(ctx.meshId);
|
|
10358
|
+
if (meshId) segs.push(`mesh=${meshId}`);
|
|
10359
|
+
const event = s(ctx.event);
|
|
10360
|
+
if (event) segs.push(`event=${event}`);
|
|
10361
|
+
return segs.join(" ");
|
|
10362
|
+
}
|
|
10363
|
+
function traceMeshEventStage(stage, ctx, detail) {
|
|
10364
|
+
LOG.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10365
|
+
}
|
|
10366
|
+
function traceMeshEventDrop(reason, ctx, detail) {
|
|
10367
|
+
LOG.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
|
|
10368
|
+
}
|
|
10369
|
+
var CAT;
|
|
10370
|
+
var init_mesh_event_trace = __esm({
|
|
10371
|
+
"src/mesh/mesh-event-trace.ts"() {
|
|
10372
|
+
"use strict";
|
|
10373
|
+
init_logger();
|
|
10374
|
+
CAT = "EvtTrace";
|
|
10375
|
+
}
|
|
10376
|
+
});
|
|
10377
|
+
|
|
10308
10378
|
// src/config/state-store.ts
|
|
10309
10379
|
import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
10310
10380
|
import { join as join18 } from "path";
|
|
@@ -12090,9 +12160,9 @@ function buildAcpSession(state, options) {
|
|
|
12090
12160
|
}
|
|
12091
12161
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
12092
12162
|
const sessions = [];
|
|
12093
|
-
const ideStates = allStates.filter((
|
|
12094
|
-
const cliStates = allStates.filter((
|
|
12095
|
-
const acpStates = allStates.filter((
|
|
12163
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
12164
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
12165
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
12096
12166
|
for (const state of ideStates) {
|
|
12097
12167
|
sessions.push(buildWorkspaceSession(state, cdpManagers, options));
|
|
12098
12168
|
for (const ext of state.extensions) {
|
|
@@ -12577,6 +12647,15 @@ function getCachedMeshByWorkspace(workspace) {
|
|
|
12577
12647
|
meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
|
|
12578
12648
|
return mesh;
|
|
12579
12649
|
}
|
|
12650
|
+
function recoverMeshIdByNodeId(nodeId) {
|
|
12651
|
+
if (!nodeId) return "";
|
|
12652
|
+
for (const mesh of listMeshes()) {
|
|
12653
|
+
if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
|
|
12654
|
+
return readNonEmptyString2(mesh.id);
|
|
12655
|
+
}
|
|
12656
|
+
}
|
|
12657
|
+
return "";
|
|
12658
|
+
}
|
|
12580
12659
|
function __resetIdleAutoFastForwardForTests() {
|
|
12581
12660
|
idleAutoFastForwardLastAttempt.clear();
|
|
12582
12661
|
}
|
|
@@ -13479,6 +13558,13 @@ function shouldForceInjectMeshEvent(eventName) {
|
|
|
13479
13558
|
function injectMeshSystemMessage(components, args) {
|
|
13480
13559
|
const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
13481
13560
|
const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13561
|
+
const traceCtx = {
|
|
13562
|
+
taskId: args.metadataEvent.taskId,
|
|
13563
|
+
sessionId: eventSessionId,
|
|
13564
|
+
nodeId: eventNodeId,
|
|
13565
|
+
meshId: args.meshId,
|
|
13566
|
+
event: args.event
|
|
13567
|
+
};
|
|
13482
13568
|
const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
|
|
13483
13569
|
const workerCoordinatorDaemonId = readNonEmptyString2(
|
|
13484
13570
|
sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
|
|
@@ -13532,6 +13618,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13532
13618
|
}
|
|
13533
13619
|
}
|
|
13534
13620
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
13621
|
+
traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
|
|
13535
13622
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
13536
13623
|
}
|
|
13537
13624
|
if (args.event === "monitor:no_progress") {
|
|
@@ -13552,6 +13639,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13552
13639
|
}
|
|
13553
13640
|
if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
|
|
13554
13641
|
LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
|
|
13642
|
+
traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
|
|
13555
13643
|
return {
|
|
13556
13644
|
success: true,
|
|
13557
13645
|
forwarded: 0,
|
|
@@ -13563,6 +13651,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13563
13651
|
}
|
|
13564
13652
|
if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
|
|
13565
13653
|
LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
|
|
13654
|
+
traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
|
|
13566
13655
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
13567
13656
|
}
|
|
13568
13657
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
@@ -13577,6 +13666,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13577
13666
|
});
|
|
13578
13667
|
if (duplicateApproval) {
|
|
13579
13668
|
LOG.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13669
|
+
traceMeshEventDrop("duplicate_approval", traceCtx);
|
|
13580
13670
|
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
13581
13671
|
}
|
|
13582
13672
|
}
|
|
@@ -13596,6 +13686,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13596
13686
|
const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
13597
13687
|
if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
|
|
13598
13688
|
LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13689
|
+
traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
|
|
13599
13690
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
|
|
13600
13691
|
}
|
|
13601
13692
|
}
|
|
@@ -13614,6 +13705,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13614
13705
|
});
|
|
13615
13706
|
if (duplicateCompletion) {
|
|
13616
13707
|
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13708
|
+
traceMeshEventDrop("duplicate_completion", traceCtx);
|
|
13617
13709
|
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
13618
13710
|
}
|
|
13619
13711
|
}
|
|
@@ -13632,6 +13724,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13632
13724
|
});
|
|
13633
13725
|
if (duplicateStopped) {
|
|
13634
13726
|
LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
13727
|
+
traceMeshEventDrop("duplicate_stopped", traceCtx);
|
|
13635
13728
|
return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
|
|
13636
13729
|
}
|
|
13637
13730
|
}
|
|
@@ -13643,7 +13736,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13643
13736
|
});
|
|
13644
13737
|
const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
|
|
13645
13738
|
if (!leaveDirectDispatchActive) {
|
|
13646
|
-
updateDirectDispatchStatus(args.meshId, sessionId, outcome);
|
|
13739
|
+
updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
|
|
13647
13740
|
}
|
|
13648
13741
|
markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
|
|
13649
13742
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
@@ -13656,7 +13749,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13656
13749
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
13657
13750
|
const providerType = readNonEmptyString2(args.metadataEvent.providerType);
|
|
13658
13751
|
if (sessionId) {
|
|
13659
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13752
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13660
13753
|
const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
|
|
13661
13754
|
completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
|
|
13662
13755
|
if (nodeId && providerType) {
|
|
@@ -13739,7 +13832,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13739
13832
|
}
|
|
13740
13833
|
}
|
|
13741
13834
|
if (sessionId) {
|
|
13742
|
-
|
|
13835
|
+
const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
|
|
13836
|
+
updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
|
|
13743
13837
|
const activeDeliveries = (() => {
|
|
13744
13838
|
try {
|
|
13745
13839
|
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
|
|
@@ -13747,7 +13841,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13747
13841
|
return [];
|
|
13748
13842
|
}
|
|
13749
13843
|
})();
|
|
13750
|
-
|
|
13844
|
+
const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
|
|
13845
|
+
for (const d of deliveriesToAck) {
|
|
13751
13846
|
updateSessionDeliveryStatus(d.id, "acked");
|
|
13752
13847
|
}
|
|
13753
13848
|
}
|
|
@@ -13761,7 +13856,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13761
13856
|
}
|
|
13762
13857
|
}
|
|
13763
13858
|
if (sessionId) {
|
|
13764
|
-
directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13859
|
+
directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
|
|
13765
13860
|
completedTaskForLedger = markSessionTerminal(sessionId, "failed");
|
|
13766
13861
|
}
|
|
13767
13862
|
}
|
|
@@ -13907,6 +14002,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
13907
14002
|
};
|
|
13908
14003
|
if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
|
|
13909
14004
|
LOG.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
|
|
14005
|
+
traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
|
|
14006
|
+
} else {
|
|
14007
|
+
traceMeshEventDrop("queue_dedup", traceCtx);
|
|
13910
14008
|
}
|
|
13911
14009
|
return { success: true, forwarded: 0 };
|
|
13912
14010
|
}
|
|
@@ -13917,8 +14015,23 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
13917
14015
|
}
|
|
13918
14016
|
const nodeId = readNonEmptyString2(payload.nodeId);
|
|
13919
14017
|
const workspace = readNonEmptyString2(payload.workspace);
|
|
13920
|
-
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
|
|
13921
|
-
if (!meshId)
|
|
14018
|
+
const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
|
|
14019
|
+
if (!meshId) {
|
|
14020
|
+
traceMeshEventDrop("meshId_required", {
|
|
14021
|
+
taskId: payload.taskId,
|
|
14022
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14023
|
+
nodeId,
|
|
14024
|
+
event: eventName
|
|
14025
|
+
}, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
|
|
14026
|
+
return { success: false, error: "meshId required" };
|
|
14027
|
+
}
|
|
14028
|
+
traceMeshEventStage("received", {
|
|
14029
|
+
taskId: payload.taskId,
|
|
14030
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14031
|
+
nodeId,
|
|
14032
|
+
meshId,
|
|
14033
|
+
event: eventName
|
|
14034
|
+
});
|
|
13922
14035
|
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
13923
14036
|
const relayModalMessage = readNonEmptyString2(payload.modalMessage);
|
|
13924
14037
|
const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
|
|
@@ -13999,9 +14112,18 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
|
|
|
13999
14112
|
workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
|
|
14000
14113
|
};
|
|
14001
14114
|
const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
|
|
14115
|
+
const fwdTraceCtx = {
|
|
14116
|
+
taskId: payload.taskId,
|
|
14117
|
+
sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
|
|
14118
|
+
nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
|
|
14119
|
+
event: eventName
|
|
14120
|
+
};
|
|
14121
|
+
traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
|
|
14122
|
+
traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
|
|
14002
14123
|
Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
|
|
14003
14124
|
if (result && result.success === false) {
|
|
14004
14125
|
LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
|
|
14126
|
+
traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14005
14127
|
return;
|
|
14006
14128
|
}
|
|
14007
14129
|
if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
|
|
@@ -14069,6 +14191,14 @@ function setupMeshEventForwarding(components) {
|
|
|
14069
14191
|
if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
|
|
14070
14192
|
return;
|
|
14071
14193
|
}
|
|
14194
|
+
if (isUnroutableDelegateRejection(routing)) {
|
|
14195
|
+
traceMeshEventDrop("unroutable", {
|
|
14196
|
+
taskId: event.meshActiveTaskId ?? event.taskId,
|
|
14197
|
+
sessionId: routing.sessionId,
|
|
14198
|
+
nodeId: routing.nodeId,
|
|
14199
|
+
event: event.event
|
|
14200
|
+
}, "no coordinator anchor / mesh_unresolved");
|
|
14201
|
+
}
|
|
14072
14202
|
recordUnroutableDelegateEvent(routing, event.event);
|
|
14073
14203
|
return;
|
|
14074
14204
|
}
|
|
@@ -14098,6 +14228,7 @@ var init_mesh_events_coordinator = __esm({
|
|
|
14098
14228
|
init_mesh_events_pending();
|
|
14099
14229
|
init_mesh_routing();
|
|
14100
14230
|
init_mesh_unresolved_forward_outbox();
|
|
14231
|
+
init_mesh_event_trace();
|
|
14101
14232
|
init_snapshot();
|
|
14102
14233
|
init_repo_mesh_types();
|
|
14103
14234
|
init_dist();
|
|
@@ -14209,6 +14340,13 @@ function findLiveCoordinators(components) {
|
|
|
14209
14340
|
function injectPendingIntoCoordinator(coordinator, pending) {
|
|
14210
14341
|
if (!coordinator || !pending.coordinatorMessage) return;
|
|
14211
14342
|
const force = shouldForceInjectMeshEvent(pending.event);
|
|
14343
|
+
traceMeshEventStage("surfaced", {
|
|
14344
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14345
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
|
|
14346
|
+
nodeId: pending.nodeId,
|
|
14347
|
+
meshId: pending.meshId,
|
|
14348
|
+
event: pending.event
|
|
14349
|
+
}, force ? "force-inject" : "inject");
|
|
14212
14350
|
coordinator.onEvent("send_message", {
|
|
14213
14351
|
input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
|
|
14214
14352
|
...force ? { force: true } : {}
|
|
@@ -14267,6 +14405,13 @@ function recoverStrandedAssignedDispatches(meshId, store) {
|
|
|
14267
14405
|
});
|
|
14268
14406
|
if (reclaimed) {
|
|
14269
14407
|
LOG.warn("MeshReconcile", `Reclaimed stranded assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, dispatched ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s ago, never confirmed delivered \u2192 ${reclaimed.status})`);
|
|
14408
|
+
traceMeshEventDrop("assigned_stranded_reclaim", {
|
|
14409
|
+
taskId: row.id,
|
|
14410
|
+
sessionId: row.assignedSessionId,
|
|
14411
|
+
nodeId: row.assignedNodeId,
|
|
14412
|
+
meshId,
|
|
14413
|
+
event: "agent:generating_completed"
|
|
14414
|
+
}, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
|
|
14270
14415
|
}
|
|
14271
14416
|
}
|
|
14272
14417
|
}
|
|
@@ -14426,6 +14571,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14426
14571
|
try {
|
|
14427
14572
|
queuePendingMeshCoordinatorEvent(pending);
|
|
14428
14573
|
LOG.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
|
|
14574
|
+
traceMeshEventDrop("strict_route_hold", {
|
|
14575
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14576
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14577
|
+
nodeId: pending.nodeId,
|
|
14578
|
+
meshId,
|
|
14579
|
+
event: pending.event
|
|
14580
|
+
}, `coordinatorSession=${wantSession} not live`);
|
|
14429
14581
|
} catch (e) {
|
|
14430
14582
|
LOG.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
|
|
14431
14583
|
}
|
|
@@ -14449,6 +14601,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
|
|
|
14449
14601
|
}
|
|
14450
14602
|
});
|
|
14451
14603
|
LOG.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
|
|
14604
|
+
traceMeshEventDrop("strict_route_expired", {
|
|
14605
|
+
taskId: pending.metadataEvent?.taskId,
|
|
14606
|
+
sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
|
|
14607
|
+
nodeId: pending.nodeId,
|
|
14608
|
+
meshId,
|
|
14609
|
+
event: pending.event
|
|
14610
|
+
}, `coordinatorSession=${wantSession} never returned`);
|
|
14452
14611
|
} catch (e) {
|
|
14453
14612
|
LOG.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
|
|
14454
14613
|
}
|
|
@@ -14460,15 +14619,24 @@ async function retryUnresolvedDelegateForwards(components) {
|
|
|
14460
14619
|
const entries = peekUnresolvedDelegateForwards();
|
|
14461
14620
|
if (entries.length === 0) return;
|
|
14462
14621
|
for (const entry of entries) {
|
|
14622
|
+
const entryTraceCtx = {
|
|
14623
|
+
taskId: entry.payload.taskId,
|
|
14624
|
+
sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
|
|
14625
|
+
nodeId: readNonEmptyString2(entry.payload.nodeId),
|
|
14626
|
+
event: readNonEmptyString2(entry.payload.event)
|
|
14627
|
+
};
|
|
14463
14628
|
let result;
|
|
14464
14629
|
try {
|
|
14630
|
+
traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
|
|
14465
14631
|
result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
|
|
14466
14632
|
} catch (e) {
|
|
14467
14633
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
|
|
14634
|
+
traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
|
|
14468
14635
|
continue;
|
|
14469
14636
|
}
|
|
14470
14637
|
if (result && result.success === false) {
|
|
14471
14638
|
LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
|
|
14639
|
+
traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
|
|
14472
14640
|
continue;
|
|
14473
14641
|
}
|
|
14474
14642
|
ackUnresolvedDelegateForward(entry.id);
|
|
@@ -14710,6 +14878,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
14710
14878
|
init_mesh_events_coordinator();
|
|
14711
14879
|
init_mesh_unresolved_forward_outbox();
|
|
14712
14880
|
init_mesh_events_utils();
|
|
14881
|
+
init_mesh_event_trace();
|
|
14713
14882
|
init_dist();
|
|
14714
14883
|
init_mesh_work_queue();
|
|
14715
14884
|
init_mesh_ledger();
|
|
@@ -15548,8 +15717,8 @@ function saveProvidersActive(file) {
|
|
|
15548
15717
|
}
|
|
15549
15718
|
function isValidSource(x) {
|
|
15550
15719
|
if (!x || typeof x !== "object") return false;
|
|
15551
|
-
const
|
|
15552
|
-
return typeof
|
|
15720
|
+
const s2 = x;
|
|
15721
|
+
return typeof s2.name === "string" && s2.name.length > 0 && typeof s2.url === "string" && s2.url.length > 0 && typeof s2.ref === "string" && s2.ref.length > 0 && typeof s2.addedAt === "string";
|
|
15553
15722
|
}
|
|
15554
15723
|
function deriveSourceName(url) {
|
|
15555
15724
|
const m = url.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -15605,7 +15774,7 @@ function inventoryExternalSources() {
|
|
|
15605
15774
|
}
|
|
15606
15775
|
function sourcesProviding(category, type) {
|
|
15607
15776
|
const inventory = inventoryExternalSources();
|
|
15608
|
-
return inventory.filter((
|
|
15777
|
+
return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
|
|
15609
15778
|
}
|
|
15610
15779
|
function resolveActiveSource(category, type, activeFile) {
|
|
15611
15780
|
const candidates = sourcesProviding(category, type);
|
|
@@ -15809,10 +15978,10 @@ function compileSettledPromptMatchers(spec) {
|
|
|
15809
15978
|
const footers = (spec.withFooter ?? []).map((f) => {
|
|
15810
15979
|
if (f.kind === "regex") {
|
|
15811
15980
|
const re = compile2(f.pattern, f.flags ?? "i");
|
|
15812
|
-
return { test: (
|
|
15981
|
+
return { test: (s2) => re.test(s2) };
|
|
15813
15982
|
}
|
|
15814
15983
|
const needle = f.pattern.toLowerCase();
|
|
15815
|
-
return { test: (
|
|
15984
|
+
return { test: (s2) => s2.toLowerCase().includes(needle) };
|
|
15816
15985
|
});
|
|
15817
15986
|
return { prompt, footers };
|
|
15818
15987
|
}
|
|
@@ -16686,7 +16855,7 @@ var init_cli_state_engine = __esm({
|
|
|
16686
16855
|
}
|
|
16687
16856
|
resolveModal(buttonIndex) {
|
|
16688
16857
|
const snap = this.transport.getSnapshot();
|
|
16689
|
-
const parseApproval = typeof this.transport.runParseApproval === "function" ? (
|
|
16858
|
+
const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
|
|
16690
16859
|
let modal = this.activeModal ?? parseApproval(snap);
|
|
16691
16860
|
if (!modal && this.runner.hasParseSession()) {
|
|
16692
16861
|
try {
|
|
@@ -19374,22 +19543,23 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19374
19543
|
const matchesCandidate = (c, i) => c.re.test(lines[i]) && (c.prevRe === null || i > 0 && c.prevRe.test(lines[i - 1])) && (c.nextRe === null || i < total - 1 && c.nextRe.test(lines[i + 1]));
|
|
19375
19544
|
let idx = -1;
|
|
19376
19545
|
for (const c of candidates) {
|
|
19546
|
+
let candIdx = -1;
|
|
19377
19547
|
if (sec.anchor_last) {
|
|
19378
19548
|
for (let i = total - 1; i >= 0; i--) {
|
|
19379
19549
|
if (matchesCandidate(c, i)) {
|
|
19380
|
-
|
|
19550
|
+
candIdx = i;
|
|
19381
19551
|
break;
|
|
19382
19552
|
}
|
|
19383
19553
|
}
|
|
19384
19554
|
} else {
|
|
19385
19555
|
for (let i = 0; i < total; i++) {
|
|
19386
19556
|
if (matchesCandidate(c, i)) {
|
|
19387
|
-
|
|
19557
|
+
candIdx = i;
|
|
19388
19558
|
break;
|
|
19389
19559
|
}
|
|
19390
19560
|
}
|
|
19391
19561
|
}
|
|
19392
|
-
if (
|
|
19562
|
+
if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
|
|
19393
19563
|
}
|
|
19394
19564
|
if (idx !== -1) {
|
|
19395
19565
|
from = idx;
|
|
@@ -19441,7 +19611,7 @@ function resolveSections(sectionsObj, lines) {
|
|
|
19441
19611
|
}
|
|
19442
19612
|
function sectionText(sections, sectionId, fullScreen) {
|
|
19443
19613
|
if (!sectionId) return fullScreen;
|
|
19444
|
-
const found = sections.find((
|
|
19614
|
+
const found = sections.find((s2) => s2.id === sectionId);
|
|
19445
19615
|
return found ? found.text : "";
|
|
19446
19616
|
}
|
|
19447
19617
|
function isRegexCondition(c) {
|
|
@@ -19569,6 +19739,7 @@ function extractButtonsFromRule(rule, hay) {
|
|
|
19569
19739
|
const idx = Number(m[1]);
|
|
19570
19740
|
let label = String(m[2] ?? "").trim();
|
|
19571
19741
|
if (!Number.isFinite(idx) || idx <= 0 || !label) continue;
|
|
19742
|
+
const current = hasCursorMarker(lines[i]);
|
|
19572
19743
|
let j = i + 1;
|
|
19573
19744
|
while (j < lines.length) {
|
|
19574
19745
|
const next = lines[j];
|
|
@@ -19580,7 +19751,7 @@ function extractButtonsFromRule(rule, hay) {
|
|
|
19580
19751
|
}
|
|
19581
19752
|
if (buttons.some((b) => b.index === idx)) continue;
|
|
19582
19753
|
const key = keyTemplate.replace(/\{index\}/g, String(idx));
|
|
19583
|
-
buttons.push({ index: idx, label, key });
|
|
19754
|
+
buttons.push({ index: idx, label, key, current });
|
|
19584
19755
|
i = j - 1;
|
|
19585
19756
|
}
|
|
19586
19757
|
} else {
|
|
@@ -19592,12 +19763,15 @@ function extractButtonsFromRule(rule, hay) {
|
|
|
19592
19763
|
if (!Number.isFinite(idx) || idx <= 0 || !label) continue;
|
|
19593
19764
|
if (buttons.some((b) => b.index === idx)) continue;
|
|
19594
19765
|
const key = keyTemplate.replace(/\{index\}/g, String(idx));
|
|
19595
|
-
buttons.push({ index: idx, label, key });
|
|
19766
|
+
buttons.push({ index: idx, label, key, current: hasCursorMarker(m[0]) });
|
|
19596
19767
|
}
|
|
19597
19768
|
}
|
|
19598
19769
|
buttons.sort((a, b) => a.index - b.index);
|
|
19599
19770
|
return buttons;
|
|
19600
19771
|
}
|
|
19772
|
+
function hasCursorMarker(text) {
|
|
19773
|
+
return /^\s*[❯›>]/.test(text);
|
|
19774
|
+
}
|
|
19601
19775
|
var init_evaluator = __esm({
|
|
19602
19776
|
"src/providers/spec/evaluator.ts"() {
|
|
19603
19777
|
"use strict";
|
|
@@ -19609,10 +19783,10 @@ function isV4Spec(raw) {
|
|
|
19609
19783
|
return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
|
|
19610
19784
|
}
|
|
19611
19785
|
function initialState(spec) {
|
|
19612
|
-
return spec.states.find((
|
|
19786
|
+
return spec.states.find((s2) => s2.initial) ?? spec.states[0];
|
|
19613
19787
|
}
|
|
19614
19788
|
function stateById(spec, id) {
|
|
19615
|
-
return spec.states.find((
|
|
19789
|
+
return spec.states.find((s2) => s2.id === id);
|
|
19616
19790
|
}
|
|
19617
19791
|
function outgoingTransitions(spec, stateId) {
|
|
19618
19792
|
const matches = spec.transitions.filter((t) => {
|
|
@@ -19701,7 +19875,17 @@ function evalCond(cond, sections, fullScreen, cursor, prevLines, clock, legacyTr
|
|
|
19701
19875
|
const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
|
|
19702
19876
|
const kind = isRegex(cond) ? "regex" : "changed";
|
|
19703
19877
|
const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
|
|
19704
|
-
|
|
19878
|
+
let matchedText;
|
|
19879
|
+
if (result && isRegex(cond)) {
|
|
19880
|
+
try {
|
|
19881
|
+
const hay = sectionText(sections, cond.section, fullScreen);
|
|
19882
|
+
const re = new RegExp(cond.matches, cond.flags ?? "i");
|
|
19883
|
+
const m = re.exec(hay);
|
|
19884
|
+
if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
|
|
19885
|
+
} catch {
|
|
19886
|
+
}
|
|
19887
|
+
}
|
|
19888
|
+
return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
|
|
19705
19889
|
}
|
|
19706
19890
|
return { kind: "all", result: false, detail: "unknown condition" };
|
|
19707
19891
|
}
|
|
@@ -19817,17 +20001,17 @@ function validateFsmSpec(raw) {
|
|
|
19817
20001
|
}
|
|
19818
20002
|
const ids = /* @__PURE__ */ new Set();
|
|
19819
20003
|
let initialCount = 0;
|
|
19820
|
-
for (const [i,
|
|
19821
|
-
if (!
|
|
20004
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20005
|
+
if (!s2.id) {
|
|
19822
20006
|
errs.push(`states[${i}].id is required`);
|
|
19823
20007
|
continue;
|
|
19824
20008
|
}
|
|
19825
|
-
if (ids.has(
|
|
19826
|
-
ids.add(
|
|
19827
|
-
if (!
|
|
19828
|
-
if (
|
|
19829
|
-
if (
|
|
19830
|
-
errs.push(`states[${i}].status "${
|
|
20009
|
+
if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
|
|
20010
|
+
ids.add(s2.id);
|
|
20011
|
+
if (!s2.label) errs.push(`states[${i}].label is required`);
|
|
20012
|
+
if (s2.initial) initialCount += 1;
|
|
20013
|
+
if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
|
|
20014
|
+
errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
|
|
19831
20015
|
}
|
|
19832
20016
|
}
|
|
19833
20017
|
if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
|
|
@@ -19843,10 +20027,10 @@ function validateFsmSpec(raw) {
|
|
|
19843
20027
|
else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
|
|
19844
20028
|
if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
|
|
19845
20029
|
}
|
|
19846
|
-
for (const [i,
|
|
19847
|
-
const sec =
|
|
20030
|
+
for (const [i, s2] of spec.states.entries()) {
|
|
20031
|
+
const sec = s2.extract?.title?.section;
|
|
19848
20032
|
if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
|
|
19849
|
-
const bsec =
|
|
20033
|
+
const bsec = s2.extract?.buttons?.section;
|
|
19850
20034
|
if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
|
|
19851
20035
|
}
|
|
19852
20036
|
return errs;
|
|
@@ -32218,10 +32402,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32218
32402
|
const path42 = __require("path");
|
|
32219
32403
|
const { spawnSync: spawnSync2 } = __require("child_process");
|
|
32220
32404
|
const file = ext.loadExternalSources();
|
|
32221
|
-
if (file.sources.some((
|
|
32405
|
+
if (file.sources.some((s2) => s2.name === requestedName)) {
|
|
32222
32406
|
return { success: false, error: `source name "${requestedName}" is already registered` };
|
|
32223
32407
|
}
|
|
32224
|
-
if (file.sources.some((
|
|
32408
|
+
if (file.sources.some((s2) => s2.url === url && s2.ref === ref)) {
|
|
32225
32409
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
32226
32410
|
}
|
|
32227
32411
|
const sourceDir = path42.join(ext.externalRoot(), requestedName);
|
|
@@ -32283,7 +32467,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32283
32467
|
const fs32 = __require("fs");
|
|
32284
32468
|
const path42 = __require("path");
|
|
32285
32469
|
const file = ext.loadExternalSources();
|
|
32286
|
-
const match = file.sources.find((
|
|
32470
|
+
const match = file.sources.find((s2) => s2.name === name);
|
|
32287
32471
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
32288
32472
|
const sourceDir = path42.join(ext.externalRoot(), name);
|
|
32289
32473
|
if (fs32.existsSync(sourceDir)) {
|
|
@@ -32295,7 +32479,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32295
32479
|
}
|
|
32296
32480
|
ext.saveExternalSources({
|
|
32297
32481
|
schema: 1,
|
|
32298
|
-
sources: file.sources.filter((
|
|
32482
|
+
sources: file.sources.filter((s2) => s2.name !== name)
|
|
32299
32483
|
});
|
|
32300
32484
|
const active = ext.loadProvidersActive();
|
|
32301
32485
|
const filteredActive = {};
|
|
@@ -32319,10 +32503,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
32319
32503
|
const file = ext.loadExternalSources();
|
|
32320
32504
|
const inventory = ext.inventoryExternalSources();
|
|
32321
32505
|
const active = ext.loadProvidersActive();
|
|
32322
|
-
const sources = file.sources.map((
|
|
32323
|
-
const inv = inventory.find((e) => e.sourceName ===
|
|
32506
|
+
const sources = file.sources.map((s2) => {
|
|
32507
|
+
const inv = inventory.find((e) => e.sourceName === s2.name);
|
|
32324
32508
|
return {
|
|
32325
|
-
...
|
|
32509
|
+
...s2,
|
|
32326
32510
|
providers: inv?.providers ?? {}
|
|
32327
32511
|
};
|
|
32328
32512
|
});
|
|
@@ -32499,6 +32683,21 @@ import * as path21 from "path";
|
|
|
32499
32683
|
// src/providers/spec/adapter.ts
|
|
32500
32684
|
init_terminal_screen();
|
|
32501
32685
|
import { DEFAULT_SESSION_HOST_COLS as DEFAULT_SESSION_HOST_COLS5, DEFAULT_SESSION_HOST_ROWS as DEFAULT_SESSION_HOST_ROWS5 } from "@adhdev/session-host-core";
|
|
32686
|
+
var MAX_PTY_EVENTS = 300;
|
|
32687
|
+
var EVENT_CONTENT_CAP = 240;
|
|
32688
|
+
function escapeControl(text) {
|
|
32689
|
+
return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
|
|
32690
|
+
const code = ch.charCodeAt(0);
|
|
32691
|
+
if (ch === "\r") return "\\r";
|
|
32692
|
+
if (ch === "\n") return "\\n";
|
|
32693
|
+
if (ch === " ") return "\\t";
|
|
32694
|
+
if (code === 27) return "\\x1b";
|
|
32695
|
+
return "\\x" + code.toString(16).padStart(2, "0");
|
|
32696
|
+
});
|
|
32697
|
+
}
|
|
32698
|
+
function capPreview(text) {
|
|
32699
|
+
return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
|
|
32700
|
+
}
|
|
32502
32701
|
var TerminalAdapter = class {
|
|
32503
32702
|
constructor(opts, handlers) {
|
|
32504
32703
|
this.opts = opts;
|
|
@@ -32525,6 +32724,9 @@ var TerminalAdapter = class {
|
|
|
32525
32724
|
screenTimer = null;
|
|
32526
32725
|
tickTimer = null;
|
|
32527
32726
|
lastScreen = "";
|
|
32727
|
+
/** Debug-only ring buffer of PTY input/output/resize/cursor events. */
|
|
32728
|
+
events = [];
|
|
32729
|
+
lastCursorKey = "";
|
|
32528
32730
|
start() {
|
|
32529
32731
|
const env = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
|
|
32530
32732
|
this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
|
|
@@ -32533,10 +32735,12 @@ var TerminalAdapter = class {
|
|
|
32533
32735
|
cols: this.cols,
|
|
32534
32736
|
rows: this.rows
|
|
32535
32737
|
});
|
|
32738
|
+
this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
|
|
32536
32739
|
this.handlers.init?.({ pid: this.pty.pid });
|
|
32537
32740
|
this.pty.onData((chunk) => this.onChunk(chunk));
|
|
32538
32741
|
this.pty.onExit((info) => {
|
|
32539
32742
|
this.stopTimers();
|
|
32743
|
+
this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
|
|
32540
32744
|
this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
|
|
32541
32745
|
this.pty = null;
|
|
32542
32746
|
});
|
|
@@ -32547,6 +32751,7 @@ var TerminalAdapter = class {
|
|
|
32547
32751
|
resize(cols, rows) {
|
|
32548
32752
|
this.cols = cols;
|
|
32549
32753
|
this.rows = rows;
|
|
32754
|
+
this.recordEvent("resize", `${cols}x${rows}`);
|
|
32550
32755
|
this.pty?.resize(cols, rows);
|
|
32551
32756
|
this.screen.resize(rows, cols);
|
|
32552
32757
|
}
|
|
@@ -32567,8 +32772,21 @@ var TerminalAdapter = class {
|
|
|
32567
32772
|
return { row: pos.row, col: pos.col };
|
|
32568
32773
|
}
|
|
32569
32774
|
send_keys(text) {
|
|
32775
|
+
this.recordEvent("input", capPreview(escapeControl(text)), text.length);
|
|
32570
32776
|
this.pty?.write(text);
|
|
32571
32777
|
}
|
|
32778
|
+
/** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
|
|
32779
|
+
* first. Pure observation — never consulted by the FSM. */
|
|
32780
|
+
getEventTimeline(limit = MAX_PTY_EVENTS) {
|
|
32781
|
+
const n = Math.max(0, Math.min(limit, this.events.length));
|
|
32782
|
+
return this.events.slice(this.events.length - n);
|
|
32783
|
+
}
|
|
32784
|
+
recordEvent(kind, content, bytes) {
|
|
32785
|
+
const ev = { ts: Date.now(), kind, content };
|
|
32786
|
+
if (typeof bytes === "number") ev.bytes = bytes;
|
|
32787
|
+
this.events.push(ev);
|
|
32788
|
+
if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
|
|
32789
|
+
}
|
|
32572
32790
|
kill() {
|
|
32573
32791
|
this.stopTimers();
|
|
32574
32792
|
try {
|
|
@@ -32579,6 +32797,7 @@ var TerminalAdapter = class {
|
|
|
32579
32797
|
this.screen.dispose();
|
|
32580
32798
|
}
|
|
32581
32799
|
onChunk(chunk) {
|
|
32800
|
+
this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
|
|
32582
32801
|
try {
|
|
32583
32802
|
this.handlers.on_pty_data?.(chunk);
|
|
32584
32803
|
} catch {
|
|
@@ -32588,6 +32807,12 @@ var TerminalAdapter = class {
|
|
|
32588
32807
|
this.screenTimer = setTimeout(() => {
|
|
32589
32808
|
this.screenTimer = null;
|
|
32590
32809
|
const snap = this.computeScreen();
|
|
32810
|
+
const cur = this.screen.getCursorPosition();
|
|
32811
|
+
const curKey = `${cur.row},${cur.col}`;
|
|
32812
|
+
if (curKey !== this.lastCursorKey) {
|
|
32813
|
+
this.lastCursorKey = curKey;
|
|
32814
|
+
this.recordEvent("cursor", `(${cur.row},${cur.col})`);
|
|
32815
|
+
}
|
|
32591
32816
|
if (snap === this.lastScreen) return;
|
|
32592
32817
|
this.lastScreen = snap;
|
|
32593
32818
|
try {
|
|
@@ -32672,20 +32897,40 @@ function applyPreLaunchTrust(trust, workingDir) {
|
|
|
32672
32897
|
|
|
32673
32898
|
// src/providers/spec/fsm-driver.ts
|
|
32674
32899
|
init_logger();
|
|
32675
|
-
function countNewlines(
|
|
32900
|
+
function countNewlines(s2) {
|
|
32676
32901
|
let n = 0;
|
|
32677
|
-
for (let i = 0; i <
|
|
32902
|
+
for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
|
|
32678
32903
|
return n;
|
|
32679
32904
|
}
|
|
32680
32905
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
32681
32906
|
var WIN32_SUBMIT_RESEND_GAP_MS = 350;
|
|
32682
32907
|
var WIN32_SUBMIT_MAX_RESENDS = 14;
|
|
32908
|
+
var WIN32_SUBMIT_SETTLE_MS = 500;
|
|
32909
|
+
var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
|
|
32910
|
+
var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
|
|
32911
|
+
var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
|
|
32912
|
+
var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
|
|
32683
32913
|
function resolveSubmitDelayMs(specBeforeSubmit, text) {
|
|
32684
32914
|
const lines = countNewlines(text);
|
|
32685
32915
|
const linesBonus = Math.min(800, lines * 80);
|
|
32686
32916
|
const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
|
|
32687
32917
|
return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
|
|
32688
32918
|
}
|
|
32919
|
+
function chunkPreservingSurrogates(text, size) {
|
|
32920
|
+
const chunks = [];
|
|
32921
|
+
let offset = 0;
|
|
32922
|
+
while (offset < text.length) {
|
|
32923
|
+
let end = Math.min(text.length, offset + size);
|
|
32924
|
+
if (end < text.length) {
|
|
32925
|
+
const code = text.charCodeAt(end - 1);
|
|
32926
|
+
if (code >= 55296 && code <= 56319) end -= 1;
|
|
32927
|
+
}
|
|
32928
|
+
if (end <= offset) end = Math.min(text.length, offset + size);
|
|
32929
|
+
chunks.push(text.slice(offset, end));
|
|
32930
|
+
offset = end;
|
|
32931
|
+
}
|
|
32932
|
+
return chunks;
|
|
32933
|
+
}
|
|
32689
32934
|
function guessExt(mime) {
|
|
32690
32935
|
if (/png/i.test(mime)) return ".png";
|
|
32691
32936
|
if (/jpe?g/i.test(mime)) return ".jpg";
|
|
@@ -32701,7 +32946,10 @@ var FsmDriver = class {
|
|
|
32701
32946
|
this.buildAdapterOpts(),
|
|
32702
32947
|
{
|
|
32703
32948
|
init: () => this.emitInitialState(),
|
|
32704
|
-
on_pty_data: (chunk) =>
|
|
32949
|
+
on_pty_data: (chunk) => {
|
|
32950
|
+
this.lastPtyDataAt = Date.now();
|
|
32951
|
+
this.emit({ kind: "pty_data", chunk });
|
|
32952
|
+
},
|
|
32705
32953
|
on_screen_changed: () => this.reevaluate(),
|
|
32706
32954
|
on_exit: ({ exitCode }) => this.handleExit(exitCode)
|
|
32707
32955
|
}
|
|
@@ -32735,6 +32983,16 @@ var FsmDriver = class {
|
|
|
32735
32983
|
* WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
|
|
32736
32984
|
* leaves idle (submitted) or the resend budget is spent. */
|
|
32737
32985
|
win32SubmitTimer = null;
|
|
32986
|
+
/** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
|
|
32987
|
+
* on_pty_data — including the echo of text written into the composer — so the
|
|
32988
|
+
* win32 submit settle-gate can tell when input has finished landing. */
|
|
32989
|
+
lastPtyDataAt = 0;
|
|
32990
|
+
/** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
|
|
32991
|
+
* the gap between writing a chunk and its echo so the settle-gate does not
|
|
32992
|
+
* declare "quiet" mid-write. */
|
|
32993
|
+
lastWin32WriteAt = 0;
|
|
32994
|
+
/** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
|
|
32995
|
+
win32WriteTimer = null;
|
|
32738
32996
|
currentEval = null;
|
|
32739
32997
|
stateHistory = [];
|
|
32740
32998
|
prevStateAt = 0;
|
|
@@ -32855,6 +33113,10 @@ var FsmDriver = class {
|
|
|
32855
33113
|
clearTimeout(this.win32SubmitTimer);
|
|
32856
33114
|
this.win32SubmitTimer = null;
|
|
32857
33115
|
}
|
|
33116
|
+
if (this.win32WriteTimer) {
|
|
33117
|
+
clearTimeout(this.win32WriteTimer);
|
|
33118
|
+
this.win32WriteTimer = null;
|
|
33119
|
+
}
|
|
32858
33120
|
this.specWatcher?.close();
|
|
32859
33121
|
this.adapter.kill();
|
|
32860
33122
|
}
|
|
@@ -32885,11 +33147,15 @@ var FsmDriver = class {
|
|
|
32885
33147
|
getFsmSnapshotHistory() {
|
|
32886
33148
|
return this.fsmSnapshotHistory;
|
|
32887
33149
|
}
|
|
33150
|
+
/** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
|
|
33151
|
+
getEventTimeline(limit) {
|
|
33152
|
+
return this.adapter.getEventTimeline(limit);
|
|
33153
|
+
}
|
|
32888
33154
|
getSections() {
|
|
32889
33155
|
try {
|
|
32890
33156
|
const screen = this.adapter.snapshot();
|
|
32891
33157
|
const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
32892
|
-
return resolveSections(this.spec.sections ?? {}, lines).map((
|
|
33158
|
+
return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
|
|
32893
33159
|
} catch {
|
|
32894
33160
|
return null;
|
|
32895
33161
|
}
|
|
@@ -33267,7 +33533,7 @@ var FsmDriver = class {
|
|
|
33267
33533
|
const perChar = sm.delay_ms_per_char ?? 0;
|
|
33268
33534
|
const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
|
|
33269
33535
|
if (process.platform === "win32") {
|
|
33270
|
-
this.
|
|
33536
|
+
this.writeWin32Body(text);
|
|
33271
33537
|
this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
|
|
33272
33538
|
return;
|
|
33273
33539
|
}
|
|
@@ -33293,20 +33559,72 @@ var FsmDriver = class {
|
|
|
33293
33559
|
const st = stateById(this.spec, this.currentStateId);
|
|
33294
33560
|
return st ? statusForState(st) : "idle";
|
|
33295
33561
|
}
|
|
33562
|
+
/** Record a win32 body write so the settle-gate counts it as input activity
|
|
33563
|
+
* even before the echo arrives. */
|
|
33564
|
+
markWin32Write() {
|
|
33565
|
+
this.lastWin32WriteAt = Date.now();
|
|
33566
|
+
}
|
|
33567
|
+
/** Most recent win32 input activity — a write we issued OR a PTY output chunk
|
|
33568
|
+
* (echo). The submit settle-gate waits for this to go quiet. */
|
|
33569
|
+
lastWin32InputActivityAt() {
|
|
33570
|
+
return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
|
|
33571
|
+
}
|
|
33296
33572
|
/**
|
|
33297
|
-
*
|
|
33298
|
-
*
|
|
33299
|
-
* a
|
|
33300
|
-
*
|
|
33301
|
-
*
|
|
33302
|
-
*
|
|
33303
|
-
|
|
33573
|
+
* Write the message body to the PTY for win32, paced into bounded chunks. A
|
|
33574
|
+
* single unbounded ConPTY write can overflow the input pipe and drop leading
|
|
33575
|
+
* bytes; splitting it with a short inter-chunk gap keeps the console input
|
|
33576
|
+
* buffer from overflowing. Small bodies still go out in a single write. Each
|
|
33577
|
+
* chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
|
|
33578
|
+
* the final chunk is out and echoed.
|
|
33579
|
+
*/
|
|
33580
|
+
writeWin32Body(text) {
|
|
33581
|
+
if (this.win32WriteTimer) {
|
|
33582
|
+
clearTimeout(this.win32WriteTimer);
|
|
33583
|
+
this.win32WriteTimer = null;
|
|
33584
|
+
}
|
|
33585
|
+
if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
|
|
33586
|
+
this.markWin32Write();
|
|
33587
|
+
this.adapter.send_keys(text);
|
|
33588
|
+
return;
|
|
33589
|
+
}
|
|
33590
|
+
const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
|
|
33591
|
+
let idx = 0;
|
|
33592
|
+
const writeNext = () => {
|
|
33593
|
+
this.win32WriteTimer = null;
|
|
33594
|
+
if (idx >= chunks.length) return;
|
|
33595
|
+
this.markWin32Write();
|
|
33596
|
+
this.adapter.send_keys(chunks[idx]);
|
|
33597
|
+
idx += 1;
|
|
33598
|
+
if (idx < chunks.length) {
|
|
33599
|
+
this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
|
|
33600
|
+
}
|
|
33601
|
+
};
|
|
33602
|
+
writeNext();
|
|
33603
|
+
}
|
|
33604
|
+
/**
|
|
33605
|
+
* win32 submit. Two phases:
|
|
33606
|
+
*
|
|
33607
|
+
* Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
|
|
33608
|
+
* for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
|
|
33609
|
+
* (possibly multi-KB / multiline) body has finished arriving in the composer
|
|
33610
|
+
* and echoing. Honors an initial minimum delay and is bounded by
|
|
33611
|
+
* WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
|
|
33612
|
+
* This is what stops a long message from being submitted half-arrived (its
|
|
33613
|
+
* leading lines lost). A short message settles almost immediately.
|
|
33614
|
+
*
|
|
33615
|
+
* Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
|
|
33616
|
+
* if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
|
|
33617
|
+
* newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
|
|
33618
|
+
* (a stale/edge status never suppresses it); resends are gated on still being
|
|
33619
|
+
* idle and stop the instant the agent leaves idle (submitted → generating /
|
|
33620
|
+
* approval). This preserves the win32 lone-CR-swallow handling.
|
|
33304
33621
|
*/
|
|
33305
33622
|
scheduleWin32Submit(submitKey, initialDelayMs) {
|
|
33306
33623
|
if (this.win32SubmitTimer) {
|
|
33307
33624
|
clearTimeout(this.win32SubmitTimer);
|
|
33308
33625
|
this.win32SubmitTimer = null;
|
|
33309
33626
|
}
|
|
33627
|
+
const startedAt = Date.now();
|
|
33310
33628
|
const fire = (attempt) => {
|
|
33311
33629
|
this.win32SubmitTimer = null;
|
|
33312
33630
|
this.adapter.send_keys(submitKey);
|
|
@@ -33319,8 +33637,20 @@ var FsmDriver = class {
|
|
|
33319
33637
|
fire(attempt + 1);
|
|
33320
33638
|
}, WIN32_SUBMIT_RESEND_GAP_MS);
|
|
33321
33639
|
};
|
|
33322
|
-
|
|
33323
|
-
|
|
33640
|
+
const waitForSettle = () => {
|
|
33641
|
+
this.win32SubmitTimer = null;
|
|
33642
|
+
const now = Date.now();
|
|
33643
|
+
const quietFor = now - this.lastWin32InputActivityAt();
|
|
33644
|
+
const waited = now - startedAt;
|
|
33645
|
+
if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
|
|
33646
|
+
fire(0);
|
|
33647
|
+
return;
|
|
33648
|
+
}
|
|
33649
|
+
const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
|
|
33650
|
+
this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
|
|
33651
|
+
};
|
|
33652
|
+
if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
|
|
33653
|
+
else waitForSettle();
|
|
33324
33654
|
}
|
|
33325
33655
|
handleClickControl(controlId, payload) {
|
|
33326
33656
|
const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
|
|
@@ -33355,6 +33685,19 @@ var FsmDriver = class {
|
|
|
33355
33685
|
if (!m) return;
|
|
33356
33686
|
const btn = m.buttons.find((b) => b.index === index);
|
|
33357
33687
|
if (!btn) return;
|
|
33688
|
+
const rule = stateById(this.spec, this.currentStateId)?.extract?.buttons;
|
|
33689
|
+
if (rule?.select_mode === "arrow_keys") {
|
|
33690
|
+
const from = m.buttons.find((b) => b.current)?.index ?? 1;
|
|
33691
|
+
const up = rule.cursor_keys?.up ?? "\x1B[A";
|
|
33692
|
+
const down = rule.cursor_keys?.down ?? "\x1B[B";
|
|
33693
|
+
const delta = btn.index - from;
|
|
33694
|
+
const step = delta >= 0 ? down : up;
|
|
33695
|
+
const nav = step.repeat(Math.abs(delta));
|
|
33696
|
+
const confirm = (rule.key_for_index || "\r").replace(/\{index\}/g, "") || "\r";
|
|
33697
|
+
if (nav) this.adapter.send_keys(nav);
|
|
33698
|
+
this.adapter.send_keys(confirm);
|
|
33699
|
+
return;
|
|
33700
|
+
}
|
|
33358
33701
|
this.adapter.send_keys(btn.key);
|
|
33359
33702
|
}
|
|
33360
33703
|
handleAttachImage(blob, mime) {
|
|
@@ -33433,7 +33776,8 @@ function summarizeTransition(t) {
|
|
|
33433
33776
|
return out;
|
|
33434
33777
|
}
|
|
33435
33778
|
function flattenCond(c, out, depth) {
|
|
33436
|
-
|
|
33779
|
+
const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
|
|
33780
|
+
out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
|
|
33437
33781
|
for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
|
|
33438
33782
|
}
|
|
33439
33783
|
function findStable(c) {
|
|
@@ -34151,8 +34495,8 @@ function projectToolBlock(block2, role, tmap) {
|
|
|
34151
34495
|
}
|
|
34152
34496
|
return null;
|
|
34153
34497
|
}
|
|
34154
|
-
function oneLine(
|
|
34155
|
-
const flat =
|
|
34498
|
+
function oneLine(s2, max) {
|
|
34499
|
+
const flat = s2.replace(/\s+/g, " ").trim();
|
|
34156
34500
|
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
34157
34501
|
}
|
|
34158
34502
|
function parseTimestamp(v) {
|
|
@@ -34172,10 +34516,10 @@ function parseTimestamp(v) {
|
|
|
34172
34516
|
return null;
|
|
34173
34517
|
}
|
|
34174
34518
|
function normalizeRole(r) {
|
|
34175
|
-
const
|
|
34176
|
-
if (
|
|
34177
|
-
if (
|
|
34178
|
-
if (
|
|
34519
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
34520
|
+
if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
|
|
34521
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
34522
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
34179
34523
|
return "system";
|
|
34180
34524
|
}
|
|
34181
34525
|
function stringifyContent(v) {
|
|
@@ -34223,18 +34567,18 @@ function compileWhere(src) {
|
|
|
34223
34567
|
return (record) => ors.some((ands) => ands.every((t) => evalTerm(t, record)));
|
|
34224
34568
|
}
|
|
34225
34569
|
function parseTerm(src) {
|
|
34226
|
-
let
|
|
34570
|
+
let s2 = src.trim();
|
|
34227
34571
|
let negate = false;
|
|
34228
|
-
if (
|
|
34572
|
+
if (s2.startsWith("!")) {
|
|
34229
34573
|
negate = true;
|
|
34230
|
-
|
|
34574
|
+
s2 = s2.slice(1).trim();
|
|
34231
34575
|
}
|
|
34232
|
-
const fnMatch =
|
|
34576
|
+
const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
|
|
34233
34577
|
if (fnMatch) {
|
|
34234
34578
|
const [, op2, pathExpr, litExpr] = fnMatch;
|
|
34235
34579
|
return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
|
|
34236
34580
|
}
|
|
34237
|
-
const opMatch =
|
|
34581
|
+
const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
|
|
34238
34582
|
if (!opMatch) return null;
|
|
34239
34583
|
const [, lhs, op, rhsRaw] = opMatch;
|
|
34240
34584
|
return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
|
|
@@ -34591,9 +34935,12 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34591
34935
|
* — not this code — decides how a selection is keyed for each CLI.
|
|
34592
34936
|
*/
|
|
34593
34937
|
async selectPickerChoice(ctl, action, choiceIndex, choiceLabel) {
|
|
34594
|
-
|
|
34595
|
-
|
|
34596
|
-
|
|
34938
|
+
let options = this.extractPickerChoicesIfRendered(action);
|
|
34939
|
+
if (!options) {
|
|
34940
|
+
this.driver.dispatch({ kind: "click_control", control_id: ctl.id });
|
|
34941
|
+
await this.waitForPickerRendered(action);
|
|
34942
|
+
options = this.extractPickerChoices(action);
|
|
34943
|
+
}
|
|
34597
34944
|
let index = choiceIndex;
|
|
34598
34945
|
if ((index == null || !Number.isFinite(index)) && choiceLabel) {
|
|
34599
34946
|
const needle = choiceLabel.trim().toLowerCase();
|
|
@@ -34606,8 +34953,27 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34606
34953
|
if (index == null || !Number.isFinite(index)) {
|
|
34607
34954
|
return { ok: false, error: "choiceIndex or choiceLabel required to select" };
|
|
34608
34955
|
}
|
|
34609
|
-
|
|
34610
|
-
|
|
34956
|
+
if (action.select_mode === "arrow_keys") {
|
|
34957
|
+
const current = options.find((o) => o.current);
|
|
34958
|
+
if (current == null) {
|
|
34959
|
+
return {
|
|
34960
|
+
ok: false,
|
|
34961
|
+
error: "arrow-nav picker: current cursor row not detected on screen",
|
|
34962
|
+
controlResult: { options: options.map((o) => ({ value: o.label, label: o.label, current: o.current })) }
|
|
34963
|
+
};
|
|
34964
|
+
}
|
|
34965
|
+
const up = action.cursor_keys?.up ?? "\x1B[A";
|
|
34966
|
+
const down = action.cursor_keys?.down ?? "\x1B[B";
|
|
34967
|
+
const delta = index - current.index;
|
|
34968
|
+
const step = delta >= 0 ? down : up;
|
|
34969
|
+
const nav = step.repeat(Math.abs(delta));
|
|
34970
|
+
const confirm = (action.submit_key || "\r").replace(/\{index\}/g, "") || "\r";
|
|
34971
|
+
if (nav) this.driver.dispatch({ kind: "pty_write", data: nav });
|
|
34972
|
+
this.driver.dispatch({ kind: "pty_write", data: confirm });
|
|
34973
|
+
} else {
|
|
34974
|
+
const keys = (action.submit_key || "{index}\r").replace(/\{index\}/g, String(index));
|
|
34975
|
+
this.driver.dispatch({ kind: "pty_write", data: keys });
|
|
34976
|
+
}
|
|
34611
34977
|
const selected = options.find((o) => o.index === index);
|
|
34612
34978
|
return {
|
|
34613
34979
|
ok: true,
|
|
@@ -34619,6 +34985,20 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34619
34985
|
}
|
|
34620
34986
|
};
|
|
34621
34987
|
}
|
|
34988
|
+
/** Parse the picker choices only if the picker already appears rendered on
|
|
34989
|
+
* the live screen (its `wait_for` condition currently matches and at least
|
|
34990
|
+
* one choice parses). Returns the parsed choices when open, else null so
|
|
34991
|
+
* the caller knows it must send the trigger to open it. Used to de-dup the
|
|
34992
|
+
* picker open in {@link selectPickerChoice}. */
|
|
34993
|
+
extractPickerChoicesIfRendered(action) {
|
|
34994
|
+
const wf = action.wait_for;
|
|
34995
|
+
if (wf?.regex) {
|
|
34996
|
+
const re = new RegExp(wf.regex, wf.flags ?? "i");
|
|
34997
|
+
if (!re.test(this.readScreenSectionText(wf.section))) return null;
|
|
34998
|
+
}
|
|
34999
|
+
const options = this.extractPickerChoices(action);
|
|
35000
|
+
return options.length > 0 ? options : null;
|
|
35001
|
+
}
|
|
34622
35002
|
/** Poll the live screen until the picker's `wait_for` condition matches,
|
|
34623
35003
|
* up to a short budget. Returns true if it rendered, false on timeout. */
|
|
34624
35004
|
async waitForPickerRendered(action) {
|
|
@@ -34666,7 +35046,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34666
35046
|
try {
|
|
34667
35047
|
const sections = this.driver.getSections();
|
|
34668
35048
|
if (sectionId && sections) {
|
|
34669
|
-
const hit = sections.find((
|
|
35049
|
+
const hit = sections.find((s2) => s2.id === sectionId);
|
|
34670
35050
|
if (hit) return hit.text;
|
|
34671
35051
|
}
|
|
34672
35052
|
return this.driver.getScreen();
|
|
@@ -34681,7 +35061,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34681
35061
|
screen = this.driver.snapshot();
|
|
34682
35062
|
const driverSections = this.driver.getSections?.();
|
|
34683
35063
|
if (driverSections) {
|
|
34684
|
-
sections = Object.fromEntries(driverSections.map((
|
|
35064
|
+
sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
|
|
34685
35065
|
} else {
|
|
34686
35066
|
sections = this.readCurrentScreenSections(screen);
|
|
34687
35067
|
}
|
|
@@ -34727,6 +35107,10 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
34727
35107
|
// answers "why did this rule fire" after the fact, unlike the live
|
|
34728
35108
|
// `fsm` field which only reflects the current instant.
|
|
34729
35109
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35110
|
+
// PTY input/output/resize/cursor event timeline (debug-only) so the
|
|
35111
|
+
// snapshot shows what we typed / what the PTY printed around each
|
|
35112
|
+
// status transition. Null for drivers without the timeline.
|
|
35113
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
34730
35114
|
// Extended fields
|
|
34731
35115
|
name: this.cliName,
|
|
34732
35116
|
status: this.getStatus().status,
|
|
@@ -35091,6 +35475,8 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
35091
35475
|
// v4 FSM transition snapshot history — the captured pre-transition
|
|
35092
35476
|
// evaluation table at each transition (null for v3 specs).
|
|
35093
35477
|
fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
|
|
35478
|
+
// PTY input/output/resize/cursor event timeline (debug-only).
|
|
35479
|
+
eventTimeline: this.driver.getEventTimeline?.() ?? null,
|
|
35094
35480
|
messages,
|
|
35095
35481
|
committedMessages: messages
|
|
35096
35482
|
};
|
|
@@ -35135,6 +35521,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
|
|
|
35135
35521
|
|
|
35136
35522
|
// src/providers/cli-provider-instance.ts
|
|
35137
35523
|
init_logger();
|
|
35524
|
+
init_mesh_event_trace();
|
|
35138
35525
|
init_control_effects();
|
|
35139
35526
|
init_approval_utils();
|
|
35140
35527
|
init_provider_patch_state();
|
|
@@ -36186,6 +36573,23 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36186
36573
|
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
36187
36574
|
this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
|
|
36188
36575
|
}
|
|
36576
|
+
// EVTTRACE (observation-only): is this a mesh worker session whose completion
|
|
36577
|
+
// events must route to a coordinator? Used purely to gate trace logging so a
|
|
36578
|
+
// non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
|
|
36579
|
+
isMeshWorkerSession() {
|
|
36580
|
+
return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
|
|
36581
|
+
}
|
|
36582
|
+
// EVTTRACE correlation context for this session's completion lifecycle. taskId is
|
|
36583
|
+
// the primary grep anchor; instanceId is the session fallback.
|
|
36584
|
+
meshTraceCtx(event = "agent:generating_completed") {
|
|
36585
|
+
return {
|
|
36586
|
+
taskId: this.settings.meshActiveTaskId,
|
|
36587
|
+
sessionId: this.instanceId,
|
|
36588
|
+
nodeId: this.settings.meshNodeId,
|
|
36589
|
+
meshId: this.settings.meshNodeFor,
|
|
36590
|
+
event
|
|
36591
|
+
};
|
|
36592
|
+
}
|
|
36189
36593
|
flushCompletedDebounceIfFinalized() {
|
|
36190
36594
|
const pending = this.completedDebouncePending;
|
|
36191
36595
|
if (!pending) {
|
|
@@ -36206,24 +36610,33 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36206
36610
|
if (block2) {
|
|
36207
36611
|
const blockReason = block2.reason;
|
|
36208
36612
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
36209
|
-
|
|
36210
|
-
|
|
36613
|
+
const isTranscriptEvidenceGate = block2.allowTimeout === true;
|
|
36614
|
+
LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
36615
|
+
if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
|
|
36211
36616
|
if (pending.loggedBlockReason !== blockReason) {
|
|
36212
36617
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
36618
|
+
if (this.isMeshWorkerSession()) {
|
|
36619
|
+
traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
|
|
36620
|
+
}
|
|
36213
36621
|
pending.loggedBlockReason = blockReason;
|
|
36214
36622
|
}
|
|
36215
36623
|
this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
|
|
36216
36624
|
return;
|
|
36217
36625
|
}
|
|
36626
|
+
const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
|
|
36218
36627
|
const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
|
|
36219
36628
|
blockReason,
|
|
36220
36629
|
latestStatus,
|
|
36221
36630
|
latestVisibleStatus,
|
|
36222
36631
|
waitedMs,
|
|
36223
36632
|
pending,
|
|
36224
|
-
emittedAfterFinalizationTimeout
|
|
36633
|
+
emittedAfterFinalizationTimeout
|
|
36225
36634
|
});
|
|
36226
|
-
|
|
36635
|
+
completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
|
|
36636
|
+
LOG.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
|
|
36637
|
+
if (this.isMeshWorkerSession()) {
|
|
36638
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
|
|
36639
|
+
}
|
|
36227
36640
|
this.pushEvent({
|
|
36228
36641
|
event: "agent:generating_completed",
|
|
36229
36642
|
chatTitle: pending.chatTitle,
|
|
@@ -36246,6 +36659,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36246
36659
|
return;
|
|
36247
36660
|
}
|
|
36248
36661
|
LOG.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
|
|
36662
|
+
if (this.isMeshWorkerSession()) {
|
|
36663
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
|
|
36664
|
+
}
|
|
36249
36665
|
this.pushEvent({
|
|
36250
36666
|
event: "agent:generating_completed",
|
|
36251
36667
|
chatTitle: pending.chatTitle,
|
|
@@ -36484,6 +36900,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36484
36900
|
if (missingEvidence && !hasMeshContext) {
|
|
36485
36901
|
LOG.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
|
|
36486
36902
|
} else {
|
|
36903
|
+
if (this.isMeshWorkerSession()) {
|
|
36904
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
|
|
36905
|
+
}
|
|
36487
36906
|
this.pushEvent({
|
|
36488
36907
|
event: "agent:generating_completed",
|
|
36489
36908
|
chatTitle,
|
|
@@ -36560,6 +36979,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36560
36979
|
const monitorParsedStatus = parsedStatus;
|
|
36561
36980
|
for (const me of monitorEvents) {
|
|
36562
36981
|
if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
|
|
36982
|
+
if (this.isMeshWorkerSession()) {
|
|
36983
|
+
traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
|
|
36984
|
+
}
|
|
36563
36985
|
this.pushEvent({
|
|
36564
36986
|
event: "agent:generating_completed",
|
|
36565
36987
|
chatTitle,
|
|
@@ -36600,6 +37022,12 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
36600
37022
|
workspace: typeof event.workspace === "string" && event.workspace.trim() ? event.workspace : this.workingDir,
|
|
36601
37023
|
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
36602
37024
|
};
|
|
37025
|
+
if (this.isMeshWorkerSession() && this.settings.meshActiveTaskId) {
|
|
37026
|
+
const existingTaskId = typeof enrichedEvent.taskId === "string" && enrichedEvent.taskId.trim() ? enrichedEvent.taskId : void 0;
|
|
37027
|
+
if (!existingTaskId) {
|
|
37028
|
+
enrichedEvent.taskId = this.settings.meshActiveTaskId;
|
|
37029
|
+
}
|
|
37030
|
+
}
|
|
36603
37031
|
if (this.context?.emitProviderEvent) {
|
|
36604
37032
|
this.context.emitProviderEvent(enrichedEvent);
|
|
36605
37033
|
} else {
|
|
@@ -40428,7 +40856,7 @@ function parsePbFile(filePath, sessionId) {
|
|
|
40428
40856
|
}
|
|
40429
40857
|
if (buf.length === 0) return null;
|
|
40430
40858
|
const strings = extractStringsFromBuffer(buf);
|
|
40431
|
-
const meaningful = strings.filter((
|
|
40859
|
+
const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
|
|
40432
40860
|
if (meaningful.length === 0) return null;
|
|
40433
40861
|
const content = meaningful.join("\n");
|
|
40434
40862
|
const sourceMtimeMs = statMtimeMs3(filePath);
|
|
@@ -40636,10 +41064,10 @@ function readSession4(sessionPath) {
|
|
|
40636
41064
|
};
|
|
40637
41065
|
}
|
|
40638
41066
|
function normalizeHermesRole(r) {
|
|
40639
|
-
const
|
|
40640
|
-
if (
|
|
40641
|
-
if (
|
|
40642
|
-
if (
|
|
41067
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41068
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41069
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41070
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
40643
41071
|
return "system";
|
|
40644
41072
|
}
|
|
40645
41073
|
|
|
@@ -40865,10 +41293,10 @@ function safeMtime(p) {
|
|
|
40865
41293
|
}
|
|
40866
41294
|
}
|
|
40867
41295
|
function normalizeRole2(r) {
|
|
40868
|
-
const
|
|
40869
|
-
if (
|
|
40870
|
-
if (
|
|
40871
|
-
if (
|
|
41296
|
+
const s2 = String(r ?? "").toLowerCase();
|
|
41297
|
+
if (s2 === "user" || s2 === "human") return "user";
|
|
41298
|
+
if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
|
|
41299
|
+
if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
|
|
40872
41300
|
return "system";
|
|
40873
41301
|
}
|
|
40874
41302
|
|
|
@@ -40888,7 +41316,7 @@ function synthesizeControlsFromControlBar(specControls) {
|
|
|
40888
41316
|
const actionType = ctl?.action?.type;
|
|
40889
41317
|
if (!id || !actionType) return;
|
|
40890
41318
|
const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
|
|
40891
|
-
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((
|
|
41319
|
+
const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
|
|
40892
41320
|
if (actionType === "open_picker") {
|
|
40893
41321
|
out.push({
|
|
40894
41322
|
id,
|
|
@@ -47804,7 +48232,7 @@ var DaemonCommandRouter = class {
|
|
|
47804
48232
|
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.";
|
|
47805
48233
|
if (!firstFailedCmd) return base;
|
|
47806
48234
|
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 : "";
|
|
47807
|
-
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((
|
|
48235
|
+
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|
|
47808
48236
|
const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
|
|
47809
48237
|
return [
|
|
47810
48238
|
base,
|
|
@@ -48555,7 +48983,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
48555
48983
|
convergence = "blocked_review";
|
|
48556
48984
|
}
|
|
48557
48985
|
const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
|
|
48558
|
-
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((
|
|
48986
|
+
const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
|
|
48559
48987
|
results.push({
|
|
48560
48988
|
nodeId: node.id,
|
|
48561
48989
|
workspace: node.workspace,
|
|
@@ -49552,7 +49980,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
49552
49980
|
return {
|
|
49553
49981
|
success: true,
|
|
49554
49982
|
screenLineCount: lines.length,
|
|
49555
|
-
sections: resolved.map((
|
|
49983
|
+
sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
|
|
49556
49984
|
};
|
|
49557
49985
|
} catch (e) {
|
|
49558
49986
|
return { success: false, error: `resolve failed: ${e.message}` };
|
|
@@ -50121,7 +50549,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50121
50549
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
50122
50550
|
try {
|
|
50123
50551
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
50124
|
-
const status = Array.isArray(args?.status) ? args.status.map((
|
|
50552
|
+
const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
|
|
50125
50553
|
const rawQueue = getQueue2(meshId, { status });
|
|
50126
50554
|
const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
|
|
50127
50555
|
const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
|
|
@@ -50402,7 +50830,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50402
50830
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50403
50831
|
}
|
|
50404
50832
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50405
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
50833
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50406
50834
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50407
50835
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
50408
50836
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50436,7 +50864,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50436
50864
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50437
50865
|
}
|
|
50438
50866
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50439
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
50867
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50440
50868
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50441
50869
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
50442
50870
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50484,7 +50912,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50484
50912
|
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
50485
50913
|
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
50486
50914
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
50487
|
-
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId
|
|
50915
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
50488
50916
|
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50489
50917
|
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
50490
50918
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
@@ -50571,7 +50999,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50571
50999
|
let worktreeCleanup;
|
|
50572
51000
|
if (node?.isLocalWorktree) {
|
|
50573
51001
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50574
|
-
const isRemoteWorktree = nodeDaemonId && nodeDaemonId
|
|
51002
|
+
const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
|
|
50575
51003
|
if (isRemoteWorktree) {
|
|
50576
51004
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
|
|
50577
51005
|
...typeof args === "object" && args !== null ? args : {},
|
|
@@ -50653,7 +51081,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50653
51081
|
const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
|
|
50654
51082
|
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
50655
51083
|
const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
|
|
50656
|
-
if (sourceDaemonId && sourceDaemonId
|
|
51084
|
+
if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50657
51085
|
const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
|
|
50658
51086
|
...typeof args === "object" && args !== null ? args : {},
|
|
50659
51087
|
_meshDirectDispatch: true
|
|
@@ -50895,7 +51323,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
50895
51323
|
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
50896
51324
|
if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
|
|
50897
51325
|
const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
50898
|
-
if (nodeDaemonId && nodeDaemonId
|
|
51326
|
+
if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
50899
51327
|
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
|
|
50900
51328
|
...typeof args === "object" && args !== null ? args : {},
|
|
50901
51329
|
_meshDirectDispatch: true
|
|
@@ -52105,16 +52533,16 @@ var DaemonStatusReporter = class {
|
|
|
52105
52533
|
const now = this.lastStatusSentAt;
|
|
52106
52534
|
const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
|
|
52107
52535
|
const allStates = this.deps.instanceManager.collectAllStates();
|
|
52108
|
-
const ideStates = allStates.filter((
|
|
52109
|
-
const cliStates = allStates.filter((
|
|
52110
|
-
const acpStates = allStates.filter((
|
|
52111
|
-
const ideSummary = ideStates.map((
|
|
52112
|
-
const msgs =
|
|
52113
|
-
const exts =
|
|
52114
|
-
return `${
|
|
52536
|
+
const ideStates = allStates.filter((s2) => s2.category === "ide");
|
|
52537
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli");
|
|
52538
|
+
const acpStates = allStates.filter((s2) => s2.category === "acp");
|
|
52539
|
+
const ideSummary = ideStates.map((s2) => {
|
|
52540
|
+
const msgs = s2.activeChat?.messages?.length || 0;
|
|
52541
|
+
const exts = s2.extensions.length;
|
|
52542
|
+
return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
|
|
52115
52543
|
}).join(", ");
|
|
52116
|
-
const cliSummary = cliStates.map((
|
|
52117
|
-
const acpSummary = acpStates.map((
|
|
52544
|
+
const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52545
|
+
const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
|
|
52118
52546
|
const logLevel = opts?.p2pOnly ? "debug" : "info";
|
|
52119
52547
|
const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
|
|
52120
52548
|
const summaryChanged = baseSummary !== this.lastStatusSummary;
|
|
@@ -52225,10 +52653,10 @@ var DaemonStatusReporter = class {
|
|
|
52225
52653
|
}
|
|
52226
52654
|
return false;
|
|
52227
52655
|
}
|
|
52228
|
-
simpleHash(
|
|
52656
|
+
simpleHash(s2) {
|
|
52229
52657
|
let h = 2166136261;
|
|
52230
|
-
for (let i = 0; i <
|
|
52231
|
-
h ^=
|
|
52658
|
+
for (let i = 0; i < s2.length; i++) {
|
|
52659
|
+
h ^= s2.charCodeAt(i);
|
|
52232
52660
|
h = h * 16777619 >>> 0;
|
|
52233
52661
|
}
|
|
52234
52662
|
return h.toString(36);
|
|
@@ -53454,7 +53882,7 @@ var ProviderInstanceManager = class {
|
|
|
53454
53882
|
* Per-category status collect
|
|
53455
53883
|
*/
|
|
53456
53884
|
collectStatesByCategory(category) {
|
|
53457
|
-
return this.collectAllStates().filter((
|
|
53885
|
+
return this.collectAllStates().filter((s2) => s2.category === category);
|
|
53458
53886
|
}
|
|
53459
53887
|
// ─── Tick engine ─────────────────────────────────
|
|
53460
53888
|
/**
|
|
@@ -55354,9 +55782,9 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
|
|
|
55354
55782
|
function findCliTarget(ctx, type, instanceId) {
|
|
55355
55783
|
if (!ctx.instanceManager) return null;
|
|
55356
55784
|
const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
|
|
55357
|
-
if (instanceId) return cliStates.find((
|
|
55785
|
+
if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
|
|
55358
55786
|
if (!type) return cliStates[cliStates.length - 1] || null;
|
|
55359
|
-
const matches = cliStates.filter((
|
|
55787
|
+
const matches = cliStates.filter((s2) => s2.type === type);
|
|
55360
55788
|
return matches[matches.length - 1] || null;
|
|
55361
55789
|
}
|
|
55362
55790
|
function getCliTargetBundle(ctx, type, instanceId) {
|
|
@@ -55719,20 +56147,20 @@ async function handleCliStatus(ctx, _req, res) {
|
|
|
55719
56147
|
return;
|
|
55720
56148
|
}
|
|
55721
56149
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55722
|
-
const cliStates = allStates.filter((
|
|
55723
|
-
const result = cliStates.map((
|
|
55724
|
-
instanceId:
|
|
55725
|
-
type:
|
|
55726
|
-
name:
|
|
55727
|
-
category:
|
|
55728
|
-
status:
|
|
55729
|
-
mode:
|
|
55730
|
-
workspace:
|
|
55731
|
-
messageCount:
|
|
55732
|
-
lastMessage:
|
|
55733
|
-
activeModal:
|
|
55734
|
-
pendingEvents:
|
|
55735
|
-
settings:
|
|
56150
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56151
|
+
const result = cliStates.map((s2) => ({
|
|
56152
|
+
instanceId: s2.instanceId,
|
|
56153
|
+
type: s2.type,
|
|
56154
|
+
name: s2.name,
|
|
56155
|
+
category: s2.category,
|
|
56156
|
+
status: s2.status,
|
|
56157
|
+
mode: s2.mode,
|
|
56158
|
+
workspace: s2.workspace,
|
|
56159
|
+
messageCount: s2.activeChat?.messages?.length || 0,
|
|
56160
|
+
lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
|
|
56161
|
+
activeModal: s2.activeChat?.activeModal || null,
|
|
56162
|
+
pendingEvents: s2.pendingEvents || [],
|
|
56163
|
+
settings: s2.settings
|
|
55736
56164
|
}));
|
|
55737
56165
|
ctx.json(res, 200, { instances: result, count: result.length });
|
|
55738
56166
|
}
|
|
@@ -55821,9 +56249,9 @@ function handleCliSSE(ctx, cliSSEClients, _req, res) {
|
|
|
55821
56249
|
}
|
|
55822
56250
|
if (ctx.instanceManager) {
|
|
55823
56251
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55824
|
-
const cliStates = allStates.filter((
|
|
55825
|
-
for (const
|
|
55826
|
-
ctx.sendCliSSE({ event: "snapshot", providerType:
|
|
56252
|
+
const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
|
|
56253
|
+
for (const s2 of cliStates) {
|
|
56254
|
+
ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
|
|
55827
56255
|
}
|
|
55828
56256
|
}
|
|
55829
56257
|
_req.on("close", () => {
|
|
@@ -55839,7 +56267,7 @@ async function handleCliDebug(ctx, type, _req, res) {
|
|
|
55839
56267
|
const target = findCliTarget(ctx, type);
|
|
55840
56268
|
if (!target) {
|
|
55841
56269
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55842
|
-
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((
|
|
56270
|
+
ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
|
|
55843
56271
|
return;
|
|
55844
56272
|
}
|
|
55845
56273
|
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
@@ -55885,7 +56313,7 @@ async function handleCliTrace(ctx, type, req, res) {
|
|
|
55885
56313
|
const allStates = ctx.instanceManager.collectAllStates();
|
|
55886
56314
|
ctx.json(res, 404, {
|
|
55887
56315
|
error: `No running instance for: ${type}`,
|
|
55888
|
-
available: allStates.filter((
|
|
56316
|
+
available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
|
|
55889
56317
|
});
|
|
55890
56318
|
return;
|
|
55891
56319
|
}
|
|
@@ -56690,7 +57118,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56690
57118
|
child.write("\x1B[12;1R");
|
|
56691
57119
|
ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
|
|
56692
57120
|
}
|
|
56693
|
-
checkAutoApproval(data, (
|
|
57121
|
+
checkAutoApproval(data, (s2) => child.write(s2));
|
|
56694
57122
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
|
|
56695
57123
|
scheduleAutoStopForVerification();
|
|
56696
57124
|
});
|
|
@@ -56703,7 +57131,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56703
57131
|
stdout += chunk;
|
|
56704
57132
|
clearAutoStopTimer();
|
|
56705
57133
|
if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
|
|
56706
|
-
checkAutoApproval(chunk, (
|
|
57134
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
56707
57135
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
|
|
56708
57136
|
scheduleAutoStopForVerification();
|
|
56709
57137
|
});
|
|
@@ -56711,7 +57139,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
56711
57139
|
const chunk = d.toString();
|
|
56712
57140
|
stderr += chunk;
|
|
56713
57141
|
clearAutoStopTimer();
|
|
56714
|
-
checkAutoApproval(chunk, (
|
|
57142
|
+
checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
|
|
56715
57143
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
|
|
56716
57144
|
scheduleAutoStopForVerification();
|
|
56717
57145
|
});
|
|
@@ -57526,59 +57954,59 @@ var DevServer = class _DevServer {
|
|
|
57526
57954
|
// ─── Route Table ─────────────────────────────────────
|
|
57527
57955
|
routes = [
|
|
57528
57956
|
// Static routes
|
|
57529
|
-
{ method: "GET", pattern: "/api/providers", handler: (q,
|
|
57530
|
-
{ method: "GET", pattern: "/api/providers/source-config", handler: (q,
|
|
57531
|
-
{ method: "POST", pattern: "/api/providers/source-config", handler: (q,
|
|
57532
|
-
{ method: "GET", pattern: "/api/providers/versions", handler: (q,
|
|
57533
|
-
{ method: "POST", pattern: "/api/providers/reload", handler: (q,
|
|
57534
|
-
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q,
|
|
57535
|
-
{ method: "POST", pattern: "/api/cdp/click", handler: (q,
|
|
57536
|
-
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q,
|
|
57537
|
-
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q,
|
|
57538
|
-
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q,
|
|
57539
|
-
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q,
|
|
57540
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q,
|
|
57541
|
-
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q,
|
|
57542
|
-
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q,
|
|
57543
|
-
{ method: "GET", pattern: "/api/cdp/targets", handler: (q,
|
|
57544
|
-
{ method: "POST", pattern: "/api/scripts/run", handler: (q,
|
|
57545
|
-
{ method: "GET", pattern: "/api/status", handler: (q,
|
|
57546
|
-
{ method: "POST", pattern: "/api/watch/start", handler: (q,
|
|
57547
|
-
{ method: "POST", pattern: "/api/watch/stop", handler: (q,
|
|
57548
|
-
{ method: "GET", pattern: "/api/watch/events", handler: (q,
|
|
57549
|
-
{ method: "POST", pattern: "/api/scaffold", handler: (q,
|
|
57957
|
+
{ method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
|
|
57958
|
+
{ method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
|
|
57959
|
+
{ method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
|
|
57960
|
+
{ method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
|
|
57961
|
+
{ method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
|
|
57962
|
+
{ method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
|
|
57963
|
+
{ method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
|
|
57964
|
+
{ method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
|
|
57965
|
+
{ method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
|
|
57966
|
+
{ method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
|
|
57967
|
+
{ method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
|
|
57968
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
|
|
57969
|
+
{ method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
|
|
57970
|
+
{ method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
|
|
57971
|
+
{ method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
|
|
57972
|
+
{ method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
|
|
57973
|
+
{ method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
|
|
57974
|
+
{ method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
|
|
57975
|
+
{ method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
|
|
57976
|
+
{ method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
|
|
57977
|
+
{ method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
|
|
57550
57978
|
// CLI Debug routes
|
|
57551
|
-
{ method: "GET", pattern: "/api/cli/status", handler: (q,
|
|
57552
|
-
{ method: "POST", pattern: "/api/cli/launch", handler: (q,
|
|
57553
|
-
{ method: "POST", pattern: "/api/cli/send", handler: (q,
|
|
57554
|
-
{ method: "POST", pattern: "/api/cli/exercise", handler: (q,
|
|
57555
|
-
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q,
|
|
57556
|
-
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q,
|
|
57557
|
-
{ method: "POST", pattern: "/api/cli/resolve", handler: (q,
|
|
57558
|
-
{ method: "POST", pattern: "/api/cli/raw", handler: (q,
|
|
57559
|
-
{ method: "POST", pattern: "/api/cli/stop", handler: (q,
|
|
57560
|
-
{ method: "GET", pattern: "/api/cli/events", handler: (q,
|
|
57561
|
-
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q,
|
|
57562
|
-
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q,
|
|
57563
|
-
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q,
|
|
57979
|
+
{ method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
|
|
57980
|
+
{ method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
|
|
57981
|
+
{ method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
|
|
57982
|
+
{ method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
|
|
57983
|
+
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
|
|
57984
|
+
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
|
|
57985
|
+
{ method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
|
|
57986
|
+
{ method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
|
|
57987
|
+
{ method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
|
|
57988
|
+
{ method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
|
|
57989
|
+
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
|
|
57990
|
+
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
|
|
57991
|
+
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
|
|
57564
57992
|
// Dynamic routes (provider :type param)
|
|
57565
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q,
|
|
57566
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q,
|
|
57567
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57568
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q,
|
|
57569
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q,
|
|
57570
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q,
|
|
57571
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q,
|
|
57572
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q,
|
|
57573
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q,
|
|
57574
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q,
|
|
57575
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q,
|
|
57576
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q,
|
|
57577
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q,
|
|
57578
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q,
|
|
57579
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q,
|
|
57580
|
-
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q,
|
|
57581
|
-
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q,
|
|
57993
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
|
|
57994
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
|
|
57995
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
|
|
57996
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
|
|
57997
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
|
|
57998
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
|
|
57999
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
|
|
58000
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
|
|
58001
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
|
|
58002
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
|
|
58003
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
|
|
58004
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
|
|
58005
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
|
|
58006
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
|
|
58007
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
|
|
58008
|
+
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
|
|
58009
|
+
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
|
|
57582
58010
|
];
|
|
57583
58011
|
matchRoute(method, pathname) {
|
|
57584
58012
|
for (const route of this.routes) {
|
|
@@ -58173,14 +58601,14 @@ var DevServer = class _DevServer {
|
|
|
58173
58601
|
warnings.push(...validation.warnings);
|
|
58174
58602
|
if (config.settings) {
|
|
58175
58603
|
for (const [key, val] of Object.entries(config.settings)) {
|
|
58176
|
-
const
|
|
58177
|
-
if (!
|
|
58178
|
-
else if (!["boolean", "number", "string", "select"].includes(
|
|
58179
|
-
errors.push(`settings.${key}: invalid type '${
|
|
58180
|
-
if (
|
|
58181
|
-
if (
|
|
58182
|
-
errors.push(`settings.${key}: min (${
|
|
58183
|
-
if (
|
|
58604
|
+
const s2 = val;
|
|
58605
|
+
if (!s2.type) errors.push(`settings.${key}: missing type`);
|
|
58606
|
+
else if (!["boolean", "number", "string", "select"].includes(s2.type))
|
|
58607
|
+
errors.push(`settings.${key}: invalid type '${s2.type}'`);
|
|
58608
|
+
if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
|
|
58609
|
+
if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
|
|
58610
|
+
errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
|
|
58611
|
+
if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
|
|
58184
58612
|
errors.push(`settings.${key}: select type requires options[]`);
|
|
58185
58613
|
}
|
|
58186
58614
|
}
|