@adhdev/daemon-core 0.9.82-rc.195 → 0.9.82-rc.197
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/cli-adapter-types.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +594 -78
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +593 -83
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/contracts.d.ts +1 -1
- package/dist/mesh/mesh-active-work.d.ts +1 -1
- package/dist/mesh/mesh-delivery-policy.d.ts +126 -0
- package/dist/mesh/{beads-db.d.ts → mesh-runtime-store.d.ts} +68 -2
- package/dist/mesh/mesh-work-queue.d.ts +3 -3
- package/dist/providers/provider-instance.d.ts +1 -1
- package/dist/providers/spec/driver.d.ts +4 -1
- package/dist/providers/spec/schema.gen.d.ts +46 -0
- package/dist/providers/spec/types.d.ts +39 -0
- package/dist/shared-types-extra.d.ts +1 -1
- package/dist/status/normalize.d.ts +1 -1
- package/dist/status/normalize.js +1 -0
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +1 -0
- package/dist/status/normalize.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cli-adapter-types.ts +1 -0
- package/src/cli-adapters/cli-state-engine.ts +44 -2
- package/src/index.ts +4 -0
- package/src/mesh/contracts.ts +1 -1
- package/src/mesh/mesh-active-work.ts +8 -8
- package/src/mesh/mesh-delivery-policy.ts +298 -0
- package/src/mesh/mesh-events.ts +64 -15
- package/src/mesh/{beads-db.ts → mesh-runtime-store.ts} +249 -7
- package/src/mesh/mesh-work-queue.ts +33 -33
- package/src/providers/cli-provider-instance.ts +31 -8
- package/src/providers/provider-instance.ts +1 -1
- package/src/providers/spec/driver.ts +34 -3
- package/src/providers/spec/evaluator.ts +32 -3
- package/src/providers/spec/schema.gen.ts +22 -2
- package/src/providers/spec/schema.json +1 -0
- package/src/providers/spec/types.ts +39 -0
- package/src/providers/types/interactive-prompt.ts +21 -7
- package/src/shared-types-extra.ts +1 -1
- package/src/status/normalize.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -3295,7 +3295,7 @@ var init_mesh_fast_forward = __esm({
|
|
|
3295
3295
|
}
|
|
3296
3296
|
});
|
|
3297
3297
|
|
|
3298
|
-
// src/mesh/
|
|
3298
|
+
// src/mesh/mesh-runtime-store.ts
|
|
3299
3299
|
function loadDatabaseCtor() {
|
|
3300
3300
|
if (DatabaseCtor) return DatabaseCtor;
|
|
3301
3301
|
const runtimeRequire = typeof require === "function" ? require : (0, import_module.createRequire)(import_meta.url);
|
|
@@ -3308,9 +3308,27 @@ function safeMeshId(meshId) {
|
|
|
3308
3308
|
function legacyQueuePath(meshId) {
|
|
3309
3309
|
return (0, import_path7.join)(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
3310
3310
|
}
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
"
|
|
3311
|
+
function meshRuntimeStorePath() {
|
|
3312
|
+
const dir = getLedgerDir();
|
|
3313
|
+
const nextPath = (0, import_path7.join)(dir, "mesh-runtime.db");
|
|
3314
|
+
if ((0, import_fs7.existsSync)(nextPath)) return nextPath;
|
|
3315
|
+
const legacyPath = (0, import_path7.join)(dir, "beads.db");
|
|
3316
|
+
if (!(0, import_fs7.existsSync)(legacyPath)) return nextPath;
|
|
3317
|
+
try {
|
|
3318
|
+
(0, import_fs7.renameSync)(legacyPath, nextPath);
|
|
3319
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
3320
|
+
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
3321
|
+
if ((0, import_fs7.existsSync)(legacyCompanion)) {
|
|
3322
|
+
(0, import_fs7.renameSync)(legacyCompanion, `${nextPath}${suffix}`);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
} catch {
|
|
3326
|
+
}
|
|
3327
|
+
return nextPath;
|
|
3328
|
+
}
|
|
3329
|
+
var import_fs7, import_path7, import_module, import_meta, DatabaseCtor, MeshRuntimeStore;
|
|
3330
|
+
var init_mesh_runtime_store = __esm({
|
|
3331
|
+
"src/mesh/mesh-runtime-store.ts"() {
|
|
3314
3332
|
"use strict";
|
|
3315
3333
|
import_fs7 = require("fs");
|
|
3316
3334
|
import_path7 = require("path");
|
|
@@ -3318,7 +3336,7 @@ var init_beads_db = __esm({
|
|
|
3318
3336
|
init_mesh_ledger();
|
|
3319
3337
|
init_mesh_work_queue();
|
|
3320
3338
|
import_meta = {};
|
|
3321
|
-
|
|
3339
|
+
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
3322
3340
|
static instance;
|
|
3323
3341
|
db;
|
|
3324
3342
|
dbPath;
|
|
@@ -3341,7 +3359,7 @@ var init_beads_db = __esm({
|
|
|
3341
3359
|
}
|
|
3342
3360
|
static getInstance() {
|
|
3343
3361
|
if (!this.instance) {
|
|
3344
|
-
this.instance = new
|
|
3362
|
+
this.instance = new _MeshRuntimeStore(meshRuntimeStorePath());
|
|
3345
3363
|
}
|
|
3346
3364
|
return this.instance;
|
|
3347
3365
|
}
|
|
@@ -3406,6 +3424,49 @@ var init_beads_db = __esm({
|
|
|
3406
3424
|
metadata TEXT,
|
|
3407
3425
|
PRIMARY KEY (node_id, session_id)
|
|
3408
3426
|
);
|
|
3427
|
+
|
|
3428
|
+
CREATE TABLE IF NOT EXISTS mesh_session_delivery (
|
|
3429
|
+
id TEXT PRIMARY KEY,
|
|
3430
|
+
mesh_id TEXT NOT NULL,
|
|
3431
|
+
node_id TEXT,
|
|
3432
|
+
session_id TEXT,
|
|
3433
|
+
provider_type TEXT,
|
|
3434
|
+
task_id TEXT,
|
|
3435
|
+
kind TEXT NOT NULL,
|
|
3436
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
3437
|
+
message TEXT NOT NULL,
|
|
3438
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
3439
|
+
deliver_after TEXT,
|
|
3440
|
+
expires_at TEXT,
|
|
3441
|
+
attempt_count INTEGER NOT NULL DEFAULT 0,
|
|
3442
|
+
source_coordinator_session_id TEXT,
|
|
3443
|
+
source_coordinator_daemon_id TEXT,
|
|
3444
|
+
last_error TEXT,
|
|
3445
|
+
created_at TEXT NOT NULL,
|
|
3446
|
+
updated_at TEXT NOT NULL
|
|
3447
|
+
);
|
|
3448
|
+
|
|
3449
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_mesh_status
|
|
3450
|
+
ON mesh_session_delivery(mesh_id, status, created_at);
|
|
3451
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_session
|
|
3452
|
+
ON mesh_session_delivery(mesh_id, session_id, status);
|
|
3453
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_task
|
|
3454
|
+
ON mesh_session_delivery(mesh_id, task_id);
|
|
3455
|
+
|
|
3456
|
+
CREATE TABLE IF NOT EXISTS mesh_completion_conflicts (
|
|
3457
|
+
id TEXT PRIMARY KEY,
|
|
3458
|
+
mesh_id TEXT NOT NULL,
|
|
3459
|
+
fingerprint TEXT NOT NULL,
|
|
3460
|
+
conflicting_task_id TEXT,
|
|
3461
|
+
conflicting_session_id TEXT,
|
|
3462
|
+
original_task_id TEXT,
|
|
3463
|
+
original_session_id TEXT,
|
|
3464
|
+
event TEXT NOT NULL,
|
|
3465
|
+
created_at TEXT NOT NULL
|
|
3466
|
+
);
|
|
3467
|
+
|
|
3468
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_completion_conflicts_mesh
|
|
3469
|
+
ON mesh_completion_conflicts(mesh_id, created_at);
|
|
3409
3470
|
`);
|
|
3410
3471
|
}
|
|
3411
3472
|
hasCompletionFingerprint(fingerprint) {
|
|
@@ -3426,13 +3487,13 @@ var init_beads_db = __esm({
|
|
|
3426
3487
|
this.db.prepare("DELETE FROM mesh_completion_fingerprints WHERE expires_at <= ?").run(Date.now());
|
|
3427
3488
|
}
|
|
3428
3489
|
maybeCheckpointWal() {
|
|
3429
|
-
if (++this.walWriteCounter <
|
|
3490
|
+
if (++this.walWriteCounter < _MeshRuntimeStore.WAL_CHECK_INTERVAL) return;
|
|
3430
3491
|
this.walWriteCounter = 0;
|
|
3431
3492
|
try {
|
|
3432
3493
|
const walPath = `${this.dbPath}-wal`;
|
|
3433
3494
|
if (!(0, import_fs7.existsSync)(walPath)) return;
|
|
3434
3495
|
const size = (0, import_fs7.statSync)(walPath).size;
|
|
3435
|
-
if (size <
|
|
3496
|
+
if (size < _MeshRuntimeStore.WAL_MAX_BYTES) return;
|
|
3436
3497
|
process.stderr.write(
|
|
3437
3498
|
`[adhdev-mesh] WAL file ${Math.round(size / 1024 / 1024)}MB exceeds threshold; forcing checkpoint
|
|
3438
3499
|
`
|
|
@@ -3730,6 +3791,131 @@ var init_beads_db = __esm({
|
|
|
3730
3791
|
pruneExpiredRemoteIdleSessions() {
|
|
3731
3792
|
this.db.prepare("DELETE FROM remote_idle_sessions WHERE expires_at <= ?").run(Date.now());
|
|
3732
3793
|
}
|
|
3794
|
+
// ── Session Delivery Queue ───────────────────────────────────────────────
|
|
3795
|
+
insertSessionDelivery(entry) {
|
|
3796
|
+
this.db.prepare(`
|
|
3797
|
+
INSERT OR REPLACE INTO mesh_session_delivery (
|
|
3798
|
+
id, mesh_id, node_id, session_id, provider_type, task_id, kind, priority,
|
|
3799
|
+
message, status, deliver_after, expires_at, attempt_count,
|
|
3800
|
+
source_coordinator_session_id, source_coordinator_daemon_id,
|
|
3801
|
+
last_error, created_at, updated_at
|
|
3802
|
+
) VALUES (
|
|
3803
|
+
@id, @meshId, @nodeId, @sessionId, @providerType, @taskId, @kind, @priority,
|
|
3804
|
+
@message, @status, @deliverAfter, @expiresAt, 0,
|
|
3805
|
+
@sourceCoordinatorSessionId, @sourceCoordinatorDaemonId,
|
|
3806
|
+
NULL, @createdAt, @updatedAt
|
|
3807
|
+
)
|
|
3808
|
+
`).run({
|
|
3809
|
+
id: entry.id,
|
|
3810
|
+
meshId: entry.meshId,
|
|
3811
|
+
nodeId: entry.nodeId ?? null,
|
|
3812
|
+
sessionId: entry.sessionId ?? null,
|
|
3813
|
+
providerType: entry.providerType ?? null,
|
|
3814
|
+
taskId: entry.taskId ?? null,
|
|
3815
|
+
kind: entry.kind,
|
|
3816
|
+
priority: entry.priority ?? 0,
|
|
3817
|
+
message: entry.message,
|
|
3818
|
+
status: entry.status,
|
|
3819
|
+
deliverAfter: entry.deliverAfter ?? null,
|
|
3820
|
+
expiresAt: entry.expiresAt ?? null,
|
|
3821
|
+
sourceCoordinatorSessionId: entry.sourceCoordinatorSessionId ?? null,
|
|
3822
|
+
sourceCoordinatorDaemonId: entry.sourceCoordinatorDaemonId ?? null,
|
|
3823
|
+
createdAt: entry.createdAt,
|
|
3824
|
+
updatedAt: entry.updatedAt
|
|
3825
|
+
});
|
|
3826
|
+
this.maybeCheckpointWal();
|
|
3827
|
+
}
|
|
3828
|
+
updateSessionDeliveryStatus(id, status, opts) {
|
|
3829
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3830
|
+
if (opts?.incrementAttempt) {
|
|
3831
|
+
this.db.prepare(`
|
|
3832
|
+
UPDATE mesh_session_delivery
|
|
3833
|
+
SET status = @status, last_error = @lastError, attempt_count = attempt_count + 1, updated_at = @updatedAt
|
|
3834
|
+
WHERE id = @id
|
|
3835
|
+
`).run({ id, status, lastError: opts?.lastError ?? null, updatedAt: now });
|
|
3836
|
+
} else {
|
|
3837
|
+
this.db.prepare(`
|
|
3838
|
+
UPDATE mesh_session_delivery
|
|
3839
|
+
SET status = @status, last_error = @lastError, updated_at = @updatedAt
|
|
3840
|
+
WHERE id = @id
|
|
3841
|
+
`).run({ id, status, lastError: opts?.lastError ?? null, updatedAt: now });
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
getActiveSessionDeliveries(meshId, sessionId) {
|
|
3845
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3846
|
+
const sql = sessionId ? `SELECT * FROM mesh_session_delivery WHERE mesh_id = ? AND session_id = ? AND status NOT IN ('delivered','completed','failed','expired','cancelled') AND (expires_at IS NULL OR expires_at > ?) ORDER BY priority DESC, created_at ASC` : `SELECT * FROM mesh_session_delivery WHERE mesh_id = ? AND status NOT IN ('delivered','completed','failed','expired','cancelled') AND (expires_at IS NULL OR expires_at > ?) ORDER BY priority DESC, created_at ASC`;
|
|
3847
|
+
const rows = sessionId ? this.db.prepare(sql).all(meshId, sessionId, now) : this.db.prepare(sql).all(meshId, now);
|
|
3848
|
+
return rows.map((r) => ({
|
|
3849
|
+
id: r.id,
|
|
3850
|
+
meshId: r.mesh_id,
|
|
3851
|
+
nodeId: r.node_id,
|
|
3852
|
+
sessionId: r.session_id,
|
|
3853
|
+
providerType: r.provider_type,
|
|
3854
|
+
taskId: r.task_id,
|
|
3855
|
+
kind: r.kind,
|
|
3856
|
+
priority: r.priority,
|
|
3857
|
+
message: r.message,
|
|
3858
|
+
status: r.status,
|
|
3859
|
+
deliverAfter: r.deliver_after,
|
|
3860
|
+
expiresAt: r.expires_at,
|
|
3861
|
+
attemptCount: r.attempt_count,
|
|
3862
|
+
sourceCoordinatorSessionId: r.source_coordinator_session_id,
|
|
3863
|
+
sourceCoordinatorDaemonId: r.source_coordinator_daemon_id,
|
|
3864
|
+
lastError: r.last_error,
|
|
3865
|
+
createdAt: r.created_at,
|
|
3866
|
+
updatedAt: r.updated_at
|
|
3867
|
+
}));
|
|
3868
|
+
}
|
|
3869
|
+
expireStaleSessionDeliveries(meshId) {
|
|
3870
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3871
|
+
this.db.prepare(`
|
|
3872
|
+
UPDATE mesh_session_delivery
|
|
3873
|
+
SET status = 'expired', updated_at = ?
|
|
3874
|
+
WHERE mesh_id = ? AND expires_at IS NOT NULL AND expires_at <= ?
|
|
3875
|
+
AND status NOT IN ('delivered','completed','failed','expired','cancelled')
|
|
3876
|
+
`).run(now, meshId, now);
|
|
3877
|
+
}
|
|
3878
|
+
deleteSessionDeliveries(meshId) {
|
|
3879
|
+
this.db.prepare("DELETE FROM mesh_session_delivery WHERE mesh_id = ?").run(meshId);
|
|
3880
|
+
}
|
|
3881
|
+
// ── Completion Conflict Diagnostics ──────────────────────────────────────
|
|
3882
|
+
recordCompletionConflict(entry) {
|
|
3883
|
+
this.db.prepare(`
|
|
3884
|
+
INSERT OR IGNORE INTO mesh_completion_conflicts
|
|
3885
|
+
(id, mesh_id, fingerprint, conflicting_task_id, conflicting_session_id,
|
|
3886
|
+
original_task_id, original_session_id, event, created_at)
|
|
3887
|
+
VALUES (@id, @meshId, @fingerprint, @conflictingTaskId, @conflictingSessionId,
|
|
3888
|
+
@originalTaskId, @originalSessionId, @event, @createdAt)
|
|
3889
|
+
`).run({
|
|
3890
|
+
id: entry.id,
|
|
3891
|
+
meshId: entry.meshId,
|
|
3892
|
+
fingerprint: entry.fingerprint,
|
|
3893
|
+
conflictingTaskId: entry.conflictingTaskId ?? null,
|
|
3894
|
+
conflictingSessionId: entry.conflictingSessionId ?? null,
|
|
3895
|
+
originalTaskId: entry.originalTaskId ?? null,
|
|
3896
|
+
originalSessionId: entry.originalSessionId ?? null,
|
|
3897
|
+
event: entry.event,
|
|
3898
|
+
createdAt: entry.createdAt
|
|
3899
|
+
});
|
|
3900
|
+
this.maybeCheckpointWal();
|
|
3901
|
+
}
|
|
3902
|
+
getRecentCompletionConflicts(meshId, limitMs = 60 * 60 * 1e3) {
|
|
3903
|
+
const cutoff = new Date(Date.now() - limitMs).toISOString();
|
|
3904
|
+
const rows = this.db.prepare(
|
|
3905
|
+
"SELECT * FROM mesh_completion_conflicts WHERE mesh_id = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 50"
|
|
3906
|
+
).all(meshId, cutoff);
|
|
3907
|
+
return rows.map((r) => ({
|
|
3908
|
+
id: r.id,
|
|
3909
|
+
meshId: r.mesh_id,
|
|
3910
|
+
fingerprint: r.fingerprint,
|
|
3911
|
+
conflictingTaskId: r.conflicting_task_id,
|
|
3912
|
+
conflictingSessionId: r.conflicting_session_id,
|
|
3913
|
+
originalTaskId: r.original_task_id,
|
|
3914
|
+
originalSessionId: r.original_session_id,
|
|
3915
|
+
event: r.event,
|
|
3916
|
+
createdAt: r.created_at
|
|
3917
|
+
}));
|
|
3918
|
+
}
|
|
3733
3919
|
};
|
|
3734
3920
|
}
|
|
3735
3921
|
});
|
|
@@ -3743,7 +3929,7 @@ __export(mesh_work_queue_exports, {
|
|
|
3743
3929
|
__clearDirectDispatchesForTests: () => __clearDirectDispatchesForTests,
|
|
3744
3930
|
__clearMeshQueueForTests: () => __clearMeshQueueForTests,
|
|
3745
3931
|
__replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
|
|
3746
|
-
|
|
3932
|
+
__resetMeshRuntimeStoreForTests: () => __resetMeshRuntimeStoreForTests,
|
|
3747
3933
|
buildMeshNodeCapabilityTags: () => buildMeshNodeCapabilityTags,
|
|
3748
3934
|
cancelTask: () => cancelTask,
|
|
3749
3935
|
claimNextTask: () => claimNextTask,
|
|
@@ -3821,7 +4007,7 @@ function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
|
|
|
3821
4007
|
return required.every((tag) => available.has(tag));
|
|
3822
4008
|
}
|
|
3823
4009
|
function withQueueLock(_meshId, fn) {
|
|
3824
|
-
return
|
|
4010
|
+
return MeshRuntimeStore.getInstance().transaction(fn);
|
|
3825
4011
|
}
|
|
3826
4012
|
function enqueueTask(meshId, message, opts) {
|
|
3827
4013
|
requireMeshHostQueueOwner(opts);
|
|
@@ -3841,55 +4027,55 @@ function enqueueTask(meshId, message, opts) {
|
|
|
3841
4027
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3842
4028
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3843
4029
|
};
|
|
3844
|
-
|
|
4030
|
+
MeshRuntimeStore.getInstance().insertQueueEntry(entry);
|
|
3845
4031
|
return entry;
|
|
3846
4032
|
}
|
|
3847
4033
|
function getQueue(meshId, opts) {
|
|
3848
|
-
return
|
|
4034
|
+
return MeshRuntimeStore.getInstance().getQueueEntries(meshId, opts?.status?.length ? opts.status : void 0);
|
|
3849
4035
|
}
|
|
3850
4036
|
function getMeshQueueRevision(meshId) {
|
|
3851
|
-
return
|
|
4037
|
+
return MeshRuntimeStore.getInstance().getQueueRevision(meshId);
|
|
3852
4038
|
}
|
|
3853
4039
|
function claimNextTask(meshId, nodeId, sessionId, capabilityTags) {
|
|
3854
|
-
return
|
|
4040
|
+
return MeshRuntimeStore.getInstance().claimNextQueueTask(meshId, nodeId, sessionId, capabilityTags);
|
|
3855
4041
|
}
|
|
3856
4042
|
function updateTaskStatus(meshId, taskId, status, opts) {
|
|
3857
4043
|
requireMeshHostQueueOwner(opts);
|
|
3858
4044
|
return withQueueLock(meshId, () => {
|
|
3859
|
-
const entry =
|
|
4045
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3860
4046
|
if (!entry) return null;
|
|
3861
4047
|
entry.status = status;
|
|
3862
|
-
|
|
4048
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3863
4049
|
return entry;
|
|
3864
4050
|
});
|
|
3865
4051
|
}
|
|
3866
4052
|
function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
|
|
3867
4053
|
return withQueueLock(meshId, () => {
|
|
3868
|
-
const entry =
|
|
4054
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3869
4055
|
if (!entry) return null;
|
|
3870
4056
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3871
4057
|
entry.autoLaunch = { ...autoLaunch, updatedAt: now };
|
|
3872
|
-
|
|
4058
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3873
4059
|
return entry;
|
|
3874
4060
|
});
|
|
3875
4061
|
}
|
|
3876
4062
|
function cancelTask(meshId, taskId, opts) {
|
|
3877
4063
|
requireMeshHostQueueOwner(opts);
|
|
3878
4064
|
return withQueueLock(meshId, () => {
|
|
3879
|
-
const entry =
|
|
4065
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3880
4066
|
if (!entry) return null;
|
|
3881
4067
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3882
4068
|
entry.status = "cancelled";
|
|
3883
4069
|
entry.cancelledAt = now;
|
|
3884
4070
|
if (opts?.reason) entry.cancelReason = opts.reason;
|
|
3885
|
-
|
|
4071
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3886
4072
|
return entry;
|
|
3887
4073
|
});
|
|
3888
4074
|
}
|
|
3889
4075
|
function requeueTask(meshId, taskId, opts) {
|
|
3890
4076
|
requireMeshHostQueueOwner(opts);
|
|
3891
4077
|
return withQueueLock(meshId, () => {
|
|
3892
|
-
const entry =
|
|
4078
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3893
4079
|
if (!entry) return null;
|
|
3894
4080
|
entry.status = "pending";
|
|
3895
4081
|
delete entry.assignedNodeId;
|
|
@@ -3903,22 +4089,22 @@ function requeueTask(meshId, taskId, opts) {
|
|
|
3903
4089
|
entry.requeuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3904
4090
|
entry.requeueCount = (entry.requeueCount || 0) + 1;
|
|
3905
4091
|
if (opts?.reason) entry.requeueReason = opts.reason;
|
|
3906
|
-
|
|
4092
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3907
4093
|
return entry;
|
|
3908
4094
|
});
|
|
3909
4095
|
}
|
|
3910
4096
|
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
3911
4097
|
return withQueueLock(meshId, () => {
|
|
3912
4098
|
const occurredAtIso = opts?.occurredAt ? new Date(opts.occurredAt).toISOString() : void 0;
|
|
3913
|
-
const entry =
|
|
4099
|
+
const entry = MeshRuntimeStore.getInstance().findAssignedBySession(meshId, sessionId, occurredAtIso);
|
|
3914
4100
|
if (!entry) return null;
|
|
3915
4101
|
entry.status = status;
|
|
3916
|
-
|
|
4102
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3917
4103
|
return entry;
|
|
3918
4104
|
});
|
|
3919
4105
|
}
|
|
3920
4106
|
function getMeshQueueStats(meshId) {
|
|
3921
|
-
const rows =
|
|
4107
|
+
const rows = MeshRuntimeStore.getInstance().getQueueStatsByStatus(meshId);
|
|
3922
4108
|
const counts = {};
|
|
3923
4109
|
for (const r of rows) counts[r.status] = r.count;
|
|
3924
4110
|
const pending = counts["pending"] ?? 0;
|
|
@@ -3937,26 +4123,26 @@ function getMeshQueueStats(meshId) {
|
|
|
3937
4123
|
cancelled,
|
|
3938
4124
|
activeCounts: { pending, assigned },
|
|
3939
4125
|
historicalCounts: { completed, failed, cancelled },
|
|
3940
|
-
activeAssignments:
|
|
4126
|
+
activeAssignments: MeshRuntimeStore.getInstance().getActiveAssignmentDetails(meshId)
|
|
3941
4127
|
};
|
|
3942
4128
|
}
|
|
3943
4129
|
function __replaceMeshQueueForTests(meshId, queue) {
|
|
3944
|
-
|
|
3945
|
-
|
|
4130
|
+
MeshRuntimeStore.getInstance().transaction(() => {
|
|
4131
|
+
MeshRuntimeStore.getInstance().replaceQueue(meshId, queue);
|
|
3946
4132
|
});
|
|
3947
4133
|
}
|
|
3948
4134
|
function __clearMeshQueueForTests(meshId) {
|
|
3949
|
-
|
|
4135
|
+
MeshRuntimeStore.getInstance().deleteQueue(meshId);
|
|
3950
4136
|
}
|
|
3951
4137
|
function __clearDirectDispatchesForTests(meshId) {
|
|
3952
|
-
|
|
4138
|
+
MeshRuntimeStore.getInstance().deleteDirectDispatches(meshId);
|
|
3953
4139
|
}
|
|
3954
|
-
function
|
|
3955
|
-
|
|
4140
|
+
function __resetMeshRuntimeStoreForTests() {
|
|
4141
|
+
MeshRuntimeStore.resetForTests();
|
|
3956
4142
|
}
|
|
3957
4143
|
function insertDirectDispatch(meshId, data) {
|
|
3958
4144
|
try {
|
|
3959
|
-
|
|
4145
|
+
MeshRuntimeStore.getInstance().insertDirectDispatch({ ...data, meshId });
|
|
3960
4146
|
} catch (e) {
|
|
3961
4147
|
process.stderr.write(`[adhdev-mesh] insertDirectDispatch failed for task ${data.taskId}: ${e?.message || e}
|
|
3962
4148
|
`);
|
|
@@ -3964,26 +4150,26 @@ function insertDirectDispatch(meshId, data) {
|
|
|
3964
4150
|
}
|
|
3965
4151
|
function getActiveDirectDispatches(meshId) {
|
|
3966
4152
|
try {
|
|
3967
|
-
return
|
|
4153
|
+
return MeshRuntimeStore.getInstance().getActiveDirectDispatches(meshId);
|
|
3968
4154
|
} catch {
|
|
3969
4155
|
return [];
|
|
3970
4156
|
}
|
|
3971
4157
|
}
|
|
3972
4158
|
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
3973
4159
|
try {
|
|
3974
|
-
|
|
4160
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status);
|
|
3975
4161
|
} catch {
|
|
3976
4162
|
}
|
|
3977
4163
|
}
|
|
3978
4164
|
function cleanupTerminalDirectDispatches(olderThanMs = 7 * 24 * 60 * 6e4) {
|
|
3979
4165
|
try {
|
|
3980
|
-
|
|
4166
|
+
MeshRuntimeStore.getInstance().cleanupTerminalDirectDispatches(olderThanMs);
|
|
3981
4167
|
} catch {
|
|
3982
4168
|
}
|
|
3983
4169
|
}
|
|
3984
4170
|
function markStaleDirectDispatches(meshId, olderThanMs = 60 * 6e4) {
|
|
3985
4171
|
try {
|
|
3986
|
-
|
|
4172
|
+
MeshRuntimeStore.getInstance().markStaleDirectDispatches(meshId, olderThanMs);
|
|
3987
4173
|
} catch {
|
|
3988
4174
|
}
|
|
3989
4175
|
}
|
|
@@ -3993,7 +4179,7 @@ var init_mesh_work_queue = __esm({
|
|
|
3993
4179
|
"use strict";
|
|
3994
4180
|
import_crypto5 = require("crypto");
|
|
3995
4181
|
init_mesh_host_ownership();
|
|
3996
|
-
|
|
4182
|
+
init_mesh_runtime_store();
|
|
3997
4183
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
3998
4184
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
3999
4185
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
@@ -4144,6 +4330,167 @@ var init_cli_detector = __esm({
|
|
|
4144
4330
|
}
|
|
4145
4331
|
});
|
|
4146
4332
|
|
|
4333
|
+
// src/mesh/mesh-delivery-policy.ts
|
|
4334
|
+
function resolveDeliveryDecision(sessionStatus, opts) {
|
|
4335
|
+
const status = (sessionStatus || "").trim().toLowerCase();
|
|
4336
|
+
if (!status) {
|
|
4337
|
+
return {
|
|
4338
|
+
decision: "rejected",
|
|
4339
|
+
reason: "unknown_session_status",
|
|
4340
|
+
message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
|
|
4341
|
+
};
|
|
4342
|
+
}
|
|
4343
|
+
if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
|
|
4344
|
+
return {
|
|
4345
|
+
decision: "immediate",
|
|
4346
|
+
reason: `session_${status}`,
|
|
4347
|
+
message: `Session is ${status} \u2014 delivery allowed immediately.`
|
|
4348
|
+
};
|
|
4349
|
+
}
|
|
4350
|
+
if (BUSY_DELIVERY_STATUSES.has(status)) {
|
|
4351
|
+
if (opts?.allowBusyInjection) {
|
|
4352
|
+
return {
|
|
4353
|
+
decision: "immediate",
|
|
4354
|
+
reason: `session_${status}_busy_injection_allowed`,
|
|
4355
|
+
message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
|
|
4356
|
+
};
|
|
4357
|
+
}
|
|
4358
|
+
if (status === "waiting_approval" && opts?.kind === "approval") {
|
|
4359
|
+
return {
|
|
4360
|
+
decision: "immediate",
|
|
4361
|
+
reason: "session_waiting_approval_approval_message",
|
|
4362
|
+
message: "Session is waiting for approval \u2014 approval message delivered immediately."
|
|
4363
|
+
};
|
|
4364
|
+
}
|
|
4365
|
+
return {
|
|
4366
|
+
decision: "queued",
|
|
4367
|
+
reason: `session_${status}_busy`,
|
|
4368
|
+
message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
|
|
4369
|
+
};
|
|
4370
|
+
}
|
|
4371
|
+
if (TERMINAL_DELIVERY_STATUSES.has(status)) {
|
|
4372
|
+
return {
|
|
4373
|
+
decision: "rejected",
|
|
4374
|
+
reason: `session_${status}_terminal`,
|
|
4375
|
+
message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
|
|
4376
|
+
};
|
|
4377
|
+
}
|
|
4378
|
+
return {
|
|
4379
|
+
decision: "rejected",
|
|
4380
|
+
reason: "unrecognized_session_status",
|
|
4381
|
+
message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
|
|
4382
|
+
};
|
|
4383
|
+
}
|
|
4384
|
+
function createSessionDelivery(opts) {
|
|
4385
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4386
|
+
const id = (0, import_crypto6.randomUUID)();
|
|
4387
|
+
const record = {
|
|
4388
|
+
id,
|
|
4389
|
+
meshId: opts.meshId,
|
|
4390
|
+
nodeId: opts.nodeId,
|
|
4391
|
+
sessionId: opts.sessionId,
|
|
4392
|
+
providerType: opts.providerType,
|
|
4393
|
+
taskId: opts.taskId,
|
|
4394
|
+
kind: opts.kind,
|
|
4395
|
+
priority: opts.priority ?? 0,
|
|
4396
|
+
message: opts.message,
|
|
4397
|
+
status: opts.status,
|
|
4398
|
+
deliverAfter: opts.deliverAfter,
|
|
4399
|
+
expiresAt: opts.expiresAt,
|
|
4400
|
+
attemptCount: 0,
|
|
4401
|
+
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
4402
|
+
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
4403
|
+
createdAt: now,
|
|
4404
|
+
updatedAt: now
|
|
4405
|
+
};
|
|
4406
|
+
MeshRuntimeStore.getInstance().insertSessionDelivery({
|
|
4407
|
+
id,
|
|
4408
|
+
meshId: opts.meshId,
|
|
4409
|
+
nodeId: opts.nodeId,
|
|
4410
|
+
sessionId: opts.sessionId,
|
|
4411
|
+
providerType: opts.providerType,
|
|
4412
|
+
taskId: opts.taskId,
|
|
4413
|
+
kind: opts.kind,
|
|
4414
|
+
priority: opts.priority ?? 0,
|
|
4415
|
+
message: opts.message,
|
|
4416
|
+
status: opts.status,
|
|
4417
|
+
deliverAfter: opts.deliverAfter,
|
|
4418
|
+
expiresAt: opts.expiresAt,
|
|
4419
|
+
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
4420
|
+
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
4421
|
+
createdAt: now,
|
|
4422
|
+
updatedAt: now
|
|
4423
|
+
});
|
|
4424
|
+
return record;
|
|
4425
|
+
}
|
|
4426
|
+
function updateSessionDeliveryStatus(id, status, opts) {
|
|
4427
|
+
try {
|
|
4428
|
+
MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
|
|
4429
|
+
} catch {
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
function getActiveSessionDeliveries(meshId, sessionId) {
|
|
4433
|
+
try {
|
|
4434
|
+
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
4435
|
+
} catch {
|
|
4436
|
+
return [];
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
function recordCompletionConflict(opts) {
|
|
4440
|
+
try {
|
|
4441
|
+
MeshRuntimeStore.getInstance().recordCompletionConflict({
|
|
4442
|
+
id: (0, import_crypto6.randomUUID)(),
|
|
4443
|
+
meshId: opts.meshId,
|
|
4444
|
+
fingerprint: opts.fingerprint,
|
|
4445
|
+
conflictingTaskId: opts.conflictingTaskId,
|
|
4446
|
+
conflictingSessionId: opts.conflictingSessionId,
|
|
4447
|
+
originalTaskId: opts.originalTaskId,
|
|
4448
|
+
originalSessionId: opts.originalSessionId,
|
|
4449
|
+
event: opts.event,
|
|
4450
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4451
|
+
});
|
|
4452
|
+
} catch {
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
function getRecentCompletionConflicts(meshId, limitMs) {
|
|
4456
|
+
try {
|
|
4457
|
+
return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
|
|
4458
|
+
} catch {
|
|
4459
|
+
return [];
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
var import_crypto6, IMMEDIATE_DELIVERY_STATUSES, BUSY_DELIVERY_STATUSES, TERMINAL_DELIVERY_STATUSES;
|
|
4463
|
+
var init_mesh_delivery_policy = __esm({
|
|
4464
|
+
"src/mesh/mesh-delivery-policy.ts"() {
|
|
4465
|
+
"use strict";
|
|
4466
|
+
import_crypto6 = require("crypto");
|
|
4467
|
+
init_mesh_runtime_store();
|
|
4468
|
+
IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4469
|
+
"idle",
|
|
4470
|
+
"waiting_input",
|
|
4471
|
+
"ready"
|
|
4472
|
+
]);
|
|
4473
|
+
BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4474
|
+
"generating",
|
|
4475
|
+
"running",
|
|
4476
|
+
"streaming",
|
|
4477
|
+
"busy",
|
|
4478
|
+
"starting",
|
|
4479
|
+
"initializing",
|
|
4480
|
+
"waiting_approval"
|
|
4481
|
+
]);
|
|
4482
|
+
TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4483
|
+
"stopped",
|
|
4484
|
+
"failed",
|
|
4485
|
+
"terminated",
|
|
4486
|
+
"exited",
|
|
4487
|
+
"closed",
|
|
4488
|
+
"deleted",
|
|
4489
|
+
"error"
|
|
4490
|
+
]);
|
|
4491
|
+
}
|
|
4492
|
+
});
|
|
4493
|
+
|
|
4147
4494
|
// src/mesh/mesh-events.ts
|
|
4148
4495
|
var mesh_events_exports = {};
|
|
4149
4496
|
__export(mesh_events_exports, {
|
|
@@ -4174,7 +4521,7 @@ function __resetIdleAutoFastForwardForTests() {
|
|
|
4174
4521
|
}
|
|
4175
4522
|
function sweepExpiredRemoteIdleSessions() {
|
|
4176
4523
|
try {
|
|
4177
|
-
|
|
4524
|
+
MeshRuntimeStore.getInstance().pruneExpiredRemoteIdleSessions();
|
|
4178
4525
|
} catch {
|
|
4179
4526
|
}
|
|
4180
4527
|
}
|
|
@@ -4450,14 +4797,14 @@ function shouldSuppressIntentionalCleanupStop(args) {
|
|
|
4450
4797
|
}
|
|
4451
4798
|
function hasFingerprintSeen(fingerprint) {
|
|
4452
4799
|
try {
|
|
4453
|
-
return
|
|
4800
|
+
return MeshRuntimeStore.getInstance().hasCompletionFingerprint(fingerprint);
|
|
4454
4801
|
} catch {
|
|
4455
4802
|
return false;
|
|
4456
4803
|
}
|
|
4457
4804
|
}
|
|
4458
4805
|
function recordFingerprintSeen(fingerprint) {
|
|
4459
4806
|
try {
|
|
4460
|
-
const db =
|
|
4807
|
+
const db = MeshRuntimeStore.getInstance();
|
|
4461
4808
|
db.recordCompletionFingerprint(fingerprint, RECENT_COMPLETION_FINGERPRINT_TTL_MS);
|
|
4462
4809
|
db.sweepExpiredFingerprints();
|
|
4463
4810
|
} catch {
|
|
@@ -4488,7 +4835,18 @@ function buildMeshCompletionFingerprint(args) {
|
|
|
4488
4835
|
function isDuplicateMeshCompletionEvent(args) {
|
|
4489
4836
|
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
4490
4837
|
if (!fingerprint) return false;
|
|
4491
|
-
if (hasFingerprintSeen(fingerprint))
|
|
4838
|
+
if (hasFingerprintSeen(fingerprint)) {
|
|
4839
|
+
if (args.taskId) {
|
|
4840
|
+
recordCompletionConflict({
|
|
4841
|
+
meshId: args.meshId,
|
|
4842
|
+
fingerprint,
|
|
4843
|
+
conflictingTaskId: args.taskId,
|
|
4844
|
+
conflictingSessionId: args.sessionId,
|
|
4845
|
+
event: args.event
|
|
4846
|
+
});
|
|
4847
|
+
}
|
|
4848
|
+
return true;
|
|
4849
|
+
}
|
|
4492
4850
|
recordFingerprintSeen(fingerprint);
|
|
4493
4851
|
return false;
|
|
4494
4852
|
}
|
|
@@ -4739,20 +5097,33 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
4739
5097
|
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
4740
5098
|
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
4741
5099
|
if (!isLocalNode) {
|
|
5100
|
+
const delivery2 = createSessionDelivery({
|
|
5101
|
+
meshId,
|
|
5102
|
+
nodeId,
|
|
5103
|
+
sessionId,
|
|
5104
|
+
providerType,
|
|
5105
|
+
taskId: task.id,
|
|
5106
|
+
kind: "task",
|
|
5107
|
+
message: task.message,
|
|
5108
|
+
status: "delivering"
|
|
5109
|
+
});
|
|
4742
5110
|
components.dispatchMeshCommand(node.daemonId, "agent_command", {
|
|
4743
5111
|
targetSessionId: sessionId,
|
|
4744
5112
|
cliType: providerType,
|
|
4745
5113
|
action: "send_chat",
|
|
4746
5114
|
message: task.message
|
|
5115
|
+
}).then(() => {
|
|
5116
|
+
updateSessionDeliveryStatus(delivery2.id, "delivered");
|
|
4747
5117
|
}).catch((e) => {
|
|
4748
5118
|
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
5119
|
+
updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
4749
5120
|
updateTaskStatus(meshId, task.id, "pending");
|
|
4750
5121
|
try {
|
|
4751
5122
|
appendLedgerEntry(meshId, {
|
|
4752
5123
|
kind: "dispatch_failed",
|
|
4753
5124
|
nodeId,
|
|
4754
5125
|
sessionId,
|
|
4755
|
-
payload: { taskId: task.id, error: e?.message, retryable: true }
|
|
5126
|
+
payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
|
|
4756
5127
|
});
|
|
4757
5128
|
} catch {
|
|
4758
5129
|
}
|
|
@@ -4760,13 +5131,26 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
4760
5131
|
return true;
|
|
4761
5132
|
}
|
|
4762
5133
|
}
|
|
5134
|
+
const delivery = createSessionDelivery({
|
|
5135
|
+
meshId,
|
|
5136
|
+
nodeId,
|
|
5137
|
+
sessionId,
|
|
5138
|
+
providerType,
|
|
5139
|
+
taskId: task.id,
|
|
5140
|
+
kind: "task",
|
|
5141
|
+
message: task.message,
|
|
5142
|
+
status: "delivering"
|
|
5143
|
+
});
|
|
4763
5144
|
components.cliManager.handleCliCommand("agent_command", {
|
|
4764
5145
|
targetSessionId: sessionId,
|
|
4765
5146
|
cliType: providerType,
|
|
4766
5147
|
action: "send_chat",
|
|
4767
5148
|
message: task.message
|
|
5149
|
+
}).then(() => {
|
|
5150
|
+
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
4768
5151
|
}).catch((e) => {
|
|
4769
5152
|
LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
|
|
5153
|
+
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
4770
5154
|
updateTaskStatus(meshId, task.id, "failed");
|
|
4771
5155
|
});
|
|
4772
5156
|
return true;
|
|
@@ -5077,7 +5461,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
5077
5461
|
}
|
|
5078
5462
|
let remoteSessions = [];
|
|
5079
5463
|
try {
|
|
5080
|
-
remoteSessions =
|
|
5464
|
+
remoteSessions = MeshRuntimeStore.getInstance().getRemoteIdleSessions();
|
|
5081
5465
|
} catch {
|
|
5082
5466
|
}
|
|
5083
5467
|
for (const idle of remoteSessions) {
|
|
@@ -5087,7 +5471,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
5087
5471
|
const assigned = tryAssignQueueTask(components, meshId, idle.nodeId, idle.sessionId, idle.providerType);
|
|
5088
5472
|
if (assigned) {
|
|
5089
5473
|
try {
|
|
5090
|
-
|
|
5474
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(idle.nodeId, idle.sessionId);
|
|
5091
5475
|
} catch {
|
|
5092
5476
|
}
|
|
5093
5477
|
}
|
|
@@ -5289,7 +5673,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5289
5673
|
if (intentionalCleanupStop) {
|
|
5290
5674
|
if (eventSessionId && eventNodeId) {
|
|
5291
5675
|
try {
|
|
5292
|
-
|
|
5676
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(eventNodeId, eventSessionId);
|
|
5293
5677
|
} catch {
|
|
5294
5678
|
}
|
|
5295
5679
|
}
|
|
@@ -5371,7 +5755,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5371
5755
|
finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0,
|
|
5372
5756
|
// Scope dedup to the coordinator daemon so two coordinators for the same mesh
|
|
5373
5757
|
// don't suppress each other's completion events via shared fingerprint table.
|
|
5374
|
-
coordinatorDaemonId: workerCoordinatorDaemonId || void 0
|
|
5758
|
+
coordinatorDaemonId: workerCoordinatorDaemonId || void 0,
|
|
5759
|
+
taskId: readNonEmptyString2(args.metadataEvent.taskId) || void 0,
|
|
5760
|
+
nodeId: eventNodeId || void 0
|
|
5375
5761
|
});
|
|
5376
5762
|
if (duplicateCompletion) {
|
|
5377
5763
|
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
@@ -5387,7 +5773,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5387
5773
|
providerSessionId: readNonEmptyString2(args.metadataEvent.providerSessionId) || void 0,
|
|
5388
5774
|
timestamp: eventTimestamp,
|
|
5389
5775
|
finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0,
|
|
5390
|
-
coordinatorDaemonId: workerCoordinatorDaemonId || void 0
|
|
5776
|
+
coordinatorDaemonId: workerCoordinatorDaemonId || void 0,
|
|
5777
|
+
taskId: readNonEmptyString2(args.metadataEvent.taskId) || void 0,
|
|
5778
|
+
nodeId: eventNodeId || void 0
|
|
5391
5779
|
});
|
|
5392
5780
|
if (duplicateStopped) {
|
|
5393
5781
|
LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
@@ -5457,14 +5845,14 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5457
5845
|
if (sessionId && nodeId && providerType) {
|
|
5458
5846
|
sweepExpiredRemoteIdleSessions();
|
|
5459
5847
|
try {
|
|
5460
|
-
|
|
5848
|
+
MeshRuntimeStore.getInstance().setRemoteIdleSession(nodeId, sessionId, providerType, Date.now() + REMOTE_IDLE_SESSION_TTL_MS);
|
|
5461
5849
|
} catch {
|
|
5462
5850
|
}
|
|
5463
5851
|
setImmediate(() => {
|
|
5464
5852
|
maybeAutoFastForwardIdleNode(components, { meshId: args.meshId, nodeId, sessionId, providerType }).finally(() => {
|
|
5465
5853
|
try {
|
|
5466
5854
|
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
5467
|
-
if (assigned)
|
|
5855
|
+
if (assigned) MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
|
|
5468
5856
|
} catch (e) {
|
|
5469
5857
|
LOG.warn("MeshQueue", `Failed to assign idle queue task after maintenance for ${nodeId}: ${e?.message || e}`);
|
|
5470
5858
|
}
|
|
@@ -5476,7 +5864,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5476
5864
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
5477
5865
|
if (sessionId && nodeId) {
|
|
5478
5866
|
try {
|
|
5479
|
-
|
|
5867
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
|
|
5480
5868
|
} catch {
|
|
5481
5869
|
}
|
|
5482
5870
|
}
|
|
@@ -5488,7 +5876,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5488
5876
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
5489
5877
|
if (sessionId && nodeId) {
|
|
5490
5878
|
try {
|
|
5491
|
-
|
|
5879
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
|
|
5492
5880
|
} catch {
|
|
5493
5881
|
}
|
|
5494
5882
|
}
|
|
@@ -5762,8 +6150,9 @@ var init_mesh_events = __esm({
|
|
|
5762
6150
|
init_logger();
|
|
5763
6151
|
init_mesh_ledger();
|
|
5764
6152
|
init_mesh_work_queue();
|
|
5765
|
-
|
|
6153
|
+
init_mesh_runtime_store();
|
|
5766
6154
|
init_mesh_fast_forward();
|
|
6155
|
+
init_mesh_delivery_policy();
|
|
5767
6156
|
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
5768
6157
|
meshByWorkspaceCache = /* @__PURE__ */ new Map();
|
|
5769
6158
|
MESH_WORKSPACE_CACHE_TTL_MS = 5e3;
|
|
@@ -8710,11 +9099,12 @@ var init_cli_state_engine = __esm({
|
|
|
8710
9099
|
}
|
|
8711
9100
|
applyGenerating(ctx) {
|
|
8712
9101
|
const { modal, parsedMessages, lastParsedAssistant, parsedStatus, prevStatus } = ctx;
|
|
9102
|
+
const noActiveTurn = !this.currentTurnScope;
|
|
9103
|
+
if (!this.isWaitingForResponse && noActiveTurn && !modal) return;
|
|
8713
9104
|
this.clearIdleFinishCandidate("generating");
|
|
8714
9105
|
this.cancelPendingIdleFinish("generating_signal_returned");
|
|
8715
9106
|
const snap = this.transport.getSnapshot();
|
|
8716
9107
|
const effectiveScreenText = snap.screenText || snap.accumulatedBuffer;
|
|
8717
|
-
const noActiveTurn = !this.currentTurnScope;
|
|
8718
9108
|
const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
|
|
8719
9109
|
const parsedShowsLiveProgress = parsedStatus === "generating" && !!lastParsedAssistant;
|
|
8720
9110
|
if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveProgress) return;
|
|
@@ -8974,7 +9364,25 @@ var init_cli_state_engine = __esm({
|
|
|
8974
9364
|
const parsedStatus = typeof parsed?.status === "string" ? parsed.status.trim() : "";
|
|
8975
9365
|
if (parsedStatus !== "idle") return true;
|
|
8976
9366
|
if (parsed?.activeModal || parsed?.modal) return true;
|
|
8977
|
-
|
|
9367
|
+
const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
|
|
9368
|
+
let lastUserIdx = -1;
|
|
9369
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
9370
|
+
if (messages[i]?.role === "user") {
|
|
9371
|
+
lastUserIdx = i;
|
|
9372
|
+
break;
|
|
9373
|
+
}
|
|
9374
|
+
}
|
|
9375
|
+
if (lastUserIdx < 0) {
|
|
9376
|
+
if (messages.length === 0) return false;
|
|
9377
|
+
return !this.parsedStatusHasFinalStandardAssistantMessage(parsed);
|
|
9378
|
+
}
|
|
9379
|
+
const hasCurrentTurnAssistant = messages.slice(lastUserIdx + 1).some((m) => {
|
|
9380
|
+
if (!m || m.role !== "assistant") return false;
|
|
9381
|
+
if (typeof m.content !== "string" || !m.content.trim()) return false;
|
|
9382
|
+
const kind = typeof m.kind === "string" && m.kind.trim() ? m.kind.trim() : "standard";
|
|
9383
|
+
return kind === "standard" && m.meta?.streaming !== true;
|
|
9384
|
+
});
|
|
9385
|
+
return !hasCurrentTurnAssistant;
|
|
8978
9386
|
}
|
|
8979
9387
|
rescheduleTranscriptFinishCheck(reason) {
|
|
8980
9388
|
this.clearIdleFinishCandidate(reason);
|
|
@@ -11296,6 +11704,7 @@ __export(index_exports, {
|
|
|
11296
11704
|
createInteractionId: () => createInteractionId,
|
|
11297
11705
|
createMesh: () => createMesh,
|
|
11298
11706
|
createNativeHistoryDispatcher: () => createNativeHistoryDispatcher,
|
|
11707
|
+
createSessionDelivery: () => createSessionDelivery,
|
|
11299
11708
|
createWorktree: () => createWorktree,
|
|
11300
11709
|
deleteMesh: () => deleteMesh,
|
|
11301
11710
|
detectAllVersions: () => detectAllVersions,
|
|
@@ -11319,6 +11728,7 @@ __export(index_exports, {
|
|
|
11319
11728
|
forwardAgentStreamsToIdeInstance: () => forwardAgentStreamsToIdeInstance,
|
|
11320
11729
|
getAIExtensions: () => getAIExtensions,
|
|
11321
11730
|
getActiveDirectDispatches: () => getActiveDirectDispatches,
|
|
11731
|
+
getActiveSessionDeliveries: () => getActiveSessionDeliveries,
|
|
11322
11732
|
getAvailableIdeIds: () => getAvailableIdeIds,
|
|
11323
11733
|
getCoordinatorForSession: () => getCoordinatorForSession,
|
|
11324
11734
|
getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
|
|
@@ -11341,6 +11751,7 @@ __export(index_exports, {
|
|
|
11341
11751
|
getQueue: () => getQueue,
|
|
11342
11752
|
getRecentActivity: () => getRecentActivity,
|
|
11343
11753
|
getRecentCommands: () => getRecentCommands,
|
|
11754
|
+
getRecentCompletionConflicts: () => getRecentCompletionConflicts,
|
|
11344
11755
|
getRecentDebugTrace: () => getRecentDebugTrace,
|
|
11345
11756
|
getRecentLogs: () => getRecentLogs,
|
|
11346
11757
|
getSavedProviderSessions: () => getSavedProviderSessions,
|
|
@@ -11428,6 +11839,7 @@ __export(index_exports, {
|
|
|
11428
11839
|
readLedgerEntries: () => readLedgerEntries,
|
|
11429
11840
|
readLedgerSlice: () => readLedgerSlice,
|
|
11430
11841
|
reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
|
|
11842
|
+
recordCompletionConflict: () => recordCompletionConflict,
|
|
11431
11843
|
recordDebugTrace: () => recordDebugTrace,
|
|
11432
11844
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
11433
11845
|
registerMeshCoordinator: () => registerMeshCoordinator,
|
|
@@ -11441,6 +11853,7 @@ __export(index_exports, {
|
|
|
11441
11853
|
resolveChatMessageKind: () => resolveChatMessageKind,
|
|
11442
11854
|
resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
|
|
11443
11855
|
resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
|
|
11856
|
+
resolveDeliveryDecision: () => resolveDeliveryDecision,
|
|
11444
11857
|
resolveGitRepository: () => resolveGitRepository,
|
|
11445
11858
|
resolveMeshHostStatus: () => resolveMeshHostStatus,
|
|
11446
11859
|
resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
|
|
@@ -11470,6 +11883,7 @@ __export(index_exports, {
|
|
|
11470
11883
|
updateDirectDispatchStatus: () => updateDirectDispatchStatus,
|
|
11471
11884
|
updateMesh: () => updateMesh,
|
|
11472
11885
|
updateNode: () => updateNode,
|
|
11886
|
+
updateSessionDeliveryStatus: () => updateSessionDeliveryStatus,
|
|
11473
11887
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
11474
11888
|
updateTaskStatus: () => updateTaskStatus,
|
|
11475
11889
|
upsertSavedProviderSession: () => upsertSavedProviderSession,
|
|
@@ -11742,14 +12156,19 @@ function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
|
|
|
11742
12156
|
if (question.multiSelect) throw new Error("Claude TUI multi-select prompts are not supported yet");
|
|
11743
12157
|
const answer = response.answers[question.questionId];
|
|
11744
12158
|
if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
|
|
11745
|
-
|
|
11746
|
-
if (
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
|
|
11750
|
-
steps.push(
|
|
12159
|
+
const freeformText = answer.freeformText?.trim() ?? "";
|
|
12160
|
+
if (freeformText) {
|
|
12161
|
+
const typeOptionIndex = question.options.findIndex((o) => /^Type something\.?$/i.test(o.label));
|
|
12162
|
+
const optionNumber = typeOptionIndex >= 0 ? typeOptionIndex + 1 : question.options.length;
|
|
12163
|
+
steps.push(String(optionNumber));
|
|
12164
|
+
for (const ch of freeformText) steps.push(ch);
|
|
12165
|
+
steps.push("\r");
|
|
12166
|
+
} else {
|
|
12167
|
+
if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
|
|
12168
|
+
const selectedIndex = question.options.findIndex((option) => option.label === answer.selectedLabels[0]);
|
|
12169
|
+
if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
|
|
12170
|
+
steps.push(String(selectedIndex + 1));
|
|
11751
12171
|
}
|
|
11752
|
-
steps.push("\r");
|
|
11753
12172
|
}
|
|
11754
12173
|
steps.push("\r");
|
|
11755
12174
|
return steps;
|
|
@@ -14316,6 +14735,7 @@ function buildMeshAsyncRefineJobs(args) {
|
|
|
14316
14735
|
// src/index.ts
|
|
14317
14736
|
init_mesh_host_ownership();
|
|
14318
14737
|
init_mesh_events();
|
|
14738
|
+
init_mesh_delivery_policy();
|
|
14319
14739
|
|
|
14320
14740
|
// src/mesh/p2p-relay-failure.ts
|
|
14321
14741
|
var NO_FALLBACK_REASON = "Repo Mesh command/data-plane is P2P-only; WS/REST command fallback is intentionally disabled to preserve the transport boundary.";
|
|
@@ -20082,6 +20502,7 @@ function normalizeManagedStatus(status, opts) {
|
|
|
20082
20502
|
if (hasApprovalButtons(opts?.activeModal)) return "waiting_approval";
|
|
20083
20503
|
const normalized = String(status || "idle").trim().toLowerCase();
|
|
20084
20504
|
if (normalized === "waiting_approval") return "waiting_approval";
|
|
20505
|
+
if (normalized === "waiting_choice") return "waiting_choice";
|
|
20085
20506
|
if (WORKING_STATUSES.has(normalized)) return "generating";
|
|
20086
20507
|
if (normalized === "error") return "error";
|
|
20087
20508
|
if (normalized === "stopped") return "stopped";
|
|
@@ -26100,10 +26521,47 @@ function resolveSections(spec, lines) {
|
|
|
26100
26521
|
for (const sec of spec.layout.sections) {
|
|
26101
26522
|
let from = 0;
|
|
26102
26523
|
let to = total;
|
|
26103
|
-
if (sec.
|
|
26524
|
+
if (sec.anchor_regex !== void 0) {
|
|
26525
|
+
try {
|
|
26526
|
+
const re = new RegExp(sec.anchor_regex, sec.anchor_flags ?? "");
|
|
26527
|
+
const prevRe = sec.anchor_context?.prev !== void 0 ? new RegExp(sec.anchor_context.prev, sec.anchor_context.prev_flags ?? "") : null;
|
|
26528
|
+
const nextRe = sec.anchor_context?.next !== void 0 ? new RegExp(sec.anchor_context.next, sec.anchor_context.next_flags ?? "") : null;
|
|
26529
|
+
const matches = (i) => re.test(lines[i]) && (prevRe === null || i > 0 && prevRe.test(lines[i - 1])) && (nextRe === null || i < total - 1 && nextRe.test(lines[i + 1]));
|
|
26530
|
+
let idx = -1;
|
|
26531
|
+
if (sec.anchor_last) {
|
|
26532
|
+
for (let i = total - 1; i >= 0; i--) {
|
|
26533
|
+
if (matches(i)) {
|
|
26534
|
+
idx = i;
|
|
26535
|
+
break;
|
|
26536
|
+
}
|
|
26537
|
+
}
|
|
26538
|
+
} else {
|
|
26539
|
+
for (let i = 0; i < total; i++) {
|
|
26540
|
+
if (matches(i)) {
|
|
26541
|
+
idx = i;
|
|
26542
|
+
break;
|
|
26543
|
+
}
|
|
26544
|
+
}
|
|
26545
|
+
}
|
|
26546
|
+
if (idx !== -1) {
|
|
26547
|
+
from = idx;
|
|
26548
|
+
to = total;
|
|
26549
|
+
if (sec.until_regex !== void 0) {
|
|
26550
|
+
try {
|
|
26551
|
+
const ure = new RegExp(sec.until_regex, sec.until_regex_flags ?? "");
|
|
26552
|
+
const end = lines.findIndex((l, i) => i > idx && ure.test(l));
|
|
26553
|
+
if (end !== -1) to = end;
|
|
26554
|
+
} catch {
|
|
26555
|
+
}
|
|
26556
|
+
} else if (sec.lines !== void 0) {
|
|
26557
|
+
to = Math.min(total, from + sec.lines);
|
|
26558
|
+
}
|
|
26559
|
+
}
|
|
26560
|
+
} catch {
|
|
26561
|
+
}
|
|
26562
|
+
} else if (sec.from_top !== void 0) {
|
|
26104
26563
|
from = resolveSize(sec.from_top, total);
|
|
26105
|
-
}
|
|
26106
|
-
if (sec.from_bottom !== void 0) {
|
|
26564
|
+
} else if (sec.from_bottom !== void 0) {
|
|
26107
26565
|
const sz = resolveSize(sec.from_bottom, total);
|
|
26108
26566
|
from = total - sz;
|
|
26109
26567
|
to = total;
|
|
@@ -26421,6 +26879,9 @@ var SCHEMA = {
|
|
|
26421
26879
|
"type": "string",
|
|
26422
26880
|
"minLength": 1
|
|
26423
26881
|
},
|
|
26882
|
+
"requiresFinalAssistantBeforeIdle": {
|
|
26883
|
+
"type": "boolean"
|
|
26884
|
+
},
|
|
26424
26885
|
"debounce": {
|
|
26425
26886
|
"type": "object",
|
|
26426
26887
|
"additionalProperties": false,
|
|
@@ -26435,7 +26896,8 @@ var SCHEMA = {
|
|
|
26435
26896
|
"section": { "type": "string", "minLength": 1 },
|
|
26436
26897
|
"regex": { "type": "string", "minLength": 1 },
|
|
26437
26898
|
"flags": { "type": "string" },
|
|
26438
|
-
"hold_ms": { "type": "integer", "minimum": 0 }
|
|
26899
|
+
"hold_ms": { "type": "integer", "minimum": 0 },
|
|
26900
|
+
"force_after_ms": { "type": "integer", "minimum": 0 }
|
|
26439
26901
|
}
|
|
26440
26902
|
}
|
|
26441
26903
|
}
|
|
@@ -26483,7 +26945,23 @@ var SCHEMA = {
|
|
|
26483
26945
|
"type": "string"
|
|
26484
26946
|
}
|
|
26485
26947
|
}
|
|
26486
|
-
}
|
|
26948
|
+
},
|
|
26949
|
+
"anchor_regex": { "type": "string", "minLength": 1 },
|
|
26950
|
+
"anchor_flags": { "type": "string" },
|
|
26951
|
+
"anchor_last": { "type": "boolean" },
|
|
26952
|
+
"anchor_context": {
|
|
26953
|
+
"type": "object",
|
|
26954
|
+
"additionalProperties": false,
|
|
26955
|
+
"properties": {
|
|
26956
|
+
"prev": { "type": "string" },
|
|
26957
|
+
"prev_flags": { "type": "string" },
|
|
26958
|
+
"next": { "type": "string" },
|
|
26959
|
+
"next_flags": { "type": "string" }
|
|
26960
|
+
}
|
|
26961
|
+
},
|
|
26962
|
+
"lines": { "type": "integer", "minimum": 1 },
|
|
26963
|
+
"until_regex": { "type": "string", "minLength": 1 },
|
|
26964
|
+
"until_regex_flags": { "type": "string" }
|
|
26487
26965
|
}
|
|
26488
26966
|
},
|
|
26489
26967
|
"sectionRegex": {
|
|
@@ -26919,6 +27397,7 @@ function resolveSpecPath(providerDir) {
|
|
|
26919
27397
|
}
|
|
26920
27398
|
|
|
26921
27399
|
// src/providers/spec/driver.ts
|
|
27400
|
+
init_logger();
|
|
26922
27401
|
var STARTUP_GRACE_MS = 2500;
|
|
26923
27402
|
var BUSY_HOLD_MS = 6e3;
|
|
26924
27403
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
@@ -26946,9 +27425,16 @@ function matchesCompletionIdleRule(spec, ev, screen) {
|
|
|
26946
27425
|
return null;
|
|
26947
27426
|
}
|
|
26948
27427
|
}
|
|
26949
|
-
function matchesCompletionIdleTargetState(spec, ev, screen) {
|
|
27428
|
+
function matchesCompletionIdleTargetState(spec, ev, screen, cursor) {
|
|
26950
27429
|
const target = spec.states.find((state) => state.id === spec.default_state) ?? spec.states.find((state) => state.id === "idle");
|
|
26951
|
-
if (!target?.when
|
|
27430
|
+
if (!target?.when) return false;
|
|
27431
|
+
const hasCursorGuard = target.when.cursor_row_min !== void 0 || target.when.cursor_row_max !== void 0 || target.when.cursor_col_min !== void 0 || target.when.cursor_col_max !== void 0;
|
|
27432
|
+
if (hasCursorGuard && cursor !== void 0) {
|
|
27433
|
+
const { cursor_row_min, cursor_row_max, cursor_col_min, cursor_col_max } = target.when;
|
|
27434
|
+
const cursorOk = (cursor_row_min === void 0 || cursor.row >= cursor_row_min) && (cursor_row_max === void 0 || cursor.row <= cursor_row_max) && (cursor_col_min === void 0 || cursor.col >= cursor_col_min) && (cursor_col_max === void 0 || cursor.col <= cursor_col_max);
|
|
27435
|
+
if (cursorOk) return true;
|
|
27436
|
+
}
|
|
27437
|
+
if (!target.when.regex) return false;
|
|
26952
27438
|
const haystack = target.when.section ? ev.sections.find((section) => section.id === target.when.section)?.text ?? "" : screen;
|
|
26953
27439
|
if (!haystack) return false;
|
|
26954
27440
|
try {
|
|
@@ -27110,6 +27596,7 @@ var SpecDriver = class {
|
|
|
27110
27596
|
if (this.busyExpiryTimer) clearTimeout(this.busyExpiryTimer);
|
|
27111
27597
|
this.busyExpiryTimer = setTimeout(() => {
|
|
27112
27598
|
this.busyExpiryTimer = null;
|
|
27599
|
+
LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] busyExpiry fired holdMs=${holdMs}`);
|
|
27113
27600
|
this.reevaluate();
|
|
27114
27601
|
}, Math.max(holdMs + 50, 100));
|
|
27115
27602
|
}
|
|
@@ -27134,11 +27621,16 @@ var SpecDriver = class {
|
|
|
27134
27621
|
if (completionKey !== this.completionIdleKey) {
|
|
27135
27622
|
this.completionIdleKey = completionKey;
|
|
27136
27623
|
this.completionIdleFirstSeenAt = now;
|
|
27624
|
+
LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] completion_idle_after matched: key="${completionKey}"`);
|
|
27137
27625
|
}
|
|
27138
27626
|
const holdMs = Math.max(0, completionIdleRule.hold_ms || 0);
|
|
27627
|
+
const forceAfterMs = typeof completionIdleRule.force_after_ms === "number" ? completionIdleRule.force_after_ms : null;
|
|
27139
27628
|
const ageMs = now - this.completionIdleFirstSeenAt;
|
|
27140
27629
|
if (ageMs >= holdMs) {
|
|
27141
|
-
|
|
27630
|
+
const targetMatches = matchesCompletionIdleTargetState(this.spec, ev, screen, cursor);
|
|
27631
|
+
const forced = !targetMatches && forceAfterMs !== null && ageMs >= holdMs + forceAfterMs;
|
|
27632
|
+
LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] completion_idle_after hold expired ageMs=${ageMs} targetState=${targetMatches} forced=${forced} screenTail="${screen.split(/\r?\n/).slice(-3).join("\\n").slice(-200)}"`);
|
|
27633
|
+
if (targetMatches || forced) {
|
|
27142
27634
|
const idle = this.spec.states.find((state) => state.id === this.spec.default_state) ?? this.spec.states.find((state) => state.id === "idle");
|
|
27143
27635
|
evState = idle ? { id: idle.id, label: idle.label, title: null } : { id: "idle", label: "Ready", title: null };
|
|
27144
27636
|
} else {
|
|
@@ -28279,16 +28771,19 @@ var CliProviderInstance = class {
|
|
|
28279
28771
|
controlValues: this.controlValues
|
|
28280
28772
|
});
|
|
28281
28773
|
const activeChatStatus = parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : adapterStatus.status !== "idle" ? visibleStatus : suppressStaleParsedBusyStatus ? visibleStatus : parsedChatStatus || visibleStatus;
|
|
28774
|
+
const hasInteractivePrompt = !!this.activeInteractivePrompt;
|
|
28775
|
+
const finalStatus = hasInteractivePrompt ? "waiting_choice" : visibleStatus;
|
|
28776
|
+
const finalChatStatus = hasInteractivePrompt ? "waiting_choice" : activeChatStatus;
|
|
28282
28777
|
return {
|
|
28283
28778
|
type: this.type,
|
|
28284
28779
|
name: this.provider.name,
|
|
28285
28780
|
category: "cli",
|
|
28286
|
-
status:
|
|
28781
|
+
status: finalStatus,
|
|
28287
28782
|
mode: this.presentationMode,
|
|
28288
28783
|
activeChat: {
|
|
28289
28784
|
id: activeChatId,
|
|
28290
28785
|
title: parsedStatus?.title || dirName,
|
|
28291
|
-
status:
|
|
28786
|
+
status: finalChatStatus,
|
|
28292
28787
|
messages: statusMessages,
|
|
28293
28788
|
activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
28294
28789
|
activeInteractivePrompt: this.activeInteractivePrompt,
|
|
@@ -28759,6 +29254,7 @@ var CliProviderInstance = class {
|
|
|
28759
29254
|
const adapterOwnsMessagesElsewhere = this.adapter?.chatMessagesOwnedExternally === true;
|
|
28760
29255
|
const finalAssistantEvidence = this.completionFinalAssistantEvidence(parsed?.messages);
|
|
28761
29256
|
const allowMissingAssistantTimeout = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
|
|
29257
|
+
LOG.debug("CLI", `[${this.type}] finalAssistantEvidence: present=${finalAssistantEvidence.present} source=${finalAssistantEvidence.source} adapterOwnsMessagesElsewhere=${adapterOwnsMessagesElsewhere} parsedStatus=${parsedStatus}`);
|
|
28762
29258
|
if (!finalAssistantEvidence.present) {
|
|
28763
29259
|
if (adapterOwnsMessagesElsewhere) {
|
|
28764
29260
|
if (finalAssistantEvidence.source === "external-native") {
|
|
@@ -28767,6 +29263,10 @@ var CliProviderInstance = class {
|
|
|
28767
29263
|
LOG.info("CLI", `[${this.type}] external transcript probe: msgCount=${probe.msgCount} lastRole=${probe.lastRole || "none"} lastKind=${probe.lastKind || "none"} contentLen=${probe.contentLen} sourceMtime=${probe.sourceMtimeMs ?? "unknown"} mtimeAge=${probe.mtimeAgeMs ?? "unknown"}ms`);
|
|
28768
29264
|
pending.loggedTranscriptProbe = true;
|
|
28769
29265
|
}
|
|
29266
|
+
LOG.debug("CLI", `[${this.type}] external-native probe result: lastRole=${probe?.lastRole} contentLen=${probe?.contentLen}`);
|
|
29267
|
+
if (probe?.lastRole === "assistant" && (probe.contentLen ?? 0) > 0) {
|
|
29268
|
+
return null;
|
|
29269
|
+
}
|
|
28770
29270
|
if (this.type === "antigravity-cli") {
|
|
28771
29271
|
return null;
|
|
28772
29272
|
}
|
|
@@ -28776,6 +29276,7 @@ var CliProviderInstance = class {
|
|
|
28776
29276
|
return { reason: "missing_final_assistant", terminal: true, allowTimeout: allowMissingAssistantTimeout };
|
|
28777
29277
|
}
|
|
28778
29278
|
} else {
|
|
29279
|
+
LOG.debug("CLI", `[${this.type}] missing_final_assistant (not ownsExternal) requiresFinalAssistant=${!!this.provider.requiresFinalAssistantBeforeIdle}`);
|
|
28779
29280
|
return {
|
|
28780
29281
|
reason: "missing_final_assistant",
|
|
28781
29282
|
terminal: this.provider.requiresFinalAssistantBeforeIdle === true,
|
|
@@ -28809,6 +29310,7 @@ var CliProviderInstance = class {
|
|
|
28809
29310
|
const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
|
|
28810
29311
|
const externalNativeFinal = this.getExternalNativeFinalReconciliation(void 0, latestStatus);
|
|
28811
29312
|
const latestVisibleStatus = externalNativeFinal && isCliGeneratingLikeStatus(latestStatus.status) ? "idle" : latestAutoApproveActive ? "generating" : latestStatus.status;
|
|
29313
|
+
LOG.debug("CLI", `[${this.type}] flush attempt: adapterStatus=${latestStatus.status} latestVisible=${latestVisibleStatus} externalNativeFinal=${!!externalNativeFinal} generatingStartedAt=${this.generatingStartedAt} isWaitingForResponse=${!!this.adapter?.isWaitingForResponse} hasPartial=${!!this.adapter.getPartialResponse?.()}`);
|
|
28812
29314
|
if (latestVisibleStatus !== "idle") {
|
|
28813
29315
|
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
|
|
28814
29316
|
this.completedDebouncePending = null;
|
|
@@ -28819,6 +29321,7 @@ var CliProviderInstance = class {
|
|
|
28819
29321
|
if (block2) {
|
|
28820
29322
|
const blockReason = block2.reason;
|
|
28821
29323
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
29324
|
+
LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
28822
29325
|
if (block2.terminal && !block2.allowTimeout || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
|
|
28823
29326
|
if (pending.loggedBlockReason !== blockReason) {
|
|
28824
29327
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
@@ -28933,9 +29436,13 @@ var CliProviderInstance = class {
|
|
|
28933
29436
|
if (newStatus !== this.lastStatus) {
|
|
28934
29437
|
LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
|
|
28935
29438
|
if (this.lastStatus === "idle" && newStatus === "generating") {
|
|
29439
|
+
if (this.completedDebouncePending && this.generatingStartedAt === 0) {
|
|
29440
|
+
LOG.debug("CLI", `[${this.type}] ignoring post-completion PTY generating blip (generatingStartedAt=0)`);
|
|
29441
|
+
return;
|
|
29442
|
+
}
|
|
28936
29443
|
this.suppressIdleHistoryReplay = false;
|
|
28937
29444
|
if (this.completedDebouncePending) {
|
|
28938
|
-
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating)`);
|
|
29445
|
+
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating) generatingStartedAt=${this.generatingStartedAt} isWaitingForResponse=${!!this.adapter?.isWaitingForResponse}`);
|
|
28939
29446
|
if (this.completedDebounceTimer) {
|
|
28940
29447
|
clearTimeout(this.completedDebounceTimer);
|
|
28941
29448
|
this.completedDebounceTimer = null;
|
|
@@ -29033,7 +29540,10 @@ var CliProviderInstance = class {
|
|
|
29033
29540
|
firstObservedAt: now,
|
|
29034
29541
|
previousStatus: this.lastStatus
|
|
29035
29542
|
};
|
|
29036
|
-
this.
|
|
29543
|
+
const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
|
|
29544
|
+
const flushDelay = ownsExternalHistory ? 0 : 3e3;
|
|
29545
|
+
LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
|
|
29546
|
+
this.scheduleCompletedDebounceFlush(flushDelay);
|
|
29037
29547
|
}
|
|
29038
29548
|
} else if (newStatus === "idle" && this.lastStatus === "starting") {
|
|
29039
29549
|
this.pushEvent({ event: "agent:ready", chatTitle, timestamp: now });
|
|
@@ -41435,9 +41945,9 @@ var DaemonCommandRouter = class {
|
|
|
41435
41945
|
});
|
|
41436
41946
|
let node;
|
|
41437
41947
|
if (meshRecord.inline) {
|
|
41438
|
-
const { randomUUID:
|
|
41948
|
+
const { randomUUID: randomUUID12 } = await import("crypto");
|
|
41439
41949
|
node = {
|
|
41440
|
-
id: `node_${
|
|
41950
|
+
id: `node_${randomUUID12().replace(/-/g, "")}`,
|
|
41441
41951
|
workspace: result.worktreePath,
|
|
41442
41952
|
repoRoot: result.worktreePath,
|
|
41443
41953
|
daemonId: sourceNode.daemonId,
|
|
@@ -49885,7 +50395,7 @@ var SessionHostPtyTransportFactory = class {
|
|
|
49885
50395
|
};
|
|
49886
50396
|
|
|
49887
50397
|
// src/cli-adapters/raw-terminal-io.ts
|
|
49888
|
-
var
|
|
50398
|
+
var import_crypto7 = require("crypto");
|
|
49889
50399
|
var import_session_host_core4 = require("@adhdev/session-host-core");
|
|
49890
50400
|
var BASE_KEY_SEQUENCES = {
|
|
49891
50401
|
enter: "\r",
|
|
@@ -49983,7 +50493,7 @@ var RawTerminalAttachment = class _RawTerminalAttachment {
|
|
|
49983
50493
|
const sessionId = String(options.sessionId || "").trim();
|
|
49984
50494
|
if (!sessionId) throw new Error("sessionId is required");
|
|
49985
50495
|
const mode = options.mode || "read";
|
|
49986
|
-
const clientId = options.clientId || `raw-terminal-${process.pid}-${(0,
|
|
50496
|
+
const clientId = options.clientId || `raw-terminal-${process.pid}-${(0, import_crypto7.randomUUID)().slice(0, 8)}`;
|
|
49987
50497
|
const client = options.client || new import_session_host_core4.SessionHostClient({ endpoint: options.endpoint });
|
|
49988
50498
|
await client.connect();
|
|
49989
50499
|
const attachResponse = await client.request({
|
|
@@ -51097,6 +51607,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
51097
51607
|
createInteractionId,
|
|
51098
51608
|
createMesh,
|
|
51099
51609
|
createNativeHistoryDispatcher,
|
|
51610
|
+
createSessionDelivery,
|
|
51100
51611
|
createWorktree,
|
|
51101
51612
|
deleteMesh,
|
|
51102
51613
|
detectAllVersions,
|
|
@@ -51120,6 +51631,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
51120
51631
|
forwardAgentStreamsToIdeInstance,
|
|
51121
51632
|
getAIExtensions,
|
|
51122
51633
|
getActiveDirectDispatches,
|
|
51634
|
+
getActiveSessionDeliveries,
|
|
51123
51635
|
getAvailableIdeIds,
|
|
51124
51636
|
getCoordinatorForSession,
|
|
51125
51637
|
getCurrentDaemonLogPath,
|
|
@@ -51142,6 +51654,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
51142
51654
|
getQueue,
|
|
51143
51655
|
getRecentActivity,
|
|
51144
51656
|
getRecentCommands,
|
|
51657
|
+
getRecentCompletionConflicts,
|
|
51145
51658
|
getRecentDebugTrace,
|
|
51146
51659
|
getRecentLogs,
|
|
51147
51660
|
getSavedProviderSessions,
|
|
@@ -51229,6 +51742,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
51229
51742
|
readLedgerEntries,
|
|
51230
51743
|
readLedgerSlice,
|
|
51231
51744
|
reconcileDirectDispatchCompletionFromTranscript,
|
|
51745
|
+
recordCompletionConflict,
|
|
51232
51746
|
recordDebugTrace,
|
|
51233
51747
|
registerExtensionProviders,
|
|
51234
51748
|
registerMeshCoordinator,
|
|
@@ -51242,6 +51756,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
51242
51756
|
resolveChatMessageKind,
|
|
51243
51757
|
resolveCurrentGlobalInstallSurface,
|
|
51244
51758
|
resolveDebugRuntimeConfig,
|
|
51759
|
+
resolveDeliveryDecision,
|
|
51245
51760
|
resolveGitRepository,
|
|
51246
51761
|
resolveMeshHostStatus,
|
|
51247
51762
|
resolveMeshRefineValidationPlan,
|
|
@@ -51271,6 +51786,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
51271
51786
|
updateDirectDispatchStatus,
|
|
51272
51787
|
updateMesh,
|
|
51273
51788
|
updateNode,
|
|
51789
|
+
updateSessionDeliveryStatus,
|
|
51274
51790
|
updateSessionTaskStatus,
|
|
51275
51791
|
updateTaskStatus,
|
|
51276
51792
|
upsertSavedProviderSession,
|