@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.mjs
CHANGED
|
@@ -3290,8 +3290,8 @@ var init_mesh_fast_forward = __esm({
|
|
|
3290
3290
|
}
|
|
3291
3291
|
});
|
|
3292
3292
|
|
|
3293
|
-
// src/mesh/
|
|
3294
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync4 } from "fs";
|
|
3293
|
+
// src/mesh/mesh-runtime-store.ts
|
|
3294
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync9, renameSync as renameSync3, statSync as statSync4 } from "fs";
|
|
3295
3295
|
import { dirname as dirname2, join as join12 } from "path";
|
|
3296
3296
|
import { createRequire } from "module";
|
|
3297
3297
|
function loadDatabaseCtor() {
|
|
@@ -3306,13 +3306,31 @@ function safeMeshId(meshId) {
|
|
|
3306
3306
|
function legacyQueuePath(meshId) {
|
|
3307
3307
|
return join12(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
3308
3308
|
}
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
"
|
|
3309
|
+
function meshRuntimeStorePath() {
|
|
3310
|
+
const dir = getLedgerDir();
|
|
3311
|
+
const nextPath = join12(dir, "mesh-runtime.db");
|
|
3312
|
+
if (existsSync11(nextPath)) return nextPath;
|
|
3313
|
+
const legacyPath = join12(dir, "beads.db");
|
|
3314
|
+
if (!existsSync11(legacyPath)) return nextPath;
|
|
3315
|
+
try {
|
|
3316
|
+
renameSync3(legacyPath, nextPath);
|
|
3317
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
3318
|
+
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
3319
|
+
if (existsSync11(legacyCompanion)) {
|
|
3320
|
+
renameSync3(legacyCompanion, `${nextPath}${suffix}`);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
} catch {
|
|
3324
|
+
}
|
|
3325
|
+
return nextPath;
|
|
3326
|
+
}
|
|
3327
|
+
var DatabaseCtor, MeshRuntimeStore;
|
|
3328
|
+
var init_mesh_runtime_store = __esm({
|
|
3329
|
+
"src/mesh/mesh-runtime-store.ts"() {
|
|
3312
3330
|
"use strict";
|
|
3313
3331
|
init_mesh_ledger();
|
|
3314
3332
|
init_mesh_work_queue();
|
|
3315
|
-
|
|
3333
|
+
MeshRuntimeStore = class _MeshRuntimeStore {
|
|
3316
3334
|
static instance;
|
|
3317
3335
|
db;
|
|
3318
3336
|
dbPath;
|
|
@@ -3335,7 +3353,7 @@ var init_beads_db = __esm({
|
|
|
3335
3353
|
}
|
|
3336
3354
|
static getInstance() {
|
|
3337
3355
|
if (!this.instance) {
|
|
3338
|
-
this.instance = new
|
|
3356
|
+
this.instance = new _MeshRuntimeStore(meshRuntimeStorePath());
|
|
3339
3357
|
}
|
|
3340
3358
|
return this.instance;
|
|
3341
3359
|
}
|
|
@@ -3400,6 +3418,49 @@ var init_beads_db = __esm({
|
|
|
3400
3418
|
metadata TEXT,
|
|
3401
3419
|
PRIMARY KEY (node_id, session_id)
|
|
3402
3420
|
);
|
|
3421
|
+
|
|
3422
|
+
CREATE TABLE IF NOT EXISTS mesh_session_delivery (
|
|
3423
|
+
id TEXT PRIMARY KEY,
|
|
3424
|
+
mesh_id TEXT NOT NULL,
|
|
3425
|
+
node_id TEXT,
|
|
3426
|
+
session_id TEXT,
|
|
3427
|
+
provider_type TEXT,
|
|
3428
|
+
task_id TEXT,
|
|
3429
|
+
kind TEXT NOT NULL,
|
|
3430
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
3431
|
+
message TEXT NOT NULL,
|
|
3432
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
3433
|
+
deliver_after TEXT,
|
|
3434
|
+
expires_at TEXT,
|
|
3435
|
+
attempt_count INTEGER NOT NULL DEFAULT 0,
|
|
3436
|
+
source_coordinator_session_id TEXT,
|
|
3437
|
+
source_coordinator_daemon_id TEXT,
|
|
3438
|
+
last_error TEXT,
|
|
3439
|
+
created_at TEXT NOT NULL,
|
|
3440
|
+
updated_at TEXT NOT NULL
|
|
3441
|
+
);
|
|
3442
|
+
|
|
3443
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_mesh_status
|
|
3444
|
+
ON mesh_session_delivery(mesh_id, status, created_at);
|
|
3445
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_session
|
|
3446
|
+
ON mesh_session_delivery(mesh_id, session_id, status);
|
|
3447
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_session_delivery_task
|
|
3448
|
+
ON mesh_session_delivery(mesh_id, task_id);
|
|
3449
|
+
|
|
3450
|
+
CREATE TABLE IF NOT EXISTS mesh_completion_conflicts (
|
|
3451
|
+
id TEXT PRIMARY KEY,
|
|
3452
|
+
mesh_id TEXT NOT NULL,
|
|
3453
|
+
fingerprint TEXT NOT NULL,
|
|
3454
|
+
conflicting_task_id TEXT,
|
|
3455
|
+
conflicting_session_id TEXT,
|
|
3456
|
+
original_task_id TEXT,
|
|
3457
|
+
original_session_id TEXT,
|
|
3458
|
+
event TEXT NOT NULL,
|
|
3459
|
+
created_at TEXT NOT NULL
|
|
3460
|
+
);
|
|
3461
|
+
|
|
3462
|
+
CREATE INDEX IF NOT EXISTS idx_mesh_completion_conflicts_mesh
|
|
3463
|
+
ON mesh_completion_conflicts(mesh_id, created_at);
|
|
3403
3464
|
`);
|
|
3404
3465
|
}
|
|
3405
3466
|
hasCompletionFingerprint(fingerprint) {
|
|
@@ -3420,13 +3481,13 @@ var init_beads_db = __esm({
|
|
|
3420
3481
|
this.db.prepare("DELETE FROM mesh_completion_fingerprints WHERE expires_at <= ?").run(Date.now());
|
|
3421
3482
|
}
|
|
3422
3483
|
maybeCheckpointWal() {
|
|
3423
|
-
if (++this.walWriteCounter <
|
|
3484
|
+
if (++this.walWriteCounter < _MeshRuntimeStore.WAL_CHECK_INTERVAL) return;
|
|
3424
3485
|
this.walWriteCounter = 0;
|
|
3425
3486
|
try {
|
|
3426
3487
|
const walPath = `${this.dbPath}-wal`;
|
|
3427
3488
|
if (!existsSync11(walPath)) return;
|
|
3428
3489
|
const size = statSync4(walPath).size;
|
|
3429
|
-
if (size <
|
|
3490
|
+
if (size < _MeshRuntimeStore.WAL_MAX_BYTES) return;
|
|
3430
3491
|
process.stderr.write(
|
|
3431
3492
|
`[adhdev-mesh] WAL file ${Math.round(size / 1024 / 1024)}MB exceeds threshold; forcing checkpoint
|
|
3432
3493
|
`
|
|
@@ -3724,6 +3785,131 @@ var init_beads_db = __esm({
|
|
|
3724
3785
|
pruneExpiredRemoteIdleSessions() {
|
|
3725
3786
|
this.db.prepare("DELETE FROM remote_idle_sessions WHERE expires_at <= ?").run(Date.now());
|
|
3726
3787
|
}
|
|
3788
|
+
// ── Session Delivery Queue ───────────────────────────────────────────────
|
|
3789
|
+
insertSessionDelivery(entry) {
|
|
3790
|
+
this.db.prepare(`
|
|
3791
|
+
INSERT OR REPLACE INTO mesh_session_delivery (
|
|
3792
|
+
id, mesh_id, node_id, session_id, provider_type, task_id, kind, priority,
|
|
3793
|
+
message, status, deliver_after, expires_at, attempt_count,
|
|
3794
|
+
source_coordinator_session_id, source_coordinator_daemon_id,
|
|
3795
|
+
last_error, created_at, updated_at
|
|
3796
|
+
) VALUES (
|
|
3797
|
+
@id, @meshId, @nodeId, @sessionId, @providerType, @taskId, @kind, @priority,
|
|
3798
|
+
@message, @status, @deliverAfter, @expiresAt, 0,
|
|
3799
|
+
@sourceCoordinatorSessionId, @sourceCoordinatorDaemonId,
|
|
3800
|
+
NULL, @createdAt, @updatedAt
|
|
3801
|
+
)
|
|
3802
|
+
`).run({
|
|
3803
|
+
id: entry.id,
|
|
3804
|
+
meshId: entry.meshId,
|
|
3805
|
+
nodeId: entry.nodeId ?? null,
|
|
3806
|
+
sessionId: entry.sessionId ?? null,
|
|
3807
|
+
providerType: entry.providerType ?? null,
|
|
3808
|
+
taskId: entry.taskId ?? null,
|
|
3809
|
+
kind: entry.kind,
|
|
3810
|
+
priority: entry.priority ?? 0,
|
|
3811
|
+
message: entry.message,
|
|
3812
|
+
status: entry.status,
|
|
3813
|
+
deliverAfter: entry.deliverAfter ?? null,
|
|
3814
|
+
expiresAt: entry.expiresAt ?? null,
|
|
3815
|
+
sourceCoordinatorSessionId: entry.sourceCoordinatorSessionId ?? null,
|
|
3816
|
+
sourceCoordinatorDaemonId: entry.sourceCoordinatorDaemonId ?? null,
|
|
3817
|
+
createdAt: entry.createdAt,
|
|
3818
|
+
updatedAt: entry.updatedAt
|
|
3819
|
+
});
|
|
3820
|
+
this.maybeCheckpointWal();
|
|
3821
|
+
}
|
|
3822
|
+
updateSessionDeliveryStatus(id, status, opts) {
|
|
3823
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3824
|
+
if (opts?.incrementAttempt) {
|
|
3825
|
+
this.db.prepare(`
|
|
3826
|
+
UPDATE mesh_session_delivery
|
|
3827
|
+
SET status = @status, last_error = @lastError, attempt_count = attempt_count + 1, updated_at = @updatedAt
|
|
3828
|
+
WHERE id = @id
|
|
3829
|
+
`).run({ id, status, lastError: opts?.lastError ?? null, updatedAt: now });
|
|
3830
|
+
} else {
|
|
3831
|
+
this.db.prepare(`
|
|
3832
|
+
UPDATE mesh_session_delivery
|
|
3833
|
+
SET status = @status, last_error = @lastError, updated_at = @updatedAt
|
|
3834
|
+
WHERE id = @id
|
|
3835
|
+
`).run({ id, status, lastError: opts?.lastError ?? null, updatedAt: now });
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
getActiveSessionDeliveries(meshId, sessionId) {
|
|
3839
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3840
|
+
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`;
|
|
3841
|
+
const rows = sessionId ? this.db.prepare(sql).all(meshId, sessionId, now) : this.db.prepare(sql).all(meshId, now);
|
|
3842
|
+
return rows.map((r) => ({
|
|
3843
|
+
id: r.id,
|
|
3844
|
+
meshId: r.mesh_id,
|
|
3845
|
+
nodeId: r.node_id,
|
|
3846
|
+
sessionId: r.session_id,
|
|
3847
|
+
providerType: r.provider_type,
|
|
3848
|
+
taskId: r.task_id,
|
|
3849
|
+
kind: r.kind,
|
|
3850
|
+
priority: r.priority,
|
|
3851
|
+
message: r.message,
|
|
3852
|
+
status: r.status,
|
|
3853
|
+
deliverAfter: r.deliver_after,
|
|
3854
|
+
expiresAt: r.expires_at,
|
|
3855
|
+
attemptCount: r.attempt_count,
|
|
3856
|
+
sourceCoordinatorSessionId: r.source_coordinator_session_id,
|
|
3857
|
+
sourceCoordinatorDaemonId: r.source_coordinator_daemon_id,
|
|
3858
|
+
lastError: r.last_error,
|
|
3859
|
+
createdAt: r.created_at,
|
|
3860
|
+
updatedAt: r.updated_at
|
|
3861
|
+
}));
|
|
3862
|
+
}
|
|
3863
|
+
expireStaleSessionDeliveries(meshId) {
|
|
3864
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3865
|
+
this.db.prepare(`
|
|
3866
|
+
UPDATE mesh_session_delivery
|
|
3867
|
+
SET status = 'expired', updated_at = ?
|
|
3868
|
+
WHERE mesh_id = ? AND expires_at IS NOT NULL AND expires_at <= ?
|
|
3869
|
+
AND status NOT IN ('delivered','completed','failed','expired','cancelled')
|
|
3870
|
+
`).run(now, meshId, now);
|
|
3871
|
+
}
|
|
3872
|
+
deleteSessionDeliveries(meshId) {
|
|
3873
|
+
this.db.prepare("DELETE FROM mesh_session_delivery WHERE mesh_id = ?").run(meshId);
|
|
3874
|
+
}
|
|
3875
|
+
// ── Completion Conflict Diagnostics ──────────────────────────────────────
|
|
3876
|
+
recordCompletionConflict(entry) {
|
|
3877
|
+
this.db.prepare(`
|
|
3878
|
+
INSERT OR IGNORE INTO mesh_completion_conflicts
|
|
3879
|
+
(id, mesh_id, fingerprint, conflicting_task_id, conflicting_session_id,
|
|
3880
|
+
original_task_id, original_session_id, event, created_at)
|
|
3881
|
+
VALUES (@id, @meshId, @fingerprint, @conflictingTaskId, @conflictingSessionId,
|
|
3882
|
+
@originalTaskId, @originalSessionId, @event, @createdAt)
|
|
3883
|
+
`).run({
|
|
3884
|
+
id: entry.id,
|
|
3885
|
+
meshId: entry.meshId,
|
|
3886
|
+
fingerprint: entry.fingerprint,
|
|
3887
|
+
conflictingTaskId: entry.conflictingTaskId ?? null,
|
|
3888
|
+
conflictingSessionId: entry.conflictingSessionId ?? null,
|
|
3889
|
+
originalTaskId: entry.originalTaskId ?? null,
|
|
3890
|
+
originalSessionId: entry.originalSessionId ?? null,
|
|
3891
|
+
event: entry.event,
|
|
3892
|
+
createdAt: entry.createdAt
|
|
3893
|
+
});
|
|
3894
|
+
this.maybeCheckpointWal();
|
|
3895
|
+
}
|
|
3896
|
+
getRecentCompletionConflicts(meshId, limitMs = 60 * 60 * 1e3) {
|
|
3897
|
+
const cutoff = new Date(Date.now() - limitMs).toISOString();
|
|
3898
|
+
const rows = this.db.prepare(
|
|
3899
|
+
"SELECT * FROM mesh_completion_conflicts WHERE mesh_id = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 50"
|
|
3900
|
+
).all(meshId, cutoff);
|
|
3901
|
+
return rows.map((r) => ({
|
|
3902
|
+
id: r.id,
|
|
3903
|
+
meshId: r.mesh_id,
|
|
3904
|
+
fingerprint: r.fingerprint,
|
|
3905
|
+
conflictingTaskId: r.conflicting_task_id,
|
|
3906
|
+
conflictingSessionId: r.conflicting_session_id,
|
|
3907
|
+
originalTaskId: r.original_task_id,
|
|
3908
|
+
originalSessionId: r.original_session_id,
|
|
3909
|
+
event: r.event,
|
|
3910
|
+
createdAt: r.created_at
|
|
3911
|
+
}));
|
|
3912
|
+
}
|
|
3727
3913
|
};
|
|
3728
3914
|
}
|
|
3729
3915
|
});
|
|
@@ -3737,7 +3923,7 @@ __export(mesh_work_queue_exports, {
|
|
|
3737
3923
|
__clearDirectDispatchesForTests: () => __clearDirectDispatchesForTests,
|
|
3738
3924
|
__clearMeshQueueForTests: () => __clearMeshQueueForTests,
|
|
3739
3925
|
__replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
|
|
3740
|
-
|
|
3926
|
+
__resetMeshRuntimeStoreForTests: () => __resetMeshRuntimeStoreForTests,
|
|
3741
3927
|
buildMeshNodeCapabilityTags: () => buildMeshNodeCapabilityTags,
|
|
3742
3928
|
cancelTask: () => cancelTask,
|
|
3743
3929
|
claimNextTask: () => claimNextTask,
|
|
@@ -3816,7 +4002,7 @@ function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
|
|
|
3816
4002
|
return required.every((tag) => available.has(tag));
|
|
3817
4003
|
}
|
|
3818
4004
|
function withQueueLock(_meshId, fn) {
|
|
3819
|
-
return
|
|
4005
|
+
return MeshRuntimeStore.getInstance().transaction(fn);
|
|
3820
4006
|
}
|
|
3821
4007
|
function enqueueTask(meshId, message, opts) {
|
|
3822
4008
|
requireMeshHostQueueOwner(opts);
|
|
@@ -3836,55 +4022,55 @@ function enqueueTask(meshId, message, opts) {
|
|
|
3836
4022
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3837
4023
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3838
4024
|
};
|
|
3839
|
-
|
|
4025
|
+
MeshRuntimeStore.getInstance().insertQueueEntry(entry);
|
|
3840
4026
|
return entry;
|
|
3841
4027
|
}
|
|
3842
4028
|
function getQueue(meshId, opts) {
|
|
3843
|
-
return
|
|
4029
|
+
return MeshRuntimeStore.getInstance().getQueueEntries(meshId, opts?.status?.length ? opts.status : void 0);
|
|
3844
4030
|
}
|
|
3845
4031
|
function getMeshQueueRevision(meshId) {
|
|
3846
|
-
return
|
|
4032
|
+
return MeshRuntimeStore.getInstance().getQueueRevision(meshId);
|
|
3847
4033
|
}
|
|
3848
4034
|
function claimNextTask(meshId, nodeId, sessionId, capabilityTags) {
|
|
3849
|
-
return
|
|
4035
|
+
return MeshRuntimeStore.getInstance().claimNextQueueTask(meshId, nodeId, sessionId, capabilityTags);
|
|
3850
4036
|
}
|
|
3851
4037
|
function updateTaskStatus(meshId, taskId, status, opts) {
|
|
3852
4038
|
requireMeshHostQueueOwner(opts);
|
|
3853
4039
|
return withQueueLock(meshId, () => {
|
|
3854
|
-
const entry =
|
|
4040
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3855
4041
|
if (!entry) return null;
|
|
3856
4042
|
entry.status = status;
|
|
3857
|
-
|
|
4043
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3858
4044
|
return entry;
|
|
3859
4045
|
});
|
|
3860
4046
|
}
|
|
3861
4047
|
function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
|
|
3862
4048
|
return withQueueLock(meshId, () => {
|
|
3863
|
-
const entry =
|
|
4049
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3864
4050
|
if (!entry) return null;
|
|
3865
4051
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3866
4052
|
entry.autoLaunch = { ...autoLaunch, updatedAt: now };
|
|
3867
|
-
|
|
4053
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3868
4054
|
return entry;
|
|
3869
4055
|
});
|
|
3870
4056
|
}
|
|
3871
4057
|
function cancelTask(meshId, taskId, opts) {
|
|
3872
4058
|
requireMeshHostQueueOwner(opts);
|
|
3873
4059
|
return withQueueLock(meshId, () => {
|
|
3874
|
-
const entry =
|
|
4060
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3875
4061
|
if (!entry) return null;
|
|
3876
4062
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3877
4063
|
entry.status = "cancelled";
|
|
3878
4064
|
entry.cancelledAt = now;
|
|
3879
4065
|
if (opts?.reason) entry.cancelReason = opts.reason;
|
|
3880
|
-
|
|
4066
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3881
4067
|
return entry;
|
|
3882
4068
|
});
|
|
3883
4069
|
}
|
|
3884
4070
|
function requeueTask(meshId, taskId, opts) {
|
|
3885
4071
|
requireMeshHostQueueOwner(opts);
|
|
3886
4072
|
return withQueueLock(meshId, () => {
|
|
3887
|
-
const entry =
|
|
4073
|
+
const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
|
|
3888
4074
|
if (!entry) return null;
|
|
3889
4075
|
entry.status = "pending";
|
|
3890
4076
|
delete entry.assignedNodeId;
|
|
@@ -3898,22 +4084,22 @@ function requeueTask(meshId, taskId, opts) {
|
|
|
3898
4084
|
entry.requeuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3899
4085
|
entry.requeueCount = (entry.requeueCount || 0) + 1;
|
|
3900
4086
|
if (opts?.reason) entry.requeueReason = opts.reason;
|
|
3901
|
-
|
|
4087
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3902
4088
|
return entry;
|
|
3903
4089
|
});
|
|
3904
4090
|
}
|
|
3905
4091
|
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
3906
4092
|
return withQueueLock(meshId, () => {
|
|
3907
4093
|
const occurredAtIso = opts?.occurredAt ? new Date(opts.occurredAt).toISOString() : void 0;
|
|
3908
|
-
const entry =
|
|
4094
|
+
const entry = MeshRuntimeStore.getInstance().findAssignedBySession(meshId, sessionId, occurredAtIso);
|
|
3909
4095
|
if (!entry) return null;
|
|
3910
4096
|
entry.status = status;
|
|
3911
|
-
|
|
4097
|
+
MeshRuntimeStore.getInstance().updateQueueEntry(entry);
|
|
3912
4098
|
return entry;
|
|
3913
4099
|
});
|
|
3914
4100
|
}
|
|
3915
4101
|
function getMeshQueueStats(meshId) {
|
|
3916
|
-
const rows =
|
|
4102
|
+
const rows = MeshRuntimeStore.getInstance().getQueueStatsByStatus(meshId);
|
|
3917
4103
|
const counts = {};
|
|
3918
4104
|
for (const r of rows) counts[r.status] = r.count;
|
|
3919
4105
|
const pending = counts["pending"] ?? 0;
|
|
@@ -3932,26 +4118,26 @@ function getMeshQueueStats(meshId) {
|
|
|
3932
4118
|
cancelled,
|
|
3933
4119
|
activeCounts: { pending, assigned },
|
|
3934
4120
|
historicalCounts: { completed, failed, cancelled },
|
|
3935
|
-
activeAssignments:
|
|
4121
|
+
activeAssignments: MeshRuntimeStore.getInstance().getActiveAssignmentDetails(meshId)
|
|
3936
4122
|
};
|
|
3937
4123
|
}
|
|
3938
4124
|
function __replaceMeshQueueForTests(meshId, queue) {
|
|
3939
|
-
|
|
3940
|
-
|
|
4125
|
+
MeshRuntimeStore.getInstance().transaction(() => {
|
|
4126
|
+
MeshRuntimeStore.getInstance().replaceQueue(meshId, queue);
|
|
3941
4127
|
});
|
|
3942
4128
|
}
|
|
3943
4129
|
function __clearMeshQueueForTests(meshId) {
|
|
3944
|
-
|
|
4130
|
+
MeshRuntimeStore.getInstance().deleteQueue(meshId);
|
|
3945
4131
|
}
|
|
3946
4132
|
function __clearDirectDispatchesForTests(meshId) {
|
|
3947
|
-
|
|
4133
|
+
MeshRuntimeStore.getInstance().deleteDirectDispatches(meshId);
|
|
3948
4134
|
}
|
|
3949
|
-
function
|
|
3950
|
-
|
|
4135
|
+
function __resetMeshRuntimeStoreForTests() {
|
|
4136
|
+
MeshRuntimeStore.resetForTests();
|
|
3951
4137
|
}
|
|
3952
4138
|
function insertDirectDispatch(meshId, data) {
|
|
3953
4139
|
try {
|
|
3954
|
-
|
|
4140
|
+
MeshRuntimeStore.getInstance().insertDirectDispatch({ ...data, meshId });
|
|
3955
4141
|
} catch (e) {
|
|
3956
4142
|
process.stderr.write(`[adhdev-mesh] insertDirectDispatch failed for task ${data.taskId}: ${e?.message || e}
|
|
3957
4143
|
`);
|
|
@@ -3959,26 +4145,26 @@ function insertDirectDispatch(meshId, data) {
|
|
|
3959
4145
|
}
|
|
3960
4146
|
function getActiveDirectDispatches(meshId) {
|
|
3961
4147
|
try {
|
|
3962
|
-
return
|
|
4148
|
+
return MeshRuntimeStore.getInstance().getActiveDirectDispatches(meshId);
|
|
3963
4149
|
} catch {
|
|
3964
4150
|
return [];
|
|
3965
4151
|
}
|
|
3966
4152
|
}
|
|
3967
4153
|
function updateDirectDispatchStatus(meshId, sessionId, status) {
|
|
3968
4154
|
try {
|
|
3969
|
-
|
|
4155
|
+
MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status);
|
|
3970
4156
|
} catch {
|
|
3971
4157
|
}
|
|
3972
4158
|
}
|
|
3973
4159
|
function cleanupTerminalDirectDispatches(olderThanMs = 7 * 24 * 60 * 6e4) {
|
|
3974
4160
|
try {
|
|
3975
|
-
|
|
4161
|
+
MeshRuntimeStore.getInstance().cleanupTerminalDirectDispatches(olderThanMs);
|
|
3976
4162
|
} catch {
|
|
3977
4163
|
}
|
|
3978
4164
|
}
|
|
3979
4165
|
function markStaleDirectDispatches(meshId, olderThanMs = 60 * 6e4) {
|
|
3980
4166
|
try {
|
|
3981
|
-
|
|
4167
|
+
MeshRuntimeStore.getInstance().markStaleDirectDispatches(meshId, olderThanMs);
|
|
3982
4168
|
} catch {
|
|
3983
4169
|
}
|
|
3984
4170
|
}
|
|
@@ -3987,7 +4173,7 @@ var init_mesh_work_queue = __esm({
|
|
|
3987
4173
|
"src/mesh/mesh-work-queue.ts"() {
|
|
3988
4174
|
"use strict";
|
|
3989
4175
|
init_mesh_host_ownership();
|
|
3990
|
-
|
|
4176
|
+
init_mesh_runtime_store();
|
|
3991
4177
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
3992
4178
|
HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
|
|
3993
4179
|
MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
|
|
@@ -4137,6 +4323,167 @@ var init_cli_detector = __esm({
|
|
|
4137
4323
|
}
|
|
4138
4324
|
});
|
|
4139
4325
|
|
|
4326
|
+
// src/mesh/mesh-delivery-policy.ts
|
|
4327
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
4328
|
+
function resolveDeliveryDecision(sessionStatus, opts) {
|
|
4329
|
+
const status = (sessionStatus || "").trim().toLowerCase();
|
|
4330
|
+
if (!status) {
|
|
4331
|
+
return {
|
|
4332
|
+
decision: "rejected",
|
|
4333
|
+
reason: "unknown_session_status",
|
|
4334
|
+
message: "Session status is unknown. Delivery rejected (fail-closed). Use mesh_launch_session to start a fresh session."
|
|
4335
|
+
};
|
|
4336
|
+
}
|
|
4337
|
+
if (IMMEDIATE_DELIVERY_STATUSES.has(status)) {
|
|
4338
|
+
return {
|
|
4339
|
+
decision: "immediate",
|
|
4340
|
+
reason: `session_${status}`,
|
|
4341
|
+
message: `Session is ${status} \u2014 delivery allowed immediately.`
|
|
4342
|
+
};
|
|
4343
|
+
}
|
|
4344
|
+
if (BUSY_DELIVERY_STATUSES.has(status)) {
|
|
4345
|
+
if (opts?.allowBusyInjection) {
|
|
4346
|
+
return {
|
|
4347
|
+
decision: "immediate",
|
|
4348
|
+
reason: `session_${status}_busy_injection_allowed`,
|
|
4349
|
+
message: `Session is ${status} but provider supports busy injection. Delivered immediately.`
|
|
4350
|
+
};
|
|
4351
|
+
}
|
|
4352
|
+
if (status === "waiting_approval" && opts?.kind === "approval") {
|
|
4353
|
+
return {
|
|
4354
|
+
decision: "immediate",
|
|
4355
|
+
reason: "session_waiting_approval_approval_message",
|
|
4356
|
+
message: "Session is waiting for approval \u2014 approval message delivered immediately."
|
|
4357
|
+
};
|
|
4358
|
+
}
|
|
4359
|
+
return {
|
|
4360
|
+
decision: "queued",
|
|
4361
|
+
reason: `session_${status}_busy`,
|
|
4362
|
+
message: `Session is ${status}. Task queued for delivery when session becomes idle. Do not inject directly into a busy session.`
|
|
4363
|
+
};
|
|
4364
|
+
}
|
|
4365
|
+
if (TERMINAL_DELIVERY_STATUSES.has(status)) {
|
|
4366
|
+
return {
|
|
4367
|
+
decision: "rejected",
|
|
4368
|
+
reason: `session_${status}_terminal`,
|
|
4369
|
+
message: `Session is ${status} (terminal). Delivery rejected. Launch a new session before dispatching tasks.`
|
|
4370
|
+
};
|
|
4371
|
+
}
|
|
4372
|
+
return {
|
|
4373
|
+
decision: "rejected",
|
|
4374
|
+
reason: "unrecognized_session_status",
|
|
4375
|
+
message: `Session status '${sessionStatus}' is not recognized. Delivery rejected (fail-closed). Inspect session state before retrying.`
|
|
4376
|
+
};
|
|
4377
|
+
}
|
|
4378
|
+
function createSessionDelivery(opts) {
|
|
4379
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4380
|
+
const id = randomUUID6();
|
|
4381
|
+
const record = {
|
|
4382
|
+
id,
|
|
4383
|
+
meshId: opts.meshId,
|
|
4384
|
+
nodeId: opts.nodeId,
|
|
4385
|
+
sessionId: opts.sessionId,
|
|
4386
|
+
providerType: opts.providerType,
|
|
4387
|
+
taskId: opts.taskId,
|
|
4388
|
+
kind: opts.kind,
|
|
4389
|
+
priority: opts.priority ?? 0,
|
|
4390
|
+
message: opts.message,
|
|
4391
|
+
status: opts.status,
|
|
4392
|
+
deliverAfter: opts.deliverAfter,
|
|
4393
|
+
expiresAt: opts.expiresAt,
|
|
4394
|
+
attemptCount: 0,
|
|
4395
|
+
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
4396
|
+
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
4397
|
+
createdAt: now,
|
|
4398
|
+
updatedAt: now
|
|
4399
|
+
};
|
|
4400
|
+
MeshRuntimeStore.getInstance().insertSessionDelivery({
|
|
4401
|
+
id,
|
|
4402
|
+
meshId: opts.meshId,
|
|
4403
|
+
nodeId: opts.nodeId,
|
|
4404
|
+
sessionId: opts.sessionId,
|
|
4405
|
+
providerType: opts.providerType,
|
|
4406
|
+
taskId: opts.taskId,
|
|
4407
|
+
kind: opts.kind,
|
|
4408
|
+
priority: opts.priority ?? 0,
|
|
4409
|
+
message: opts.message,
|
|
4410
|
+
status: opts.status,
|
|
4411
|
+
deliverAfter: opts.deliverAfter,
|
|
4412
|
+
expiresAt: opts.expiresAt,
|
|
4413
|
+
sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId,
|
|
4414
|
+
sourceCoordinatorDaemonId: opts.sourceCoordinatorDaemonId,
|
|
4415
|
+
createdAt: now,
|
|
4416
|
+
updatedAt: now
|
|
4417
|
+
});
|
|
4418
|
+
return record;
|
|
4419
|
+
}
|
|
4420
|
+
function updateSessionDeliveryStatus(id, status, opts) {
|
|
4421
|
+
try {
|
|
4422
|
+
MeshRuntimeStore.getInstance().updateSessionDeliveryStatus(id, status, opts);
|
|
4423
|
+
} catch {
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
function getActiveSessionDeliveries(meshId, sessionId) {
|
|
4427
|
+
try {
|
|
4428
|
+
return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(meshId, sessionId);
|
|
4429
|
+
} catch {
|
|
4430
|
+
return [];
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
function recordCompletionConflict(opts) {
|
|
4434
|
+
try {
|
|
4435
|
+
MeshRuntimeStore.getInstance().recordCompletionConflict({
|
|
4436
|
+
id: randomUUID6(),
|
|
4437
|
+
meshId: opts.meshId,
|
|
4438
|
+
fingerprint: opts.fingerprint,
|
|
4439
|
+
conflictingTaskId: opts.conflictingTaskId,
|
|
4440
|
+
conflictingSessionId: opts.conflictingSessionId,
|
|
4441
|
+
originalTaskId: opts.originalTaskId,
|
|
4442
|
+
originalSessionId: opts.originalSessionId,
|
|
4443
|
+
event: opts.event,
|
|
4444
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4445
|
+
});
|
|
4446
|
+
} catch {
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
function getRecentCompletionConflicts(meshId, limitMs) {
|
|
4450
|
+
try {
|
|
4451
|
+
return MeshRuntimeStore.getInstance().getRecentCompletionConflicts(meshId, limitMs);
|
|
4452
|
+
} catch {
|
|
4453
|
+
return [];
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
var IMMEDIATE_DELIVERY_STATUSES, BUSY_DELIVERY_STATUSES, TERMINAL_DELIVERY_STATUSES;
|
|
4457
|
+
var init_mesh_delivery_policy = __esm({
|
|
4458
|
+
"src/mesh/mesh-delivery-policy.ts"() {
|
|
4459
|
+
"use strict";
|
|
4460
|
+
init_mesh_runtime_store();
|
|
4461
|
+
IMMEDIATE_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4462
|
+
"idle",
|
|
4463
|
+
"waiting_input",
|
|
4464
|
+
"ready"
|
|
4465
|
+
]);
|
|
4466
|
+
BUSY_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4467
|
+
"generating",
|
|
4468
|
+
"running",
|
|
4469
|
+
"streaming",
|
|
4470
|
+
"busy",
|
|
4471
|
+
"starting",
|
|
4472
|
+
"initializing",
|
|
4473
|
+
"waiting_approval"
|
|
4474
|
+
]);
|
|
4475
|
+
TERMINAL_DELIVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
4476
|
+
"stopped",
|
|
4477
|
+
"failed",
|
|
4478
|
+
"terminated",
|
|
4479
|
+
"exited",
|
|
4480
|
+
"closed",
|
|
4481
|
+
"deleted",
|
|
4482
|
+
"error"
|
|
4483
|
+
]);
|
|
4484
|
+
}
|
|
4485
|
+
});
|
|
4486
|
+
|
|
4140
4487
|
// src/mesh/mesh-events.ts
|
|
4141
4488
|
var mesh_events_exports = {};
|
|
4142
4489
|
__export(mesh_events_exports, {
|
|
@@ -4151,7 +4498,7 @@ __export(mesh_events_exports, {
|
|
|
4151
4498
|
triggerMeshQueue: () => triggerMeshQueue,
|
|
4152
4499
|
tryAssignQueueTask: () => tryAssignQueueTask
|
|
4153
4500
|
});
|
|
4154
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync13, readFileSync as readFileSync10, renameSync as
|
|
4501
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync13, readFileSync as readFileSync10, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
4155
4502
|
import { join as join14 } from "path";
|
|
4156
4503
|
function getCachedMeshByWorkspace(workspace) {
|
|
4157
4504
|
const now = Date.now();
|
|
@@ -4169,7 +4516,7 @@ function __resetIdleAutoFastForwardForTests() {
|
|
|
4169
4516
|
}
|
|
4170
4517
|
function sweepExpiredRemoteIdleSessions() {
|
|
4171
4518
|
try {
|
|
4172
|
-
|
|
4519
|
+
MeshRuntimeStore.getInstance().pruneExpiredRemoteIdleSessions();
|
|
4173
4520
|
} catch {
|
|
4174
4521
|
}
|
|
4175
4522
|
}
|
|
@@ -4338,7 +4685,7 @@ function queuePendingMeshCoordinatorEvent(event) {
|
|
|
4338
4685
|
function atomicDrainFile(path40) {
|
|
4339
4686
|
const tmpPath = `${path40}.draining`;
|
|
4340
4687
|
try {
|
|
4341
|
-
|
|
4688
|
+
renameSync4(path40, tmpPath);
|
|
4342
4689
|
} catch {
|
|
4343
4690
|
return null;
|
|
4344
4691
|
}
|
|
@@ -4445,14 +4792,14 @@ function shouldSuppressIntentionalCleanupStop(args) {
|
|
|
4445
4792
|
}
|
|
4446
4793
|
function hasFingerprintSeen(fingerprint) {
|
|
4447
4794
|
try {
|
|
4448
|
-
return
|
|
4795
|
+
return MeshRuntimeStore.getInstance().hasCompletionFingerprint(fingerprint);
|
|
4449
4796
|
} catch {
|
|
4450
4797
|
return false;
|
|
4451
4798
|
}
|
|
4452
4799
|
}
|
|
4453
4800
|
function recordFingerprintSeen(fingerprint) {
|
|
4454
4801
|
try {
|
|
4455
|
-
const db =
|
|
4802
|
+
const db = MeshRuntimeStore.getInstance();
|
|
4456
4803
|
db.recordCompletionFingerprint(fingerprint, RECENT_COMPLETION_FINGERPRINT_TTL_MS);
|
|
4457
4804
|
db.sweepExpiredFingerprints();
|
|
4458
4805
|
} catch {
|
|
@@ -4483,7 +4830,18 @@ function buildMeshCompletionFingerprint(args) {
|
|
|
4483
4830
|
function isDuplicateMeshCompletionEvent(args) {
|
|
4484
4831
|
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
4485
4832
|
if (!fingerprint) return false;
|
|
4486
|
-
if (hasFingerprintSeen(fingerprint))
|
|
4833
|
+
if (hasFingerprintSeen(fingerprint)) {
|
|
4834
|
+
if (args.taskId) {
|
|
4835
|
+
recordCompletionConflict({
|
|
4836
|
+
meshId: args.meshId,
|
|
4837
|
+
fingerprint,
|
|
4838
|
+
conflictingTaskId: args.taskId,
|
|
4839
|
+
conflictingSessionId: args.sessionId,
|
|
4840
|
+
event: args.event
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
return true;
|
|
4844
|
+
}
|
|
4487
4845
|
recordFingerprintSeen(fingerprint);
|
|
4488
4846
|
return false;
|
|
4489
4847
|
}
|
|
@@ -4734,20 +5092,33 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
4734
5092
|
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
4735
5093
|
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
4736
5094
|
if (!isLocalNode) {
|
|
5095
|
+
const delivery2 = createSessionDelivery({
|
|
5096
|
+
meshId,
|
|
5097
|
+
nodeId,
|
|
5098
|
+
sessionId,
|
|
5099
|
+
providerType,
|
|
5100
|
+
taskId: task.id,
|
|
5101
|
+
kind: "task",
|
|
5102
|
+
message: task.message,
|
|
5103
|
+
status: "delivering"
|
|
5104
|
+
});
|
|
4737
5105
|
components.dispatchMeshCommand(node.daemonId, "agent_command", {
|
|
4738
5106
|
targetSessionId: sessionId,
|
|
4739
5107
|
cliType: providerType,
|
|
4740
5108
|
action: "send_chat",
|
|
4741
5109
|
message: task.message
|
|
5110
|
+
}).then(() => {
|
|
5111
|
+
updateSessionDeliveryStatus(delivery2.id, "delivered");
|
|
4742
5112
|
}).catch((e) => {
|
|
4743
5113
|
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
5114
|
+
updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
4744
5115
|
updateTaskStatus(meshId, task.id, "pending");
|
|
4745
5116
|
try {
|
|
4746
5117
|
appendLedgerEntry(meshId, {
|
|
4747
5118
|
kind: "dispatch_failed",
|
|
4748
5119
|
nodeId,
|
|
4749
5120
|
sessionId,
|
|
4750
|
-
payload: { taskId: task.id, error: e?.message, retryable: true }
|
|
5121
|
+
payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
|
|
4751
5122
|
});
|
|
4752
5123
|
} catch {
|
|
4753
5124
|
}
|
|
@@ -4755,13 +5126,26 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
4755
5126
|
return true;
|
|
4756
5127
|
}
|
|
4757
5128
|
}
|
|
5129
|
+
const delivery = createSessionDelivery({
|
|
5130
|
+
meshId,
|
|
5131
|
+
nodeId,
|
|
5132
|
+
sessionId,
|
|
5133
|
+
providerType,
|
|
5134
|
+
taskId: task.id,
|
|
5135
|
+
kind: "task",
|
|
5136
|
+
message: task.message,
|
|
5137
|
+
status: "delivering"
|
|
5138
|
+
});
|
|
4758
5139
|
components.cliManager.handleCliCommand("agent_command", {
|
|
4759
5140
|
targetSessionId: sessionId,
|
|
4760
5141
|
cliType: providerType,
|
|
4761
5142
|
action: "send_chat",
|
|
4762
5143
|
message: task.message
|
|
5144
|
+
}).then(() => {
|
|
5145
|
+
updateSessionDeliveryStatus(delivery.id, "delivered");
|
|
4763
5146
|
}).catch((e) => {
|
|
4764
5147
|
LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
|
|
5148
|
+
updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
|
|
4765
5149
|
updateTaskStatus(meshId, task.id, "failed");
|
|
4766
5150
|
});
|
|
4767
5151
|
return true;
|
|
@@ -5072,7 +5456,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
5072
5456
|
}
|
|
5073
5457
|
let remoteSessions = [];
|
|
5074
5458
|
try {
|
|
5075
|
-
remoteSessions =
|
|
5459
|
+
remoteSessions = MeshRuntimeStore.getInstance().getRemoteIdleSessions();
|
|
5076
5460
|
} catch {
|
|
5077
5461
|
}
|
|
5078
5462
|
for (const idle of remoteSessions) {
|
|
@@ -5082,7 +5466,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
5082
5466
|
const assigned = tryAssignQueueTask(components, meshId, idle.nodeId, idle.sessionId, idle.providerType);
|
|
5083
5467
|
if (assigned) {
|
|
5084
5468
|
try {
|
|
5085
|
-
|
|
5469
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(idle.nodeId, idle.sessionId);
|
|
5086
5470
|
} catch {
|
|
5087
5471
|
}
|
|
5088
5472
|
}
|
|
@@ -5284,7 +5668,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5284
5668
|
if (intentionalCleanupStop) {
|
|
5285
5669
|
if (eventSessionId && eventNodeId) {
|
|
5286
5670
|
try {
|
|
5287
|
-
|
|
5671
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(eventNodeId, eventSessionId);
|
|
5288
5672
|
} catch {
|
|
5289
5673
|
}
|
|
5290
5674
|
}
|
|
@@ -5366,7 +5750,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5366
5750
|
finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0,
|
|
5367
5751
|
// Scope dedup to the coordinator daemon so two coordinators for the same mesh
|
|
5368
5752
|
// don't suppress each other's completion events via shared fingerprint table.
|
|
5369
|
-
coordinatorDaemonId: workerCoordinatorDaemonId || void 0
|
|
5753
|
+
coordinatorDaemonId: workerCoordinatorDaemonId || void 0,
|
|
5754
|
+
taskId: readNonEmptyString2(args.metadataEvent.taskId) || void 0,
|
|
5755
|
+
nodeId: eventNodeId || void 0
|
|
5370
5756
|
});
|
|
5371
5757
|
if (duplicateCompletion) {
|
|
5372
5758
|
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
@@ -5382,7 +5768,9 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5382
5768
|
providerSessionId: readNonEmptyString2(args.metadataEvent.providerSessionId) || void 0,
|
|
5383
5769
|
timestamp: eventTimestamp,
|
|
5384
5770
|
finalSummary: readNonEmptyString2(args.metadataEvent.finalSummary) || void 0,
|
|
5385
|
-
coordinatorDaemonId: workerCoordinatorDaemonId || void 0
|
|
5771
|
+
coordinatorDaemonId: workerCoordinatorDaemonId || void 0,
|
|
5772
|
+
taskId: readNonEmptyString2(args.metadataEvent.taskId) || void 0,
|
|
5773
|
+
nodeId: eventNodeId || void 0
|
|
5386
5774
|
});
|
|
5387
5775
|
if (duplicateStopped) {
|
|
5388
5776
|
LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
@@ -5452,14 +5840,14 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5452
5840
|
if (sessionId && nodeId && providerType) {
|
|
5453
5841
|
sweepExpiredRemoteIdleSessions();
|
|
5454
5842
|
try {
|
|
5455
|
-
|
|
5843
|
+
MeshRuntimeStore.getInstance().setRemoteIdleSession(nodeId, sessionId, providerType, Date.now() + REMOTE_IDLE_SESSION_TTL_MS);
|
|
5456
5844
|
} catch {
|
|
5457
5845
|
}
|
|
5458
5846
|
setImmediate(() => {
|
|
5459
5847
|
maybeAutoFastForwardIdleNode(components, { meshId: args.meshId, nodeId, sessionId, providerType }).finally(() => {
|
|
5460
5848
|
try {
|
|
5461
5849
|
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
5462
|
-
if (assigned)
|
|
5850
|
+
if (assigned) MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
|
|
5463
5851
|
} catch (e) {
|
|
5464
5852
|
LOG.warn("MeshQueue", `Failed to assign idle queue task after maintenance for ${nodeId}: ${e?.message || e}`);
|
|
5465
5853
|
}
|
|
@@ -5471,7 +5859,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5471
5859
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
5472
5860
|
if (sessionId && nodeId) {
|
|
5473
5861
|
try {
|
|
5474
|
-
|
|
5862
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
|
|
5475
5863
|
} catch {
|
|
5476
5864
|
}
|
|
5477
5865
|
}
|
|
@@ -5483,7 +5871,7 @@ function injectMeshSystemMessage(components, args) {
|
|
|
5483
5871
|
const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
|
|
5484
5872
|
if (sessionId && nodeId) {
|
|
5485
5873
|
try {
|
|
5486
|
-
|
|
5874
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
|
|
5487
5875
|
} catch {
|
|
5488
5876
|
}
|
|
5489
5877
|
}
|
|
@@ -5755,8 +6143,9 @@ var init_mesh_events = __esm({
|
|
|
5755
6143
|
init_logger();
|
|
5756
6144
|
init_mesh_ledger();
|
|
5757
6145
|
init_mesh_work_queue();
|
|
5758
|
-
|
|
6146
|
+
init_mesh_runtime_store();
|
|
5759
6147
|
init_mesh_fast_forward();
|
|
6148
|
+
init_mesh_delivery_policy();
|
|
5760
6149
|
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
5761
6150
|
meshByWorkspaceCache = /* @__PURE__ */ new Map();
|
|
5762
6151
|
MESH_WORKSPACE_CACHE_TTL_MS = 5e3;
|
|
@@ -8706,11 +9095,12 @@ var init_cli_state_engine = __esm({
|
|
|
8706
9095
|
}
|
|
8707
9096
|
applyGenerating(ctx) {
|
|
8708
9097
|
const { modal, parsedMessages, lastParsedAssistant, parsedStatus, prevStatus } = ctx;
|
|
9098
|
+
const noActiveTurn = !this.currentTurnScope;
|
|
9099
|
+
if (!this.isWaitingForResponse && noActiveTurn && !modal) return;
|
|
8709
9100
|
this.clearIdleFinishCandidate("generating");
|
|
8710
9101
|
this.cancelPendingIdleFinish("generating_signal_returned");
|
|
8711
9102
|
const snap = this.transport.getSnapshot();
|
|
8712
9103
|
const effectiveScreenText = snap.screenText || snap.accumulatedBuffer;
|
|
8713
|
-
const noActiveTurn = !this.currentTurnScope;
|
|
8714
9104
|
const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
|
|
8715
9105
|
const parsedShowsLiveProgress = parsedStatus === "generating" && !!lastParsedAssistant;
|
|
8716
9106
|
if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveProgress) return;
|
|
@@ -8970,7 +9360,25 @@ var init_cli_state_engine = __esm({
|
|
|
8970
9360
|
const parsedStatus = typeof parsed?.status === "string" ? parsed.status.trim() : "";
|
|
8971
9361
|
if (parsedStatus !== "idle") return true;
|
|
8972
9362
|
if (parsed?.activeModal || parsed?.modal) return true;
|
|
8973
|
-
|
|
9363
|
+
const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
|
|
9364
|
+
let lastUserIdx = -1;
|
|
9365
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
9366
|
+
if (messages[i]?.role === "user") {
|
|
9367
|
+
lastUserIdx = i;
|
|
9368
|
+
break;
|
|
9369
|
+
}
|
|
9370
|
+
}
|
|
9371
|
+
if (lastUserIdx < 0) {
|
|
9372
|
+
if (messages.length === 0) return false;
|
|
9373
|
+
return !this.parsedStatusHasFinalStandardAssistantMessage(parsed);
|
|
9374
|
+
}
|
|
9375
|
+
const hasCurrentTurnAssistant = messages.slice(lastUserIdx + 1).some((m) => {
|
|
9376
|
+
if (!m || m.role !== "assistant") return false;
|
|
9377
|
+
if (typeof m.content !== "string" || !m.content.trim()) return false;
|
|
9378
|
+
const kind = typeof m.kind === "string" && m.kind.trim() ? m.kind.trim() : "standard";
|
|
9379
|
+
return kind === "standard" && m.meta?.streaming !== true;
|
|
9380
|
+
});
|
|
9381
|
+
return !hasCurrentTurnAssistant;
|
|
8974
9382
|
}
|
|
8975
9383
|
rescheduleTranscriptFinishCheck(reason) {
|
|
8976
9384
|
this.clearIdleFinishCandidate(reason);
|
|
@@ -11432,14 +11840,19 @@ function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
|
|
|
11432
11840
|
if (question.multiSelect) throw new Error("Claude TUI multi-select prompts are not supported yet");
|
|
11433
11841
|
const answer = response.answers[question.questionId];
|
|
11434
11842
|
if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
|
|
11435
|
-
|
|
11436
|
-
if (
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
steps.push(
|
|
11843
|
+
const freeformText = answer.freeformText?.trim() ?? "";
|
|
11844
|
+
if (freeformText) {
|
|
11845
|
+
const typeOptionIndex = question.options.findIndex((o) => /^Type something\.?$/i.test(o.label));
|
|
11846
|
+
const optionNumber = typeOptionIndex >= 0 ? typeOptionIndex + 1 : question.options.length;
|
|
11847
|
+
steps.push(String(optionNumber));
|
|
11848
|
+
for (const ch of freeformText) steps.push(ch);
|
|
11849
|
+
steps.push("\r");
|
|
11850
|
+
} else {
|
|
11851
|
+
if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
|
|
11852
|
+
const selectedIndex = question.options.findIndex((option) => option.label === answer.selectedLabels[0]);
|
|
11853
|
+
if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
|
|
11854
|
+
steps.push(String(selectedIndex + 1));
|
|
11441
11855
|
}
|
|
11442
|
-
steps.push("\r");
|
|
11443
11856
|
}
|
|
11444
11857
|
steps.push("\r");
|
|
11445
11858
|
return steps;
|
|
@@ -14006,6 +14419,7 @@ function buildMeshAsyncRefineJobs(args) {
|
|
|
14006
14419
|
// src/index.ts
|
|
14007
14420
|
init_mesh_host_ownership();
|
|
14008
14421
|
init_mesh_events();
|
|
14422
|
+
init_mesh_delivery_policy();
|
|
14009
14423
|
|
|
14010
14424
|
// src/mesh/p2p-relay-failure.ts
|
|
14011
14425
|
var NO_FALLBACK_REASON = "Repo Mesh command/data-plane is P2P-only; WS/REST command fallback is intentionally disabled to preserve the transport boundary.";
|
|
@@ -19772,6 +20186,7 @@ function normalizeManagedStatus(status, opts) {
|
|
|
19772
20186
|
if (hasApprovalButtons(opts?.activeModal)) return "waiting_approval";
|
|
19773
20187
|
const normalized = String(status || "idle").trim().toLowerCase();
|
|
19774
20188
|
if (normalized === "waiting_approval") return "waiting_approval";
|
|
20189
|
+
if (normalized === "waiting_choice") return "waiting_choice";
|
|
19775
20190
|
if (WORKING_STATUSES.has(normalized)) return "generating";
|
|
19776
20191
|
if (normalized === "error") return "error";
|
|
19777
20192
|
if (normalized === "stopped") return "stopped";
|
|
@@ -20336,7 +20751,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
20336
20751
|
import * as fs6 from "fs";
|
|
20337
20752
|
import * as os8 from "os";
|
|
20338
20753
|
import * as path13 from "path";
|
|
20339
|
-
import { randomUUID as
|
|
20754
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
20340
20755
|
init_logger();
|
|
20341
20756
|
|
|
20342
20757
|
// src/logging/debug-trace.ts
|
|
@@ -21876,7 +22291,7 @@ function safeBundleIdSegment(value, fallback) {
|
|
|
21876
22291
|
function createChatDebugBundleId(targetSessionId) {
|
|
21877
22292
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.]/g, "").replace("T", "T").replace("Z", "Z");
|
|
21878
22293
|
const sessionSegment = safeBundleIdSegment(targetSessionId, "unknown-session");
|
|
21879
|
-
return `chat-debug-${timestamp}-${sessionSegment}-${
|
|
22294
|
+
return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID8().slice(0, 8)}`;
|
|
21880
22295
|
}
|
|
21881
22296
|
function buildChatDebugBundleSummary(bundle) {
|
|
21882
22297
|
const target = bundle.target && typeof bundle.target === "object" ? bundle.target : {};
|
|
@@ -25790,10 +26205,47 @@ function resolveSections(spec, lines) {
|
|
|
25790
26205
|
for (const sec of spec.layout.sections) {
|
|
25791
26206
|
let from = 0;
|
|
25792
26207
|
let to = total;
|
|
25793
|
-
if (sec.
|
|
26208
|
+
if (sec.anchor_regex !== void 0) {
|
|
26209
|
+
try {
|
|
26210
|
+
const re = new RegExp(sec.anchor_regex, sec.anchor_flags ?? "");
|
|
26211
|
+
const prevRe = sec.anchor_context?.prev !== void 0 ? new RegExp(sec.anchor_context.prev, sec.anchor_context.prev_flags ?? "") : null;
|
|
26212
|
+
const nextRe = sec.anchor_context?.next !== void 0 ? new RegExp(sec.anchor_context.next, sec.anchor_context.next_flags ?? "") : null;
|
|
26213
|
+
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]));
|
|
26214
|
+
let idx = -1;
|
|
26215
|
+
if (sec.anchor_last) {
|
|
26216
|
+
for (let i = total - 1; i >= 0; i--) {
|
|
26217
|
+
if (matches(i)) {
|
|
26218
|
+
idx = i;
|
|
26219
|
+
break;
|
|
26220
|
+
}
|
|
26221
|
+
}
|
|
26222
|
+
} else {
|
|
26223
|
+
for (let i = 0; i < total; i++) {
|
|
26224
|
+
if (matches(i)) {
|
|
26225
|
+
idx = i;
|
|
26226
|
+
break;
|
|
26227
|
+
}
|
|
26228
|
+
}
|
|
26229
|
+
}
|
|
26230
|
+
if (idx !== -1) {
|
|
26231
|
+
from = idx;
|
|
26232
|
+
to = total;
|
|
26233
|
+
if (sec.until_regex !== void 0) {
|
|
26234
|
+
try {
|
|
26235
|
+
const ure = new RegExp(sec.until_regex, sec.until_regex_flags ?? "");
|
|
26236
|
+
const end = lines.findIndex((l, i) => i > idx && ure.test(l));
|
|
26237
|
+
if (end !== -1) to = end;
|
|
26238
|
+
} catch {
|
|
26239
|
+
}
|
|
26240
|
+
} else if (sec.lines !== void 0) {
|
|
26241
|
+
to = Math.min(total, from + sec.lines);
|
|
26242
|
+
}
|
|
26243
|
+
}
|
|
26244
|
+
} catch {
|
|
26245
|
+
}
|
|
26246
|
+
} else if (sec.from_top !== void 0) {
|
|
25794
26247
|
from = resolveSize(sec.from_top, total);
|
|
25795
|
-
}
|
|
25796
|
-
if (sec.from_bottom !== void 0) {
|
|
26248
|
+
} else if (sec.from_bottom !== void 0) {
|
|
25797
26249
|
const sz = resolveSize(sec.from_bottom, total);
|
|
25798
26250
|
from = total - sz;
|
|
25799
26251
|
to = total;
|
|
@@ -26111,6 +26563,9 @@ var SCHEMA = {
|
|
|
26111
26563
|
"type": "string",
|
|
26112
26564
|
"minLength": 1
|
|
26113
26565
|
},
|
|
26566
|
+
"requiresFinalAssistantBeforeIdle": {
|
|
26567
|
+
"type": "boolean"
|
|
26568
|
+
},
|
|
26114
26569
|
"debounce": {
|
|
26115
26570
|
"type": "object",
|
|
26116
26571
|
"additionalProperties": false,
|
|
@@ -26125,7 +26580,8 @@ var SCHEMA = {
|
|
|
26125
26580
|
"section": { "type": "string", "minLength": 1 },
|
|
26126
26581
|
"regex": { "type": "string", "minLength": 1 },
|
|
26127
26582
|
"flags": { "type": "string" },
|
|
26128
|
-
"hold_ms": { "type": "integer", "minimum": 0 }
|
|
26583
|
+
"hold_ms": { "type": "integer", "minimum": 0 },
|
|
26584
|
+
"force_after_ms": { "type": "integer", "minimum": 0 }
|
|
26129
26585
|
}
|
|
26130
26586
|
}
|
|
26131
26587
|
}
|
|
@@ -26173,7 +26629,23 @@ var SCHEMA = {
|
|
|
26173
26629
|
"type": "string"
|
|
26174
26630
|
}
|
|
26175
26631
|
}
|
|
26176
|
-
}
|
|
26632
|
+
},
|
|
26633
|
+
"anchor_regex": { "type": "string", "minLength": 1 },
|
|
26634
|
+
"anchor_flags": { "type": "string" },
|
|
26635
|
+
"anchor_last": { "type": "boolean" },
|
|
26636
|
+
"anchor_context": {
|
|
26637
|
+
"type": "object",
|
|
26638
|
+
"additionalProperties": false,
|
|
26639
|
+
"properties": {
|
|
26640
|
+
"prev": { "type": "string" },
|
|
26641
|
+
"prev_flags": { "type": "string" },
|
|
26642
|
+
"next": { "type": "string" },
|
|
26643
|
+
"next_flags": { "type": "string" }
|
|
26644
|
+
}
|
|
26645
|
+
},
|
|
26646
|
+
"lines": { "type": "integer", "minimum": 1 },
|
|
26647
|
+
"until_regex": { "type": "string", "minLength": 1 },
|
|
26648
|
+
"until_regex_flags": { "type": "string" }
|
|
26177
26649
|
}
|
|
26178
26650
|
},
|
|
26179
26651
|
"sectionRegex": {
|
|
@@ -26609,6 +27081,7 @@ function resolveSpecPath(providerDir) {
|
|
|
26609
27081
|
}
|
|
26610
27082
|
|
|
26611
27083
|
// src/providers/spec/driver.ts
|
|
27084
|
+
init_logger();
|
|
26612
27085
|
var STARTUP_GRACE_MS = 2500;
|
|
26613
27086
|
var BUSY_HOLD_MS = 6e3;
|
|
26614
27087
|
var SUBMIT_DELAY_FLOOR_MS = 200;
|
|
@@ -26636,9 +27109,16 @@ function matchesCompletionIdleRule(spec, ev, screen) {
|
|
|
26636
27109
|
return null;
|
|
26637
27110
|
}
|
|
26638
27111
|
}
|
|
26639
|
-
function matchesCompletionIdleTargetState(spec, ev, screen) {
|
|
27112
|
+
function matchesCompletionIdleTargetState(spec, ev, screen, cursor) {
|
|
26640
27113
|
const target = spec.states.find((state) => state.id === spec.default_state) ?? spec.states.find((state) => state.id === "idle");
|
|
26641
|
-
if (!target?.when
|
|
27114
|
+
if (!target?.when) return false;
|
|
27115
|
+
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;
|
|
27116
|
+
if (hasCursorGuard && cursor !== void 0) {
|
|
27117
|
+
const { cursor_row_min, cursor_row_max, cursor_col_min, cursor_col_max } = target.when;
|
|
27118
|
+
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);
|
|
27119
|
+
if (cursorOk) return true;
|
|
27120
|
+
}
|
|
27121
|
+
if (!target.when.regex) return false;
|
|
26642
27122
|
const haystack = target.when.section ? ev.sections.find((section) => section.id === target.when.section)?.text ?? "" : screen;
|
|
26643
27123
|
if (!haystack) return false;
|
|
26644
27124
|
try {
|
|
@@ -26800,6 +27280,7 @@ var SpecDriver = class {
|
|
|
26800
27280
|
if (this.busyExpiryTimer) clearTimeout(this.busyExpiryTimer);
|
|
26801
27281
|
this.busyExpiryTimer = setTimeout(() => {
|
|
26802
27282
|
this.busyExpiryTimer = null;
|
|
27283
|
+
LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] busyExpiry fired holdMs=${holdMs}`);
|
|
26803
27284
|
this.reevaluate();
|
|
26804
27285
|
}, Math.max(holdMs + 50, 100));
|
|
26805
27286
|
}
|
|
@@ -26824,11 +27305,16 @@ var SpecDriver = class {
|
|
|
26824
27305
|
if (completionKey !== this.completionIdleKey) {
|
|
26825
27306
|
this.completionIdleKey = completionKey;
|
|
26826
27307
|
this.completionIdleFirstSeenAt = now;
|
|
27308
|
+
LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] completion_idle_after matched: key="${completionKey}"`);
|
|
26827
27309
|
}
|
|
26828
27310
|
const holdMs = Math.max(0, completionIdleRule.hold_ms || 0);
|
|
27311
|
+
const forceAfterMs = typeof completionIdleRule.force_after_ms === "number" ? completionIdleRule.force_after_ms : null;
|
|
26829
27312
|
const ageMs = now - this.completionIdleFirstSeenAt;
|
|
26830
27313
|
if (ageMs >= holdMs) {
|
|
26831
|
-
|
|
27314
|
+
const targetMatches = matchesCompletionIdleTargetState(this.spec, ev, screen, cursor);
|
|
27315
|
+
const forced = !targetMatches && forceAfterMs !== null && ageMs >= holdMs + forceAfterMs;
|
|
27316
|
+
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)}"`);
|
|
27317
|
+
if (targetMatches || forced) {
|
|
26832
27318
|
const idle = this.spec.states.find((state) => state.id === this.spec.default_state) ?? this.spec.states.find((state) => state.id === "idle");
|
|
26833
27319
|
evState = idle ? { id: idle.id, label: idle.label, title: null } : { id: "idle", label: "Ready", title: null };
|
|
26834
27320
|
} else {
|
|
@@ -27969,16 +28455,19 @@ var CliProviderInstance = class {
|
|
|
27969
28455
|
controlValues: this.controlValues
|
|
27970
28456
|
});
|
|
27971
28457
|
const activeChatStatus = parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : adapterStatus.status !== "idle" ? visibleStatus : suppressStaleParsedBusyStatus ? visibleStatus : parsedChatStatus || visibleStatus;
|
|
28458
|
+
const hasInteractivePrompt = !!this.activeInteractivePrompt;
|
|
28459
|
+
const finalStatus = hasInteractivePrompt ? "waiting_choice" : visibleStatus;
|
|
28460
|
+
const finalChatStatus = hasInteractivePrompt ? "waiting_choice" : activeChatStatus;
|
|
27972
28461
|
return {
|
|
27973
28462
|
type: this.type,
|
|
27974
28463
|
name: this.provider.name,
|
|
27975
28464
|
category: "cli",
|
|
27976
|
-
status:
|
|
28465
|
+
status: finalStatus,
|
|
27977
28466
|
mode: this.presentationMode,
|
|
27978
28467
|
activeChat: {
|
|
27979
28468
|
id: activeChatId,
|
|
27980
28469
|
title: parsedStatus?.title || dirName,
|
|
27981
|
-
status:
|
|
28470
|
+
status: finalChatStatus,
|
|
27982
28471
|
messages: statusMessages,
|
|
27983
28472
|
activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
27984
28473
|
activeInteractivePrompt: this.activeInteractivePrompt,
|
|
@@ -28449,6 +28938,7 @@ var CliProviderInstance = class {
|
|
|
28449
28938
|
const adapterOwnsMessagesElsewhere = this.adapter?.chatMessagesOwnedExternally === true;
|
|
28450
28939
|
const finalAssistantEvidence = this.completionFinalAssistantEvidence(parsed?.messages);
|
|
28451
28940
|
const allowMissingAssistantTimeout = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
|
|
28941
|
+
LOG.debug("CLI", `[${this.type}] finalAssistantEvidence: present=${finalAssistantEvidence.present} source=${finalAssistantEvidence.source} adapterOwnsMessagesElsewhere=${adapterOwnsMessagesElsewhere} parsedStatus=${parsedStatus}`);
|
|
28452
28942
|
if (!finalAssistantEvidence.present) {
|
|
28453
28943
|
if (adapterOwnsMessagesElsewhere) {
|
|
28454
28944
|
if (finalAssistantEvidence.source === "external-native") {
|
|
@@ -28457,6 +28947,10 @@ var CliProviderInstance = class {
|
|
|
28457
28947
|
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`);
|
|
28458
28948
|
pending.loggedTranscriptProbe = true;
|
|
28459
28949
|
}
|
|
28950
|
+
LOG.debug("CLI", `[${this.type}] external-native probe result: lastRole=${probe?.lastRole} contentLen=${probe?.contentLen}`);
|
|
28951
|
+
if (probe?.lastRole === "assistant" && (probe.contentLen ?? 0) > 0) {
|
|
28952
|
+
return null;
|
|
28953
|
+
}
|
|
28460
28954
|
if (this.type === "antigravity-cli") {
|
|
28461
28955
|
return null;
|
|
28462
28956
|
}
|
|
@@ -28466,6 +28960,7 @@ var CliProviderInstance = class {
|
|
|
28466
28960
|
return { reason: "missing_final_assistant", terminal: true, allowTimeout: allowMissingAssistantTimeout };
|
|
28467
28961
|
}
|
|
28468
28962
|
} else {
|
|
28963
|
+
LOG.debug("CLI", `[${this.type}] missing_final_assistant (not ownsExternal) requiresFinalAssistant=${!!this.provider.requiresFinalAssistantBeforeIdle}`);
|
|
28469
28964
|
return {
|
|
28470
28965
|
reason: "missing_final_assistant",
|
|
28471
28966
|
terminal: this.provider.requiresFinalAssistantBeforeIdle === true,
|
|
@@ -28499,6 +28994,7 @@ var CliProviderInstance = class {
|
|
|
28499
28994
|
const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
|
|
28500
28995
|
const externalNativeFinal = this.getExternalNativeFinalReconciliation(void 0, latestStatus);
|
|
28501
28996
|
const latestVisibleStatus = externalNativeFinal && isCliGeneratingLikeStatus(latestStatus.status) ? "idle" : latestAutoApproveActive ? "generating" : latestStatus.status;
|
|
28997
|
+
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?.()}`);
|
|
28502
28998
|
if (latestVisibleStatus !== "idle") {
|
|
28503
28999
|
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
|
|
28504
29000
|
this.completedDebouncePending = null;
|
|
@@ -28509,6 +29005,7 @@ var CliProviderInstance = class {
|
|
|
28509
29005
|
if (block2) {
|
|
28510
29006
|
const blockReason = block2.reason;
|
|
28511
29007
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
29008
|
+
LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
|
|
28512
29009
|
if (block2.terminal && !block2.allowTimeout || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
|
|
28513
29010
|
if (pending.loggedBlockReason !== blockReason) {
|
|
28514
29011
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
@@ -28623,9 +29120,13 @@ var CliProviderInstance = class {
|
|
|
28623
29120
|
if (newStatus !== this.lastStatus) {
|
|
28624
29121
|
LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
|
|
28625
29122
|
if (this.lastStatus === "idle" && newStatus === "generating") {
|
|
29123
|
+
if (this.completedDebouncePending && this.generatingStartedAt === 0) {
|
|
29124
|
+
LOG.debug("CLI", `[${this.type}] ignoring post-completion PTY generating blip (generatingStartedAt=0)`);
|
|
29125
|
+
return;
|
|
29126
|
+
}
|
|
28626
29127
|
this.suppressIdleHistoryReplay = false;
|
|
28627
29128
|
if (this.completedDebouncePending) {
|
|
28628
|
-
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating)`);
|
|
29129
|
+
LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating) generatingStartedAt=${this.generatingStartedAt} isWaitingForResponse=${!!this.adapter?.isWaitingForResponse}`);
|
|
28629
29130
|
if (this.completedDebounceTimer) {
|
|
28630
29131
|
clearTimeout(this.completedDebounceTimer);
|
|
28631
29132
|
this.completedDebounceTimer = null;
|
|
@@ -28723,7 +29224,10 @@ var CliProviderInstance = class {
|
|
|
28723
29224
|
firstObservedAt: now,
|
|
28724
29225
|
previousStatus: this.lastStatus
|
|
28725
29226
|
};
|
|
28726
|
-
this.
|
|
29227
|
+
const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
|
|
29228
|
+
const flushDelay = ownsExternalHistory ? 0 : 3e3;
|
|
29229
|
+
LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
|
|
29230
|
+
this.scheduleCompletedDebounceFlush(flushDelay);
|
|
28727
29231
|
}
|
|
28728
29232
|
} else if (newStatus === "idle" && this.lastStatus === "starting") {
|
|
28729
29233
|
this.pushEvent({ event: "agent:ready", chatTitle, timestamp: now });
|
|
@@ -41130,9 +41634,9 @@ var DaemonCommandRouter = class {
|
|
|
41130
41634
|
});
|
|
41131
41635
|
let node;
|
|
41132
41636
|
if (meshRecord.inline) {
|
|
41133
|
-
const { randomUUID:
|
|
41637
|
+
const { randomUUID: randomUUID12 } = await import("crypto");
|
|
41134
41638
|
node = {
|
|
41135
|
-
id: `node_${
|
|
41639
|
+
id: `node_${randomUUID12().replace(/-/g, "")}`,
|
|
41136
41640
|
workspace: result.worktreePath,
|
|
41137
41641
|
repoRoot: result.worktreePath,
|
|
41138
41642
|
daemonId: sourceNode.daemonId,
|
|
@@ -49582,7 +50086,7 @@ var SessionHostPtyTransportFactory = class {
|
|
|
49582
50086
|
};
|
|
49583
50087
|
|
|
49584
50088
|
// src/cli-adapters/raw-terminal-io.ts
|
|
49585
|
-
import { randomUUID as
|
|
50089
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
49586
50090
|
import {
|
|
49587
50091
|
SessionHostClient as SessionHostClient2
|
|
49588
50092
|
} from "@adhdev/session-host-core";
|
|
@@ -49682,7 +50186,7 @@ var RawTerminalAttachment = class _RawTerminalAttachment {
|
|
|
49682
50186
|
const sessionId = String(options.sessionId || "").trim();
|
|
49683
50187
|
if (!sessionId) throw new Error("sessionId is required");
|
|
49684
50188
|
const mode = options.mode || "read";
|
|
49685
|
-
const clientId = options.clientId || `raw-terminal-${process.pid}-${
|
|
50189
|
+
const clientId = options.clientId || `raw-terminal-${process.pid}-${randomUUID11().slice(0, 8)}`;
|
|
49686
50190
|
const client = options.client || new SessionHostClient2({ endpoint: options.endpoint });
|
|
49687
50191
|
await client.connect();
|
|
49688
50192
|
const attachResponse = await client.request({
|
|
@@ -50798,6 +51302,7 @@ export {
|
|
|
50798
51302
|
createInteractionId,
|
|
50799
51303
|
createMesh,
|
|
50800
51304
|
createNativeHistoryDispatcher,
|
|
51305
|
+
createSessionDelivery,
|
|
50801
51306
|
createWorktree,
|
|
50802
51307
|
deleteMesh,
|
|
50803
51308
|
detectAllVersions,
|
|
@@ -50821,6 +51326,7 @@ export {
|
|
|
50821
51326
|
forwardAgentStreamsToIdeInstance,
|
|
50822
51327
|
getAIExtensions,
|
|
50823
51328
|
getActiveDirectDispatches,
|
|
51329
|
+
getActiveSessionDeliveries,
|
|
50824
51330
|
getAvailableIdeIds,
|
|
50825
51331
|
getCoordinatorForSession,
|
|
50826
51332
|
getCurrentDaemonLogPath,
|
|
@@ -50843,6 +51349,7 @@ export {
|
|
|
50843
51349
|
getQueue,
|
|
50844
51350
|
getRecentActivity,
|
|
50845
51351
|
getRecentCommands,
|
|
51352
|
+
getRecentCompletionConflicts,
|
|
50846
51353
|
getRecentDebugTrace,
|
|
50847
51354
|
getRecentLogs,
|
|
50848
51355
|
getSavedProviderSessions,
|
|
@@ -50930,6 +51437,7 @@ export {
|
|
|
50930
51437
|
readLedgerEntries,
|
|
50931
51438
|
readLedgerSlice,
|
|
50932
51439
|
reconcileDirectDispatchCompletionFromTranscript,
|
|
51440
|
+
recordCompletionConflict,
|
|
50933
51441
|
recordDebugTrace,
|
|
50934
51442
|
registerExtensionProviders,
|
|
50935
51443
|
registerMeshCoordinator,
|
|
@@ -50943,6 +51451,7 @@ export {
|
|
|
50943
51451
|
resolveChatMessageKind,
|
|
50944
51452
|
resolveCurrentGlobalInstallSurface,
|
|
50945
51453
|
resolveDebugRuntimeConfig,
|
|
51454
|
+
resolveDeliveryDecision,
|
|
50946
51455
|
resolveGitRepository,
|
|
50947
51456
|
resolveMeshHostStatus,
|
|
50948
51457
|
resolveMeshRefineValidationPlan,
|
|
@@ -50972,6 +51481,7 @@ export {
|
|
|
50972
51481
|
updateDirectDispatchStatus,
|
|
50973
51482
|
updateMesh,
|
|
50974
51483
|
updateNode,
|
|
51484
|
+
updateSessionDeliveryStatus,
|
|
50975
51485
|
updateSessionTaskStatus,
|
|
50976
51486
|
updateTaskStatus,
|
|
50977
51487
|
upsertSavedProviderSession,
|