@adhdev/daemon-core 0.9.82-rc.194 → 0.9.82-rc.196

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.
Files changed (37) hide show
  1. package/dist/cli-adapter-types.d.ts +1 -0
  2. package/dist/index.js +202 -70
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +205 -73
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/mesh/contracts.d.ts +1 -1
  7. package/dist/mesh/mesh-active-work.d.ts +1 -1
  8. package/dist/mesh/{beads-db.d.ts → mesh-runtime-store.d.ts} +2 -2
  9. package/dist/mesh/mesh-work-queue.d.ts +3 -3
  10. package/dist/providers/provider-instance.d.ts +1 -1
  11. package/dist/providers/spec/driver.d.ts +4 -1
  12. package/dist/providers/spec/schema.gen.d.ts +46 -0
  13. package/dist/providers/spec/types.d.ts +39 -0
  14. package/dist/shared-types-extra.d.ts +1 -1
  15. package/dist/status/normalize.d.ts +1 -1
  16. package/dist/status/normalize.js +1 -0
  17. package/dist/status/normalize.js.map +1 -1
  18. package/dist/status/normalize.mjs +1 -0
  19. package/dist/status/normalize.mjs.map +1 -1
  20. package/package.json +1 -1
  21. package/src/cli-adapter-types.ts +1 -0
  22. package/src/cli-adapters/cli-state-engine.ts +44 -2
  23. package/src/mesh/contracts.ts +1 -1
  24. package/src/mesh/mesh-active-work.ts +8 -8
  25. package/src/mesh/mesh-events.ts +12 -12
  26. package/src/mesh/{beads-db.ts → mesh-runtime-store.ts} +30 -7
  27. package/src/mesh/mesh-work-queue.ts +33 -33
  28. package/src/providers/cli-provider-instance.ts +31 -8
  29. package/src/providers/provider-instance.ts +1 -1
  30. package/src/providers/spec/driver.ts +34 -3
  31. package/src/providers/spec/evaluator.ts +32 -3
  32. package/src/providers/spec/schema.gen.ts +22 -2
  33. package/src/providers/spec/schema.json +1 -0
  34. package/src/providers/spec/types.ts +39 -0
  35. package/src/providers/types/interactive-prompt.ts +21 -7
  36. package/src/shared-types-extra.ts +1 -1
  37. 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/beads-db.ts
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
- var import_fs7, import_path7, import_module, import_meta, DatabaseCtor, BeadsDB;
3312
- var init_beads_db = __esm({
3313
- "src/mesh/beads-db.ts"() {
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
- BeadsDB = class _BeadsDB {
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 _BeadsDB((0, import_path7.join)(getLedgerDir(), "beads.db"));
3362
+ this.instance = new _MeshRuntimeStore(meshRuntimeStorePath());
3345
3363
  }
3346
3364
  return this.instance;
3347
3365
  }
@@ -3426,13 +3444,13 @@ var init_beads_db = __esm({
3426
3444
  this.db.prepare("DELETE FROM mesh_completion_fingerprints WHERE expires_at <= ?").run(Date.now());
3427
3445
  }
3428
3446
  maybeCheckpointWal() {
3429
- if (++this.walWriteCounter < _BeadsDB.WAL_CHECK_INTERVAL) return;
3447
+ if (++this.walWriteCounter < _MeshRuntimeStore.WAL_CHECK_INTERVAL) return;
3430
3448
  this.walWriteCounter = 0;
3431
3449
  try {
3432
3450
  const walPath = `${this.dbPath}-wal`;
3433
3451
  if (!(0, import_fs7.existsSync)(walPath)) return;
3434
3452
  const size = (0, import_fs7.statSync)(walPath).size;
3435
- if (size < _BeadsDB.WAL_MAX_BYTES) return;
3453
+ if (size < _MeshRuntimeStore.WAL_MAX_BYTES) return;
3436
3454
  process.stderr.write(
3437
3455
  `[adhdev-mesh] WAL file ${Math.round(size / 1024 / 1024)}MB exceeds threshold; forcing checkpoint
3438
3456
  `
@@ -3743,7 +3761,7 @@ __export(mesh_work_queue_exports, {
3743
3761
  __clearDirectDispatchesForTests: () => __clearDirectDispatchesForTests,
3744
3762
  __clearMeshQueueForTests: () => __clearMeshQueueForTests,
3745
3763
  __replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
3746
- __resetBeadsDBForTests: () => __resetBeadsDBForTests,
3764
+ __resetMeshRuntimeStoreForTests: () => __resetMeshRuntimeStoreForTests,
3747
3765
  buildMeshNodeCapabilityTags: () => buildMeshNodeCapabilityTags,
3748
3766
  cancelTask: () => cancelTask,
3749
3767
  claimNextTask: () => claimNextTask,
@@ -3821,7 +3839,7 @@ function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
3821
3839
  return required.every((tag) => available.has(tag));
3822
3840
  }
3823
3841
  function withQueueLock(_meshId, fn) {
3824
- return BeadsDB.getInstance().transaction(fn);
3842
+ return MeshRuntimeStore.getInstance().transaction(fn);
3825
3843
  }
3826
3844
  function enqueueTask(meshId, message, opts) {
3827
3845
  requireMeshHostQueueOwner(opts);
@@ -3841,55 +3859,55 @@ function enqueueTask(meshId, message, opts) {
3841
3859
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3842
3860
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3843
3861
  };
3844
- BeadsDB.getInstance().insertQueueEntry(entry);
3862
+ MeshRuntimeStore.getInstance().insertQueueEntry(entry);
3845
3863
  return entry;
3846
3864
  }
3847
3865
  function getQueue(meshId, opts) {
3848
- return BeadsDB.getInstance().getQueueEntries(meshId, opts?.status?.length ? opts.status : void 0);
3866
+ return MeshRuntimeStore.getInstance().getQueueEntries(meshId, opts?.status?.length ? opts.status : void 0);
3849
3867
  }
3850
3868
  function getMeshQueueRevision(meshId) {
3851
- return BeadsDB.getInstance().getQueueRevision(meshId);
3869
+ return MeshRuntimeStore.getInstance().getQueueRevision(meshId);
3852
3870
  }
3853
3871
  function claimNextTask(meshId, nodeId, sessionId, capabilityTags) {
3854
- return BeadsDB.getInstance().claimNextQueueTask(meshId, nodeId, sessionId, capabilityTags);
3872
+ return MeshRuntimeStore.getInstance().claimNextQueueTask(meshId, nodeId, sessionId, capabilityTags);
3855
3873
  }
3856
3874
  function updateTaskStatus(meshId, taskId, status, opts) {
3857
3875
  requireMeshHostQueueOwner(opts);
3858
3876
  return withQueueLock(meshId, () => {
3859
- const entry = BeadsDB.getInstance().findQueueEntryById(meshId, taskId);
3877
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
3860
3878
  if (!entry) return null;
3861
3879
  entry.status = status;
3862
- BeadsDB.getInstance().updateQueueEntry(entry);
3880
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
3863
3881
  return entry;
3864
3882
  });
3865
3883
  }
3866
3884
  function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
3867
3885
  return withQueueLock(meshId, () => {
3868
- const entry = BeadsDB.getInstance().findQueueEntryById(meshId, taskId);
3886
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
3869
3887
  if (!entry) return null;
3870
3888
  const now = (/* @__PURE__ */ new Date()).toISOString();
3871
3889
  entry.autoLaunch = { ...autoLaunch, updatedAt: now };
3872
- BeadsDB.getInstance().updateQueueEntry(entry);
3890
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
3873
3891
  return entry;
3874
3892
  });
3875
3893
  }
3876
3894
  function cancelTask(meshId, taskId, opts) {
3877
3895
  requireMeshHostQueueOwner(opts);
3878
3896
  return withQueueLock(meshId, () => {
3879
- const entry = BeadsDB.getInstance().findQueueEntryById(meshId, taskId);
3897
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
3880
3898
  if (!entry) return null;
3881
3899
  const now = (/* @__PURE__ */ new Date()).toISOString();
3882
3900
  entry.status = "cancelled";
3883
3901
  entry.cancelledAt = now;
3884
3902
  if (opts?.reason) entry.cancelReason = opts.reason;
3885
- BeadsDB.getInstance().updateQueueEntry(entry);
3903
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
3886
3904
  return entry;
3887
3905
  });
3888
3906
  }
3889
3907
  function requeueTask(meshId, taskId, opts) {
3890
3908
  requireMeshHostQueueOwner(opts);
3891
3909
  return withQueueLock(meshId, () => {
3892
- const entry = BeadsDB.getInstance().findQueueEntryById(meshId, taskId);
3910
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
3893
3911
  if (!entry) return null;
3894
3912
  entry.status = "pending";
3895
3913
  delete entry.assignedNodeId;
@@ -3903,22 +3921,22 @@ function requeueTask(meshId, taskId, opts) {
3903
3921
  entry.requeuedAt = (/* @__PURE__ */ new Date()).toISOString();
3904
3922
  entry.requeueCount = (entry.requeueCount || 0) + 1;
3905
3923
  if (opts?.reason) entry.requeueReason = opts.reason;
3906
- BeadsDB.getInstance().updateQueueEntry(entry);
3924
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
3907
3925
  return entry;
3908
3926
  });
3909
3927
  }
3910
3928
  function updateSessionTaskStatus(meshId, sessionId, status, opts) {
3911
3929
  return withQueueLock(meshId, () => {
3912
3930
  const occurredAtIso = opts?.occurredAt ? new Date(opts.occurredAt).toISOString() : void 0;
3913
- const entry = BeadsDB.getInstance().findAssignedBySession(meshId, sessionId, occurredAtIso);
3931
+ const entry = MeshRuntimeStore.getInstance().findAssignedBySession(meshId, sessionId, occurredAtIso);
3914
3932
  if (!entry) return null;
3915
3933
  entry.status = status;
3916
- BeadsDB.getInstance().updateQueueEntry(entry);
3934
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
3917
3935
  return entry;
3918
3936
  });
3919
3937
  }
3920
3938
  function getMeshQueueStats(meshId) {
3921
- const rows = BeadsDB.getInstance().getQueueStatsByStatus(meshId);
3939
+ const rows = MeshRuntimeStore.getInstance().getQueueStatsByStatus(meshId);
3922
3940
  const counts = {};
3923
3941
  for (const r of rows) counts[r.status] = r.count;
3924
3942
  const pending = counts["pending"] ?? 0;
@@ -3937,26 +3955,26 @@ function getMeshQueueStats(meshId) {
3937
3955
  cancelled,
3938
3956
  activeCounts: { pending, assigned },
3939
3957
  historicalCounts: { completed, failed, cancelled },
3940
- activeAssignments: BeadsDB.getInstance().getActiveAssignmentDetails(meshId)
3958
+ activeAssignments: MeshRuntimeStore.getInstance().getActiveAssignmentDetails(meshId)
3941
3959
  };
3942
3960
  }
3943
3961
  function __replaceMeshQueueForTests(meshId, queue) {
3944
- BeadsDB.getInstance().transaction(() => {
3945
- BeadsDB.getInstance().replaceQueue(meshId, queue);
3962
+ MeshRuntimeStore.getInstance().transaction(() => {
3963
+ MeshRuntimeStore.getInstance().replaceQueue(meshId, queue);
3946
3964
  });
3947
3965
  }
3948
3966
  function __clearMeshQueueForTests(meshId) {
3949
- BeadsDB.getInstance().deleteQueue(meshId);
3967
+ MeshRuntimeStore.getInstance().deleteQueue(meshId);
3950
3968
  }
3951
3969
  function __clearDirectDispatchesForTests(meshId) {
3952
- BeadsDB.getInstance().deleteDirectDispatches(meshId);
3970
+ MeshRuntimeStore.getInstance().deleteDirectDispatches(meshId);
3953
3971
  }
3954
- function __resetBeadsDBForTests() {
3955
- BeadsDB.resetForTests();
3972
+ function __resetMeshRuntimeStoreForTests() {
3973
+ MeshRuntimeStore.resetForTests();
3956
3974
  }
3957
3975
  function insertDirectDispatch(meshId, data) {
3958
3976
  try {
3959
- BeadsDB.getInstance().insertDirectDispatch({ ...data, meshId });
3977
+ MeshRuntimeStore.getInstance().insertDirectDispatch({ ...data, meshId });
3960
3978
  } catch (e) {
3961
3979
  process.stderr.write(`[adhdev-mesh] insertDirectDispatch failed for task ${data.taskId}: ${e?.message || e}
3962
3980
  `);
@@ -3964,26 +3982,26 @@ function insertDirectDispatch(meshId, data) {
3964
3982
  }
3965
3983
  function getActiveDirectDispatches(meshId) {
3966
3984
  try {
3967
- return BeadsDB.getInstance().getActiveDirectDispatches(meshId);
3985
+ return MeshRuntimeStore.getInstance().getActiveDirectDispatches(meshId);
3968
3986
  } catch {
3969
3987
  return [];
3970
3988
  }
3971
3989
  }
3972
3990
  function updateDirectDispatchStatus(meshId, sessionId, status) {
3973
3991
  try {
3974
- BeadsDB.getInstance().updateDirectDispatchStatus(meshId, sessionId, status);
3992
+ MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status);
3975
3993
  } catch {
3976
3994
  }
3977
3995
  }
3978
3996
  function cleanupTerminalDirectDispatches(olderThanMs = 7 * 24 * 60 * 6e4) {
3979
3997
  try {
3980
- BeadsDB.getInstance().cleanupTerminalDirectDispatches(olderThanMs);
3998
+ MeshRuntimeStore.getInstance().cleanupTerminalDirectDispatches(olderThanMs);
3981
3999
  } catch {
3982
4000
  }
3983
4001
  }
3984
4002
  function markStaleDirectDispatches(meshId, olderThanMs = 60 * 6e4) {
3985
4003
  try {
3986
- BeadsDB.getInstance().markStaleDirectDispatches(meshId, olderThanMs);
4004
+ MeshRuntimeStore.getInstance().markStaleDirectDispatches(meshId, olderThanMs);
3987
4005
  } catch {
3988
4006
  }
3989
4007
  }
@@ -3993,7 +4011,7 @@ var init_mesh_work_queue = __esm({
3993
4011
  "use strict";
3994
4012
  import_crypto5 = require("crypto");
3995
4013
  init_mesh_host_ownership();
3996
- init_beads_db();
4014
+ init_mesh_runtime_store();
3997
4015
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
3998
4016
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
3999
4017
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -4174,7 +4192,7 @@ function __resetIdleAutoFastForwardForTests() {
4174
4192
  }
4175
4193
  function sweepExpiredRemoteIdleSessions() {
4176
4194
  try {
4177
- BeadsDB.getInstance().pruneExpiredRemoteIdleSessions();
4195
+ MeshRuntimeStore.getInstance().pruneExpiredRemoteIdleSessions();
4178
4196
  } catch {
4179
4197
  }
4180
4198
  }
@@ -4450,14 +4468,14 @@ function shouldSuppressIntentionalCleanupStop(args) {
4450
4468
  }
4451
4469
  function hasFingerprintSeen(fingerprint) {
4452
4470
  try {
4453
- return BeadsDB.getInstance().hasCompletionFingerprint(fingerprint);
4471
+ return MeshRuntimeStore.getInstance().hasCompletionFingerprint(fingerprint);
4454
4472
  } catch {
4455
4473
  return false;
4456
4474
  }
4457
4475
  }
4458
4476
  function recordFingerprintSeen(fingerprint) {
4459
4477
  try {
4460
- const db = BeadsDB.getInstance();
4478
+ const db = MeshRuntimeStore.getInstance();
4461
4479
  db.recordCompletionFingerprint(fingerprint, RECENT_COMPLETION_FINGERPRINT_TTL_MS);
4462
4480
  db.sweepExpiredFingerprints();
4463
4481
  } catch {
@@ -5077,7 +5095,7 @@ async function triggerMeshQueue(components, meshId) {
5077
5095
  }
5078
5096
  let remoteSessions = [];
5079
5097
  try {
5080
- remoteSessions = BeadsDB.getInstance().getRemoteIdleSessions();
5098
+ remoteSessions = MeshRuntimeStore.getInstance().getRemoteIdleSessions();
5081
5099
  } catch {
5082
5100
  }
5083
5101
  for (const idle of remoteSessions) {
@@ -5087,7 +5105,7 @@ async function triggerMeshQueue(components, meshId) {
5087
5105
  const assigned = tryAssignQueueTask(components, meshId, idle.nodeId, idle.sessionId, idle.providerType);
5088
5106
  if (assigned) {
5089
5107
  try {
5090
- BeadsDB.getInstance().deleteRemoteIdleSession(idle.nodeId, idle.sessionId);
5108
+ MeshRuntimeStore.getInstance().deleteRemoteIdleSession(idle.nodeId, idle.sessionId);
5091
5109
  } catch {
5092
5110
  }
5093
5111
  }
@@ -5289,7 +5307,7 @@ function injectMeshSystemMessage(components, args) {
5289
5307
  if (intentionalCleanupStop) {
5290
5308
  if (eventSessionId && eventNodeId) {
5291
5309
  try {
5292
- BeadsDB.getInstance().deleteRemoteIdleSession(eventNodeId, eventSessionId);
5310
+ MeshRuntimeStore.getInstance().deleteRemoteIdleSession(eventNodeId, eventSessionId);
5293
5311
  } catch {
5294
5312
  }
5295
5313
  }
@@ -5457,14 +5475,14 @@ function injectMeshSystemMessage(components, args) {
5457
5475
  if (sessionId && nodeId && providerType) {
5458
5476
  sweepExpiredRemoteIdleSessions();
5459
5477
  try {
5460
- BeadsDB.getInstance().setRemoteIdleSession(nodeId, sessionId, providerType, Date.now() + REMOTE_IDLE_SESSION_TTL_MS);
5478
+ MeshRuntimeStore.getInstance().setRemoteIdleSession(nodeId, sessionId, providerType, Date.now() + REMOTE_IDLE_SESSION_TTL_MS);
5461
5479
  } catch {
5462
5480
  }
5463
5481
  setImmediate(() => {
5464
5482
  maybeAutoFastForwardIdleNode(components, { meshId: args.meshId, nodeId, sessionId, providerType }).finally(() => {
5465
5483
  try {
5466
5484
  const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
5467
- if (assigned) BeadsDB.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
5485
+ if (assigned) MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
5468
5486
  } catch (e) {
5469
5487
  LOG.warn("MeshQueue", `Failed to assign idle queue task after maintenance for ${nodeId}: ${e?.message || e}`);
5470
5488
  }
@@ -5476,7 +5494,7 @@ function injectMeshSystemMessage(components, args) {
5476
5494
  const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
5477
5495
  if (sessionId && nodeId) {
5478
5496
  try {
5479
- BeadsDB.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
5497
+ MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
5480
5498
  } catch {
5481
5499
  }
5482
5500
  }
@@ -5488,7 +5506,7 @@ function injectMeshSystemMessage(components, args) {
5488
5506
  const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
5489
5507
  if (sessionId && nodeId) {
5490
5508
  try {
5491
- BeadsDB.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
5509
+ MeshRuntimeStore.getInstance().deleteRemoteIdleSession(nodeId, sessionId);
5492
5510
  } catch {
5493
5511
  }
5494
5512
  }
@@ -5762,7 +5780,7 @@ var init_mesh_events = __esm({
5762
5780
  init_logger();
5763
5781
  init_mesh_ledger();
5764
5782
  init_mesh_work_queue();
5765
- init_beads_db();
5783
+ init_mesh_runtime_store();
5766
5784
  init_mesh_fast_forward();
5767
5785
  REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
5768
5786
  meshByWorkspaceCache = /* @__PURE__ */ new Map();
@@ -8710,11 +8728,12 @@ var init_cli_state_engine = __esm({
8710
8728
  }
8711
8729
  applyGenerating(ctx) {
8712
8730
  const { modal, parsedMessages, lastParsedAssistant, parsedStatus, prevStatus } = ctx;
8731
+ const noActiveTurn = !this.currentTurnScope;
8732
+ if (!this.isWaitingForResponse && noActiveTurn && !modal) return;
8713
8733
  this.clearIdleFinishCandidate("generating");
8714
8734
  this.cancelPendingIdleFinish("generating_signal_returned");
8715
8735
  const snap = this.transport.getSnapshot();
8716
8736
  const effectiveScreenText = snap.screenText || snap.accumulatedBuffer;
8717
- const noActiveTurn = !this.currentTurnScope;
8718
8737
  const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
8719
8738
  const parsedShowsLiveProgress = parsedStatus === "generating" && !!lastParsedAssistant;
8720
8739
  if (prevStatus === "idle" && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveProgress) return;
@@ -8974,7 +8993,25 @@ var init_cli_state_engine = __esm({
8974
8993
  const parsedStatus = typeof parsed?.status === "string" ? parsed.status.trim() : "";
8975
8994
  if (parsedStatus !== "idle") return true;
8976
8995
  if (parsed?.activeModal || parsed?.modal) return true;
8977
- return !this.parsedStatusHasFinalStandardAssistantMessage(parsed);
8996
+ const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
8997
+ let lastUserIdx = -1;
8998
+ for (let i = messages.length - 1; i >= 0; i--) {
8999
+ if (messages[i]?.role === "user") {
9000
+ lastUserIdx = i;
9001
+ break;
9002
+ }
9003
+ }
9004
+ if (lastUserIdx < 0) {
9005
+ if (messages.length === 0) return false;
9006
+ return !this.parsedStatusHasFinalStandardAssistantMessage(parsed);
9007
+ }
9008
+ const hasCurrentTurnAssistant = messages.slice(lastUserIdx + 1).some((m) => {
9009
+ if (!m || m.role !== "assistant") return false;
9010
+ if (typeof m.content !== "string" || !m.content.trim()) return false;
9011
+ const kind = typeof m.kind === "string" && m.kind.trim() ? m.kind.trim() : "standard";
9012
+ return kind === "standard" && m.meta?.streaming !== true;
9013
+ });
9014
+ return !hasCurrentTurnAssistant;
8978
9015
  }
8979
9016
  rescheduleTranscriptFinishCheck(reason) {
8980
9017
  this.clearIdleFinishCandidate(reason);
@@ -11742,14 +11779,19 @@ function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
11742
11779
  if (question.multiSelect) throw new Error("Claude TUI multi-select prompts are not supported yet");
11743
11780
  const answer = response.answers[question.questionId];
11744
11781
  if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
11745
- if (answer.freeformText) throw new Error("Claude TUI freeform answers are not supported yet");
11746
- if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
11747
- const selectedIndex = question.options.findIndex((option) => option.label === answer.selectedLabels[0]);
11748
- if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
11749
- for (let i = 0; i < selectedIndex; i += 1) {
11750
- steps.push("\x1B[B");
11782
+ const freeformText = answer.freeformText?.trim() ?? "";
11783
+ if (freeformText) {
11784
+ const typeOptionIndex = question.options.findIndex((o) => /^Type something\.?$/i.test(o.label));
11785
+ const optionNumber = typeOptionIndex >= 0 ? typeOptionIndex + 1 : question.options.length;
11786
+ steps.push(String(optionNumber));
11787
+ for (const ch of freeformText) steps.push(ch);
11788
+ steps.push("\r");
11789
+ } else {
11790
+ if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
11791
+ const selectedIndex = question.options.findIndex((option) => option.label === answer.selectedLabels[0]);
11792
+ if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
11793
+ steps.push(String(selectedIndex + 1));
11751
11794
  }
11752
- steps.push("\r");
11753
11795
  }
11754
11796
  steps.push("\r");
11755
11797
  return steps;
@@ -20082,6 +20124,7 @@ function normalizeManagedStatus(status, opts) {
20082
20124
  if (hasApprovalButtons(opts?.activeModal)) return "waiting_approval";
20083
20125
  const normalized = String(status || "idle").trim().toLowerCase();
20084
20126
  if (normalized === "waiting_approval") return "waiting_approval";
20127
+ if (normalized === "waiting_choice") return "waiting_choice";
20085
20128
  if (WORKING_STATUSES.has(normalized)) return "generating";
20086
20129
  if (normalized === "error") return "error";
20087
20130
  if (normalized === "stopped") return "stopped";
@@ -26100,10 +26143,47 @@ function resolveSections(spec, lines) {
26100
26143
  for (const sec of spec.layout.sections) {
26101
26144
  let from = 0;
26102
26145
  let to = total;
26103
- if (sec.from_top !== void 0) {
26146
+ if (sec.anchor_regex !== void 0) {
26147
+ try {
26148
+ const re = new RegExp(sec.anchor_regex, sec.anchor_flags ?? "");
26149
+ const prevRe = sec.anchor_context?.prev !== void 0 ? new RegExp(sec.anchor_context.prev, sec.anchor_context.prev_flags ?? "") : null;
26150
+ const nextRe = sec.anchor_context?.next !== void 0 ? new RegExp(sec.anchor_context.next, sec.anchor_context.next_flags ?? "") : null;
26151
+ 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]));
26152
+ let idx = -1;
26153
+ if (sec.anchor_last) {
26154
+ for (let i = total - 1; i >= 0; i--) {
26155
+ if (matches(i)) {
26156
+ idx = i;
26157
+ break;
26158
+ }
26159
+ }
26160
+ } else {
26161
+ for (let i = 0; i < total; i++) {
26162
+ if (matches(i)) {
26163
+ idx = i;
26164
+ break;
26165
+ }
26166
+ }
26167
+ }
26168
+ if (idx !== -1) {
26169
+ from = idx;
26170
+ to = total;
26171
+ if (sec.until_regex !== void 0) {
26172
+ try {
26173
+ const ure = new RegExp(sec.until_regex, sec.until_regex_flags ?? "");
26174
+ const end = lines.findIndex((l, i) => i > idx && ure.test(l));
26175
+ if (end !== -1) to = end;
26176
+ } catch {
26177
+ }
26178
+ } else if (sec.lines !== void 0) {
26179
+ to = Math.min(total, from + sec.lines);
26180
+ }
26181
+ }
26182
+ } catch {
26183
+ }
26184
+ } else if (sec.from_top !== void 0) {
26104
26185
  from = resolveSize(sec.from_top, total);
26105
- }
26106
- if (sec.from_bottom !== void 0) {
26186
+ } else if (sec.from_bottom !== void 0) {
26107
26187
  const sz = resolveSize(sec.from_bottom, total);
26108
26188
  from = total - sz;
26109
26189
  to = total;
@@ -26421,6 +26501,9 @@ var SCHEMA = {
26421
26501
  "type": "string",
26422
26502
  "minLength": 1
26423
26503
  },
26504
+ "requiresFinalAssistantBeforeIdle": {
26505
+ "type": "boolean"
26506
+ },
26424
26507
  "debounce": {
26425
26508
  "type": "object",
26426
26509
  "additionalProperties": false,
@@ -26435,7 +26518,8 @@ var SCHEMA = {
26435
26518
  "section": { "type": "string", "minLength": 1 },
26436
26519
  "regex": { "type": "string", "minLength": 1 },
26437
26520
  "flags": { "type": "string" },
26438
- "hold_ms": { "type": "integer", "minimum": 0 }
26521
+ "hold_ms": { "type": "integer", "minimum": 0 },
26522
+ "force_after_ms": { "type": "integer", "minimum": 0 }
26439
26523
  }
26440
26524
  }
26441
26525
  }
@@ -26483,7 +26567,23 @@ var SCHEMA = {
26483
26567
  "type": "string"
26484
26568
  }
26485
26569
  }
26486
- }
26570
+ },
26571
+ "anchor_regex": { "type": "string", "minLength": 1 },
26572
+ "anchor_flags": { "type": "string" },
26573
+ "anchor_last": { "type": "boolean" },
26574
+ "anchor_context": {
26575
+ "type": "object",
26576
+ "additionalProperties": false,
26577
+ "properties": {
26578
+ "prev": { "type": "string" },
26579
+ "prev_flags": { "type": "string" },
26580
+ "next": { "type": "string" },
26581
+ "next_flags": { "type": "string" }
26582
+ }
26583
+ },
26584
+ "lines": { "type": "integer", "minimum": 1 },
26585
+ "until_regex": { "type": "string", "minLength": 1 },
26586
+ "until_regex_flags": { "type": "string" }
26487
26587
  }
26488
26588
  },
26489
26589
  "sectionRegex": {
@@ -26919,6 +27019,7 @@ function resolveSpecPath(providerDir) {
26919
27019
  }
26920
27020
 
26921
27021
  // src/providers/spec/driver.ts
27022
+ init_logger();
26922
27023
  var STARTUP_GRACE_MS = 2500;
26923
27024
  var BUSY_HOLD_MS = 6e3;
26924
27025
  var SUBMIT_DELAY_FLOOR_MS = 200;
@@ -26946,9 +27047,16 @@ function matchesCompletionIdleRule(spec, ev, screen) {
26946
27047
  return null;
26947
27048
  }
26948
27049
  }
26949
- function matchesCompletionIdleTargetState(spec, ev, screen) {
27050
+ function matchesCompletionIdleTargetState(spec, ev, screen, cursor) {
26950
27051
  const target = spec.states.find((state) => state.id === spec.default_state) ?? spec.states.find((state) => state.id === "idle");
26951
- if (!target?.when?.regex) return false;
27052
+ if (!target?.when) return false;
27053
+ 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;
27054
+ if (hasCursorGuard && cursor !== void 0) {
27055
+ const { cursor_row_min, cursor_row_max, cursor_col_min, cursor_col_max } = target.when;
27056
+ 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);
27057
+ if (cursorOk) return true;
27058
+ }
27059
+ if (!target.when.regex) return false;
26952
27060
  const haystack = target.when.section ? ev.sections.find((section) => section.id === target.when.section)?.text ?? "" : screen;
26953
27061
  if (!haystack) return false;
26954
27062
  try {
@@ -27110,6 +27218,7 @@ var SpecDriver = class {
27110
27218
  if (this.busyExpiryTimer) clearTimeout(this.busyExpiryTimer);
27111
27219
  this.busyExpiryTimer = setTimeout(() => {
27112
27220
  this.busyExpiryTimer = null;
27221
+ LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] busyExpiry fired holdMs=${holdMs}`);
27113
27222
  this.reevaluate();
27114
27223
  }, Math.max(holdMs + 50, 100));
27115
27224
  }
@@ -27134,11 +27243,16 @@ var SpecDriver = class {
27134
27243
  if (completionKey !== this.completionIdleKey) {
27135
27244
  this.completionIdleKey = completionKey;
27136
27245
  this.completionIdleFirstSeenAt = now;
27246
+ LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] completion_idle_after matched: key="${completionKey}"`);
27137
27247
  }
27138
27248
  const holdMs = Math.max(0, completionIdleRule.hold_ms || 0);
27249
+ const forceAfterMs = typeof completionIdleRule.force_after_ms === "number" ? completionIdleRule.force_after_ms : null;
27139
27250
  const ageMs = now - this.completionIdleFirstSeenAt;
27140
27251
  if (ageMs >= holdMs) {
27141
- if (matchesCompletionIdleTargetState(this.spec, ev, screen)) {
27252
+ const targetMatches = matchesCompletionIdleTargetState(this.spec, ev, screen, cursor);
27253
+ const forced = !targetMatches && forceAfterMs !== null && ageMs >= holdMs + forceAfterMs;
27254
+ 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)}"`);
27255
+ if (targetMatches || forced) {
27142
27256
  const idle = this.spec.states.find((state) => state.id === this.spec.default_state) ?? this.spec.states.find((state) => state.id === "idle");
27143
27257
  evState = idle ? { id: idle.id, label: idle.label, title: null } : { id: "idle", label: "Ready", title: null };
27144
27258
  } else {
@@ -28279,16 +28393,19 @@ var CliProviderInstance = class {
28279
28393
  controlValues: this.controlValues
28280
28394
  });
28281
28395
  const activeChatStatus = parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : adapterStatus.status !== "idle" ? visibleStatus : suppressStaleParsedBusyStatus ? visibleStatus : parsedChatStatus || visibleStatus;
28396
+ const hasInteractivePrompt = !!this.activeInteractivePrompt;
28397
+ const finalStatus = hasInteractivePrompt ? "waiting_choice" : visibleStatus;
28398
+ const finalChatStatus = hasInteractivePrompt ? "waiting_choice" : activeChatStatus;
28282
28399
  return {
28283
28400
  type: this.type,
28284
28401
  name: this.provider.name,
28285
28402
  category: "cli",
28286
- status: visibleStatus,
28403
+ status: finalStatus,
28287
28404
  mode: this.presentationMode,
28288
28405
  activeChat: {
28289
28406
  id: activeChatId,
28290
28407
  title: parsedStatus?.title || dirName,
28291
- status: activeChatStatus,
28408
+ status: finalChatStatus,
28292
28409
  messages: statusMessages,
28293
28410
  activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
28294
28411
  activeInteractivePrompt: this.activeInteractivePrompt,
@@ -28759,6 +28876,7 @@ var CliProviderInstance = class {
28759
28876
  const adapterOwnsMessagesElsewhere = this.adapter?.chatMessagesOwnedExternally === true;
28760
28877
  const finalAssistantEvidence = this.completionFinalAssistantEvidence(parsed?.messages);
28761
28878
  const allowMissingAssistantTimeout = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
28879
+ LOG.debug("CLI", `[${this.type}] finalAssistantEvidence: present=${finalAssistantEvidence.present} source=${finalAssistantEvidence.source} adapterOwnsMessagesElsewhere=${adapterOwnsMessagesElsewhere} parsedStatus=${parsedStatus}`);
28762
28880
  if (!finalAssistantEvidence.present) {
28763
28881
  if (adapterOwnsMessagesElsewhere) {
28764
28882
  if (finalAssistantEvidence.source === "external-native") {
@@ -28767,6 +28885,10 @@ var CliProviderInstance = class {
28767
28885
  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
28886
  pending.loggedTranscriptProbe = true;
28769
28887
  }
28888
+ LOG.debug("CLI", `[${this.type}] external-native probe result: lastRole=${probe?.lastRole} contentLen=${probe?.contentLen}`);
28889
+ if (probe?.lastRole === "assistant" && (probe.contentLen ?? 0) > 0) {
28890
+ return null;
28891
+ }
28770
28892
  if (this.type === "antigravity-cli") {
28771
28893
  return null;
28772
28894
  }
@@ -28776,6 +28898,7 @@ var CliProviderInstance = class {
28776
28898
  return { reason: "missing_final_assistant", terminal: true, allowTimeout: allowMissingAssistantTimeout };
28777
28899
  }
28778
28900
  } else {
28901
+ LOG.debug("CLI", `[${this.type}] missing_final_assistant (not ownsExternal) requiresFinalAssistant=${!!this.provider.requiresFinalAssistantBeforeIdle}`);
28779
28902
  return {
28780
28903
  reason: "missing_final_assistant",
28781
28904
  terminal: this.provider.requiresFinalAssistantBeforeIdle === true,
@@ -28809,6 +28932,7 @@ var CliProviderInstance = class {
28809
28932
  const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
28810
28933
  const externalNativeFinal = this.getExternalNativeFinalReconciliation(void 0, latestStatus);
28811
28934
  const latestVisibleStatus = externalNativeFinal && isCliGeneratingLikeStatus(latestStatus.status) ? "idle" : latestAutoApproveActive ? "generating" : latestStatus.status;
28935
+ 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
28936
  if (latestVisibleStatus !== "idle") {
28813
28937
  LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
28814
28938
  this.completedDebouncePending = null;
@@ -28819,6 +28943,7 @@ var CliProviderInstance = class {
28819
28943
  if (block2) {
28820
28944
  const blockReason = block2.reason;
28821
28945
  const waitedMs = Date.now() - pending.firstObservedAt;
28946
+ LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
28822
28947
  if (block2.terminal && !block2.allowTimeout || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
28823
28948
  if (pending.loggedBlockReason !== blockReason) {
28824
28949
  LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
@@ -28933,9 +29058,13 @@ var CliProviderInstance = class {
28933
29058
  if (newStatus !== this.lastStatus) {
28934
29059
  LOG.info("CLI", `[${this.type}] status: ${this.lastStatus} \u2192 ${newStatus}`);
28935
29060
  if (this.lastStatus === "idle" && newStatus === "generating") {
29061
+ if (this.completedDebouncePending && this.generatingStartedAt === 0) {
29062
+ LOG.debug("CLI", `[${this.type}] ignoring post-completion PTY generating blip (generatingStartedAt=0)`);
29063
+ return;
29064
+ }
28936
29065
  this.suppressIdleHistoryReplay = false;
28937
29066
  if (this.completedDebouncePending) {
28938
- LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating)`);
29067
+ LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed generating) generatingStartedAt=${this.generatingStartedAt} isWaitingForResponse=${!!this.adapter?.isWaitingForResponse}`);
28939
29068
  if (this.completedDebounceTimer) {
28940
29069
  clearTimeout(this.completedDebounceTimer);
28941
29070
  this.completedDebounceTimer = null;
@@ -29033,7 +29162,10 @@ var CliProviderInstance = class {
29033
29162
  firstObservedAt: now,
29034
29163
  previousStatus: this.lastStatus
29035
29164
  };
29036
- this.scheduleCompletedDebounceFlush(3e3);
29165
+ const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
29166
+ const flushDelay = ownsExternalHistory ? 0 : 3e3;
29167
+ LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
29168
+ this.scheduleCompletedDebounceFlush(flushDelay);
29037
29169
  }
29038
29170
  } else if (newStatus === "idle" && this.lastStatus === "starting") {
29039
29171
  this.pushEvent({ event: "agent:ready", chatTitle, timestamp: now });