@cleocode/core 2026.3.58 → 2026.3.60

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 (153) hide show
  1. package/dist/agents/agent-registry.d.ts +206 -0
  2. package/dist/agents/agent-registry.d.ts.map +1 -0
  3. package/dist/agents/agent-registry.js +288 -0
  4. package/dist/agents/agent-registry.js.map +1 -0
  5. package/dist/agents/agent-schema.js +5 -0
  6. package/dist/agents/agent-schema.js.map +1 -1
  7. package/dist/agents/execution-learning.js +474 -0
  8. package/dist/agents/execution-learning.js.map +1 -0
  9. package/dist/agents/health-monitor.d.ts +161 -0
  10. package/dist/agents/health-monitor.d.ts.map +1 -0
  11. package/dist/agents/health-monitor.js +217 -0
  12. package/dist/agents/health-monitor.js.map +1 -0
  13. package/dist/agents/index.d.ts +3 -1
  14. package/dist/agents/index.d.ts.map +1 -1
  15. package/dist/agents/index.js +9 -1
  16. package/dist/agents/index.js.map +1 -1
  17. package/dist/agents/retry.d.ts +57 -4
  18. package/dist/agents/retry.d.ts.map +1 -1
  19. package/dist/agents/retry.js +57 -4
  20. package/dist/agents/retry.js.map +1 -1
  21. package/dist/backfill/index.d.ts +27 -0
  22. package/dist/backfill/index.d.ts.map +1 -1
  23. package/dist/backfill/index.js +229 -0
  24. package/dist/backfill/index.js.map +1 -0
  25. package/dist/bootstrap.d.ts +2 -1
  26. package/dist/bootstrap.d.ts.map +1 -1
  27. package/dist/bootstrap.js +135 -28
  28. package/dist/bootstrap.js.map +1 -1
  29. package/dist/cleo.d.ts +40 -0
  30. package/dist/cleo.d.ts.map +1 -1
  31. package/dist/config.js +83 -0
  32. package/dist/config.js.map +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +1036 -536
  36. package/dist/index.js.map +4 -4
  37. package/dist/intelligence/adaptive-validation.js +497 -0
  38. package/dist/intelligence/adaptive-validation.js.map +1 -0
  39. package/dist/intelligence/impact.d.ts +34 -1
  40. package/dist/intelligence/impact.d.ts.map +1 -1
  41. package/dist/intelligence/impact.js +176 -0
  42. package/dist/intelligence/impact.js.map +1 -1
  43. package/dist/intelligence/index.d.ts +2 -2
  44. package/dist/intelligence/index.d.ts.map +1 -1
  45. package/dist/intelligence/index.js +6 -1
  46. package/dist/intelligence/index.js.map +1 -1
  47. package/dist/intelligence/types.d.ts +60 -0
  48. package/dist/intelligence/types.d.ts.map +1 -1
  49. package/dist/internal.d.ts +5 -4
  50. package/dist/internal.d.ts.map +1 -1
  51. package/dist/internal.js +11 -2
  52. package/dist/internal.js.map +1 -1
  53. package/dist/lib/index.d.ts +10 -0
  54. package/dist/lib/index.d.ts.map +1 -0
  55. package/dist/lib/index.js +10 -0
  56. package/dist/lib/index.js.map +1 -0
  57. package/dist/lib/retry.d.ts +128 -0
  58. package/dist/lib/retry.d.ts.map +1 -0
  59. package/dist/lib/retry.js +152 -0
  60. package/dist/lib/retry.js.map +1 -0
  61. package/dist/nexus/sharing/index.d.ts +48 -2
  62. package/dist/nexus/sharing/index.d.ts.map +1 -1
  63. package/dist/nexus/sharing/index.js +110 -1
  64. package/dist/nexus/sharing/index.js.map +1 -1
  65. package/dist/scaffold.d.ts.map +1 -1
  66. package/dist/scaffold.js +22 -2
  67. package/dist/scaffold.js.map +1 -1
  68. package/dist/sessions/session-enforcement.js +4 -0
  69. package/dist/sessions/session-enforcement.js.map +1 -1
  70. package/dist/stats/index.js +2 -0
  71. package/dist/stats/index.js.map +1 -1
  72. package/dist/stats/workflow-telemetry.d.ts +15 -0
  73. package/dist/stats/workflow-telemetry.d.ts.map +1 -1
  74. package/dist/stats/workflow-telemetry.js +400 -0
  75. package/dist/stats/workflow-telemetry.js.map +1 -0
  76. package/dist/store/brain-schema.js +4 -1
  77. package/dist/store/brain-schema.js.map +1 -1
  78. package/dist/store/converters.js +2 -0
  79. package/dist/store/converters.js.map +1 -1
  80. package/dist/store/cross-db-cleanup.d.ts +35 -0
  81. package/dist/store/cross-db-cleanup.d.ts.map +1 -1
  82. package/dist/store/cross-db-cleanup.js +169 -0
  83. package/dist/store/cross-db-cleanup.js.map +1 -0
  84. package/dist/store/db-helpers.js +2 -0
  85. package/dist/store/db-helpers.js.map +1 -1
  86. package/dist/store/migration-sqlite.js +5 -0
  87. package/dist/store/migration-sqlite.js.map +1 -1
  88. package/dist/store/sqlite-data-accessor.js +20 -28
  89. package/dist/store/sqlite-data-accessor.js.map +1 -1
  90. package/dist/store/sqlite.js +13 -2
  91. package/dist/store/sqlite.js.map +1 -1
  92. package/dist/store/task-store.js +4 -0
  93. package/dist/store/task-store.js.map +1 -1
  94. package/dist/store/tasks-schema.js +50 -20
  95. package/dist/store/tasks-schema.js.map +1 -1
  96. package/dist/tasks/add.js +87 -3
  97. package/dist/tasks/add.js.map +1 -1
  98. package/dist/tasks/complete.d.ts.map +1 -1
  99. package/dist/tasks/complete.js +15 -4
  100. package/dist/tasks/complete.js.map +1 -1
  101. package/dist/tasks/enforcement.d.ts.map +1 -1
  102. package/dist/tasks/enforcement.js +8 -1
  103. package/dist/tasks/enforcement.js.map +1 -1
  104. package/dist/tasks/epic-enforcement.d.ts +61 -0
  105. package/dist/tasks/epic-enforcement.d.ts.map +1 -1
  106. package/dist/tasks/epic-enforcement.js +294 -0
  107. package/dist/tasks/epic-enforcement.js.map +1 -0
  108. package/dist/tasks/index.js +1 -1
  109. package/dist/tasks/index.js.map +1 -1
  110. package/dist/tasks/pipeline-stage.d.ts +70 -1
  111. package/dist/tasks/pipeline-stage.d.ts.map +1 -1
  112. package/dist/tasks/pipeline-stage.js +248 -0
  113. package/dist/tasks/pipeline-stage.js.map +1 -0
  114. package/dist/tasks/update.js +28 -0
  115. package/dist/tasks/update.js.map +1 -1
  116. package/package.json +5 -5
  117. package/schemas/config.schema.json +37 -1547
  118. package/src/__tests__/sharing.test.ts +24 -0
  119. package/src/agents/__tests__/agent-registry.test.ts +351 -0
  120. package/src/agents/__tests__/health-monitor.test.ts +332 -0
  121. package/src/agents/agent-registry.ts +394 -0
  122. package/src/agents/health-monitor.ts +279 -0
  123. package/src/agents/index.ts +24 -1
  124. package/src/agents/retry.ts +57 -4
  125. package/src/backfill/index.ts +27 -0
  126. package/src/bootstrap.ts +171 -30
  127. package/src/cleo.ts +103 -2
  128. package/src/config.ts +3 -3
  129. package/src/index.ts +1 -0
  130. package/src/intelligence/__tests__/impact.test.ts +165 -1
  131. package/src/intelligence/impact.ts +203 -0
  132. package/src/intelligence/index.ts +3 -0
  133. package/src/intelligence/types.ts +76 -0
  134. package/src/internal.ts +20 -0
  135. package/src/lib/__tests__/retry.test.ts +321 -0
  136. package/src/lib/index.ts +16 -0
  137. package/src/lib/retry.ts +224 -0
  138. package/src/nexus/sharing/index.ts +142 -2
  139. package/src/scaffold.ts +24 -2
  140. package/src/stats/workflow-telemetry.ts +15 -0
  141. package/src/store/__tests__/session-store.test.ts +43 -7
  142. package/src/store/__tests__/task-store.test.ts +1 -1
  143. package/src/store/__tests__/test-db-helper.ts +7 -3
  144. package/src/store/cross-db-cleanup.ts +35 -0
  145. package/src/tasks/__tests__/epic-enforcement.test.ts +9 -4
  146. package/src/tasks/__tests__/minimal-test.test.ts +2 -2
  147. package/src/tasks/__tests__/update.test.ts +25 -25
  148. package/src/tasks/complete.ts +11 -6
  149. package/src/tasks/enforcement.ts +6 -3
  150. package/src/tasks/epic-enforcement.ts +61 -0
  151. package/src/tasks/pipeline-stage.ts +70 -1
  152. package/templates/config.template.json +5 -116
  153. package/templates/global-config.template.json +2 -44
package/dist/index.js CHANGED
@@ -13159,9 +13159,9 @@ async function readSequenceFromDb(cwd, accessor) {
13159
13159
  return isValidSequenceState(value) ? value : null;
13160
13160
  }
13161
13161
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
13162
- const { eq: eq11 } = await import("drizzle-orm");
13162
+ const { eq: eq12 } = await import("drizzle-orm");
13163
13163
  const db = await getDb3(cwd);
13164
- const rows = await db.select().from(schemaMeta).where(eq11(schemaMeta.key, SEQUENCE_META_KEY)).all();
13164
+ const rows = await db.select().from(schemaMeta).where(eq12(schemaMeta.key, SEQUENCE_META_KEY)).all();
13165
13165
  const raw = rows[0]?.value;
13166
13166
  if (!raw) return null;
13167
13167
  try {
@@ -14207,7 +14207,7 @@ async function linkPipelineAdr(projectRoot, taskId) {
14207
14207
  return result;
14208
14208
  }
14209
14209
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
14210
- const { and: and8, eq: eq11 } = await import("drizzle-orm");
14210
+ const { and: and9, eq: eq12 } = await import("drizzle-orm");
14211
14211
  const db = await getDb3(projectRoot);
14212
14212
  const now = (/* @__PURE__ */ new Date()).toISOString();
14213
14213
  for (const filePath of matchingFiles) {
@@ -14217,7 +14217,7 @@ async function linkPipelineAdr(projectRoot, taskId) {
14217
14217
  const fm = record2.frontmatter;
14218
14218
  const content = readFileSync5(filePath, "utf-8");
14219
14219
  const relativePath = `.cleo/adrs/${filename}`;
14220
- const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq11(architectureDecisions.id, record2.id)).all();
14220
+ const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq12(architectureDecisions.id, record2.id)).all();
14221
14221
  const rowBase = {
14222
14222
  id: record2.id,
14223
14223
  title: record2.title,
@@ -14237,19 +14237,19 @@ async function linkPipelineAdr(projectRoot, taskId) {
14237
14237
  updatedAt: now
14238
14238
  };
14239
14239
  if (existing.length > 0) {
14240
- await db.update(architectureDecisions).set(rowBase).where(eq11(architectureDecisions.id, record2.id));
14240
+ await db.update(architectureDecisions).set(rowBase).where(eq12(architectureDecisions.id, record2.id));
14241
14241
  } else {
14242
14242
  await db.insert(architectureDecisions).values({ ...rowBase, createdAt: now });
14243
14243
  }
14244
14244
  result.synced++;
14245
- await db.delete(adrTaskLinks).where(and8(eq11(adrTaskLinks.adrId, record2.id), eq11(adrTaskLinks.taskId, taskId)));
14245
+ await db.delete(adrTaskLinks).where(and9(eq12(adrTaskLinks.adrId, record2.id), eq12(adrTaskLinks.taskId, taskId)));
14246
14246
  await db.insert(adrTaskLinks).values({ adrId: record2.id, taskId, linkType: "implements" });
14247
14247
  result.linked.push({ adrId: record2.id, taskId });
14248
14248
  if (fm["Related ADRs"]) {
14249
14249
  const relatedIds = fm["Related ADRs"].split(",").map((r) => r.trim()).filter((r) => /^ADR-\d+$/.test(r));
14250
14250
  for (const toId of relatedIds) {
14251
14251
  try {
14252
- const targetExists = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq11(architectureDecisions.id, toId)).all();
14252
+ const targetExists = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq12(architectureDecisions.id, toId)).all();
14253
14253
  if (targetExists.length > 0) {
14254
14254
  await db.insert(adrRelations).values({ fromAdrId: record2.id, toAdrId: toId, relationType: "related" }).onConflictDoNothing();
14255
14255
  }
@@ -14272,248 +14272,8 @@ var init_link_pipeline = __esm({
14272
14272
  }
14273
14273
  });
14274
14274
 
14275
- // packages/core/src/agents/registry.ts
14276
- var registry_exports2 = {};
14277
- __export(registry_exports2, {
14278
- checkAgentHealth: () => checkAgentHealth,
14279
- classifyError: () => classifyError,
14280
- deregisterAgent: () => deregisterAgent,
14281
- generateAgentId: () => generateAgentId,
14282
- getAgentErrorHistory: () => getAgentErrorHistory,
14283
- getAgentInstance: () => getAgentInstance,
14284
- getHealthReport: () => getHealthReport,
14285
- heartbeat: () => heartbeat,
14286
- incrementTasksCompleted: () => incrementTasksCompleted,
14287
- listAgentInstances: () => listAgentInstances,
14288
- markCrashed: () => markCrashed,
14289
- registerAgent: () => registerAgent,
14290
- updateAgentStatus: () => updateAgentStatus
14291
- });
14292
- import { randomBytes } from "node:crypto";
14293
- import { and as and3, eq as eq5, inArray as inArray4, lt as lt2, sql as sql8 } from "drizzle-orm";
14294
- function generateAgentId() {
14295
- const now = /* @__PURE__ */ new Date();
14296
- const ts = now.toISOString().replace(/[-:T]/g, "").substring(0, 14);
14297
- const hex = randomBytes(3).toString("hex");
14298
- return `agt_${ts}_${hex}`;
14299
- }
14300
- async function registerAgent(opts, cwd) {
14301
- const db = await getDb(cwd);
14302
- const id = generateAgentId();
14303
- const now = (/* @__PURE__ */ new Date()).toISOString();
14304
- const row = {
14305
- id,
14306
- agentType: opts.agentType,
14307
- status: "starting",
14308
- sessionId: opts.sessionId ?? null,
14309
- taskId: opts.taskId ?? null,
14310
- startedAt: now,
14311
- lastHeartbeat: now,
14312
- stoppedAt: null,
14313
- errorCount: 0,
14314
- totalTasksCompleted: 0,
14315
- capacity: "1.0",
14316
- metadataJson: opts.metadata ? JSON.stringify(opts.metadata) : "{}",
14317
- parentAgentId: opts.parentAgentId ?? null
14318
- };
14319
- await db.insert(agentInstances).values(row);
14320
- return row;
14321
- }
14322
- async function deregisterAgent(id, cwd) {
14323
- const db = await getDb(cwd);
14324
- const now = (/* @__PURE__ */ new Date()).toISOString();
14325
- const existing = await db.select().from(agentInstances).where(eq5(agentInstances.id, id)).get();
14326
- if (!existing) return null;
14327
- if (existing.status === "stopped") return existing;
14328
- await db.update(agentInstances).set({ status: "stopped", stoppedAt: now }).where(eq5(agentInstances.id, id));
14329
- return { ...existing, status: "stopped", stoppedAt: now };
14330
- }
14331
- async function heartbeat(id, cwd) {
14332
- const db = await getDb(cwd);
14333
- const now = (/* @__PURE__ */ new Date()).toISOString();
14334
- const existing = await db.select().from(agentInstances).where(eq5(agentInstances.id, id)).get();
14335
- if (!existing) return null;
14336
- if (existing.status === "stopped" || existing.status === "crashed") {
14337
- return existing.status;
14338
- }
14339
- await db.update(agentInstances).set({ lastHeartbeat: now }).where(eq5(agentInstances.id, id));
14340
- return existing.status;
14341
- }
14342
- async function updateAgentStatus(id, opts, cwd) {
14343
- const db = await getDb(cwd);
14344
- const existing = await db.select().from(agentInstances).where(eq5(agentInstances.id, id)).get();
14345
- if (!existing) return null;
14346
- const updates = {
14347
- status: opts.status
14348
- };
14349
- if (opts.taskId !== void 0) {
14350
- updates.taskId = opts.taskId;
14351
- }
14352
- if (opts.status === "active") {
14353
- updates.lastHeartbeat = (/* @__PURE__ */ new Date()).toISOString();
14354
- }
14355
- if (opts.status === "error" || opts.status === "crashed") {
14356
- updates.errorCount = existing.errorCount + 1;
14357
- if (opts.error) {
14358
- const errorType = classifyError(new Error(opts.error));
14359
- await db.insert(agentErrorLog).values({
14360
- agentId: id,
14361
- errorType,
14362
- message: opts.error,
14363
- occurredAt: (/* @__PURE__ */ new Date()).toISOString()
14364
- });
14365
- }
14366
- }
14367
- if (opts.status === "stopped") {
14368
- updates.stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
14369
- }
14370
- await db.update(agentInstances).set(updates).where(eq5(agentInstances.id, id));
14371
- return { ...existing, ...updates };
14372
- }
14373
- async function incrementTasksCompleted(id, cwd) {
14374
- const db = await getDb(cwd);
14375
- await db.update(agentInstances).set({ totalTasksCompleted: sql8`${agentInstances.totalTasksCompleted} + 1` }).where(eq5(agentInstances.id, id));
14376
- }
14377
- async function listAgentInstances(filters, cwd) {
14378
- const db = await getDb(cwd);
14379
- const conditions = [];
14380
- if (filters?.status) {
14381
- const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
14382
- conditions.push(inArray4(agentInstances.status, statuses));
14383
- }
14384
- if (filters?.agentType) {
14385
- const types = Array.isArray(filters.agentType) ? filters.agentType : [filters.agentType];
14386
- conditions.push(inArray4(agentInstances.agentType, types));
14387
- }
14388
- if (filters?.sessionId) {
14389
- conditions.push(eq5(agentInstances.sessionId, filters.sessionId));
14390
- }
14391
- if (filters?.parentAgentId) {
14392
- conditions.push(eq5(agentInstances.parentAgentId, filters.parentAgentId));
14393
- }
14394
- if (conditions.length === 0) {
14395
- return db.select().from(agentInstances).all();
14396
- }
14397
- return db.select().from(agentInstances).where(and3(...conditions)).all();
14398
- }
14399
- async function getAgentInstance(id, cwd) {
14400
- const db = await getDb(cwd);
14401
- const row = await db.select().from(agentInstances).where(eq5(agentInstances.id, id)).get();
14402
- return row ?? null;
14403
- }
14404
- function classifyError(error40) {
14405
- const message = error40 instanceof Error ? error40.message : String(error40);
14406
- for (const pattern of RETRIABLE_PATTERNS) {
14407
- if (pattern.test(message)) return "retriable";
14408
- }
14409
- for (const pattern of PERMANENT_PATTERNS) {
14410
- if (pattern.test(message)) return "permanent";
14411
- }
14412
- return "unknown";
14413
- }
14414
- async function getAgentErrorHistory(agentId, cwd) {
14415
- const db = await getDb(cwd);
14416
- return db.select().from(agentErrorLog).where(eq5(agentErrorLog.agentId, agentId)).all();
14417
- }
14418
- async function checkAgentHealth(thresholdMs = 3e4, cwd) {
14419
- const db = await getDb(cwd);
14420
- const cutoff = new Date(Date.now() - thresholdMs).toISOString();
14421
- return db.select().from(agentInstances).where(
14422
- and3(
14423
- inArray4(agentInstances.status, ["active", "idle", "starting"]),
14424
- lt2(agentInstances.lastHeartbeat, cutoff)
14425
- )
14426
- ).all();
14427
- }
14428
- async function markCrashed(id, reason, cwd) {
14429
- return updateAgentStatus(
14430
- id,
14431
- { status: "crashed", error: reason ?? "Heartbeat timeout \u2014 agent presumed crashed" },
14432
- cwd
14433
- );
14434
- }
14435
- async function getHealthReport(thresholdMs = 3e4, cwd) {
14436
- const allAgents = await listAgentInstances(void 0, cwd);
14437
- const staleAgents = await checkAgentHealth(thresholdMs, cwd);
14438
- const report = {
14439
- total: allAgents.length,
14440
- active: 0,
14441
- idle: 0,
14442
- starting: 0,
14443
- error: 0,
14444
- crashed: 0,
14445
- stopped: 0,
14446
- totalErrors: 0,
14447
- staleAgents
14448
- };
14449
- for (const agent of allAgents) {
14450
- switch (agent.status) {
14451
- case "active":
14452
- report.active++;
14453
- break;
14454
- case "idle":
14455
- report.idle++;
14456
- break;
14457
- case "starting":
14458
- report.starting++;
14459
- break;
14460
- case "error":
14461
- report.error++;
14462
- break;
14463
- case "crashed":
14464
- report.crashed++;
14465
- break;
14466
- case "stopped":
14467
- report.stopped++;
14468
- break;
14469
- }
14470
- report.totalErrors += agent.errorCount;
14471
- }
14472
- return report;
14473
- }
14474
- var RETRIABLE_PATTERNS, PERMANENT_PATTERNS;
14475
- var init_registry2 = __esm({
14476
- "packages/core/src/agents/registry.ts"() {
14477
- "use strict";
14478
- init_sqlite2();
14479
- init_agent_schema();
14480
- RETRIABLE_PATTERNS = [
14481
- /timeout/i,
14482
- /ECONNREFUSED/,
14483
- /ECONNRESET/,
14484
- /EPIPE/,
14485
- /ETIMEDOUT/,
14486
- /rate.?limit/i,
14487
- /429/,
14488
- /503/,
14489
- /502/,
14490
- /SQLITE_BUSY/i,
14491
- /database is locked/i,
14492
- /temporarily unavailable/i,
14493
- /too many requests/i,
14494
- /network/i,
14495
- /socket hang up/i
14496
- ];
14497
- PERMANENT_PATTERNS = [
14498
- /permission denied/i,
14499
- /EACCES/,
14500
- /authentication/i,
14501
- /unauthorized/i,
14502
- /401/,
14503
- /403/,
14504
- /404/,
14505
- /not found/i,
14506
- /invalid.*token/i,
14507
- /SQLITE_CONSTRAINT/i,
14508
- /syntax error/i,
14509
- /type error/i,
14510
- /reference error/i
14511
- ];
14512
- }
14513
- });
14514
-
14515
14275
  // packages/core/src/store/brain-accessor.ts
14516
- import { and as and4, asc as asc2, desc as desc2, eq as eq7, gte as gte2, or as or3 } from "drizzle-orm";
14276
+ import { and as and3, asc as asc2, desc as desc2, eq as eq5, gte as gte2, or as or3 } from "drizzle-orm";
14517
14277
  async function getBrainAccessor(cwd) {
14518
14278
  const db = await getBrainDb(cwd);
14519
14279
  return new BrainDataAccessor(db);
@@ -14533,30 +14293,30 @@ var init_brain_accessor = __esm({
14533
14293
  // =========================================================================
14534
14294
  async addDecision(row) {
14535
14295
  await this.db.insert(brainDecisions).values(row);
14536
- const result = await this.db.select().from(brainDecisions).where(eq7(brainDecisions.id, row.id));
14296
+ const result = await this.db.select().from(brainDecisions).where(eq5(brainDecisions.id, row.id));
14537
14297
  return result[0];
14538
14298
  }
14539
14299
  async getDecision(id) {
14540
- const result = await this.db.select().from(brainDecisions).where(eq7(brainDecisions.id, id));
14300
+ const result = await this.db.select().from(brainDecisions).where(eq5(brainDecisions.id, id));
14541
14301
  return result[0] ?? null;
14542
14302
  }
14543
14303
  async findDecisions(params = {}) {
14544
14304
  const conditions = [];
14545
14305
  if (params.type) {
14546
- conditions.push(eq7(brainDecisions.type, params.type));
14306
+ conditions.push(eq5(brainDecisions.type, params.type));
14547
14307
  }
14548
14308
  if (params.confidence) {
14549
- conditions.push(eq7(brainDecisions.confidence, params.confidence));
14309
+ conditions.push(eq5(brainDecisions.confidence, params.confidence));
14550
14310
  }
14551
14311
  if (params.outcome) {
14552
- conditions.push(eq7(brainDecisions.outcome, params.outcome));
14312
+ conditions.push(eq5(brainDecisions.outcome, params.outcome));
14553
14313
  }
14554
14314
  if (params.contextTaskId) {
14555
- conditions.push(eq7(brainDecisions.contextTaskId, params.contextTaskId));
14315
+ conditions.push(eq5(brainDecisions.contextTaskId, params.contextTaskId));
14556
14316
  }
14557
14317
  let query = this.db.select().from(brainDecisions).orderBy(desc2(brainDecisions.createdAt));
14558
14318
  if (conditions.length > 0) {
14559
- query = query.where(and4(...conditions));
14319
+ query = query.where(and3(...conditions));
14560
14320
  }
14561
14321
  if (params.limit) {
14562
14322
  query = query.limit(params.limit);
@@ -14564,34 +14324,34 @@ var init_brain_accessor = __esm({
14564
14324
  return query;
14565
14325
  }
14566
14326
  async updateDecision(id, updates) {
14567
- await this.db.update(brainDecisions).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainDecisions.id, id));
14327
+ await this.db.update(brainDecisions).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq5(brainDecisions.id, id));
14568
14328
  }
14569
14329
  // =========================================================================
14570
14330
  // Patterns CRUD
14571
14331
  // =========================================================================
14572
14332
  async addPattern(row) {
14573
14333
  await this.db.insert(brainPatterns).values(row);
14574
- const result = await this.db.select().from(brainPatterns).where(eq7(brainPatterns.id, row.id));
14334
+ const result = await this.db.select().from(brainPatterns).where(eq5(brainPatterns.id, row.id));
14575
14335
  return result[0];
14576
14336
  }
14577
14337
  async getPattern(id) {
14578
- const result = await this.db.select().from(brainPatterns).where(eq7(brainPatterns.id, id));
14338
+ const result = await this.db.select().from(brainPatterns).where(eq5(brainPatterns.id, id));
14579
14339
  return result[0] ?? null;
14580
14340
  }
14581
14341
  async findPatterns(params = {}) {
14582
14342
  const conditions = [];
14583
14343
  if (params.type) {
14584
- conditions.push(eq7(brainPatterns.type, params.type));
14344
+ conditions.push(eq5(brainPatterns.type, params.type));
14585
14345
  }
14586
14346
  if (params.impact) {
14587
- conditions.push(eq7(brainPatterns.impact, params.impact));
14347
+ conditions.push(eq5(brainPatterns.impact, params.impact));
14588
14348
  }
14589
14349
  if (params.minFrequency !== void 0) {
14590
14350
  conditions.push(gte2(brainPatterns.frequency, params.minFrequency));
14591
14351
  }
14592
14352
  let query = this.db.select().from(brainPatterns).orderBy(desc2(brainPatterns.frequency));
14593
14353
  if (conditions.length > 0) {
14594
- query = query.where(and4(...conditions));
14354
+ query = query.where(and3(...conditions));
14595
14355
  }
14596
14356
  if (params.limit) {
14597
14357
  query = query.limit(params.limit);
@@ -14599,18 +14359,18 @@ var init_brain_accessor = __esm({
14599
14359
  return query;
14600
14360
  }
14601
14361
  async updatePattern(id, updates) {
14602
- await this.db.update(brainPatterns).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainPatterns.id, id));
14362
+ await this.db.update(brainPatterns).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq5(brainPatterns.id, id));
14603
14363
  }
14604
14364
  // =========================================================================
14605
14365
  // Learnings CRUD
14606
14366
  // =========================================================================
14607
14367
  async addLearning(row) {
14608
14368
  await this.db.insert(brainLearnings).values(row);
14609
- const result = await this.db.select().from(brainLearnings).where(eq7(brainLearnings.id, row.id));
14369
+ const result = await this.db.select().from(brainLearnings).where(eq5(brainLearnings.id, row.id));
14610
14370
  return result[0];
14611
14371
  }
14612
14372
  async getLearning(id) {
14613
- const result = await this.db.select().from(brainLearnings).where(eq7(brainLearnings.id, id));
14373
+ const result = await this.db.select().from(brainLearnings).where(eq5(brainLearnings.id, id));
14614
14374
  return result[0] ?? null;
14615
14375
  }
14616
14376
  async findLearnings(params = {}) {
@@ -14619,11 +14379,11 @@ var init_brain_accessor = __esm({
14619
14379
  conditions.push(gte2(brainLearnings.confidence, params.minConfidence));
14620
14380
  }
14621
14381
  if (params.actionable !== void 0) {
14622
- conditions.push(eq7(brainLearnings.actionable, params.actionable));
14382
+ conditions.push(eq5(brainLearnings.actionable, params.actionable));
14623
14383
  }
14624
14384
  let query = this.db.select().from(brainLearnings).orderBy(desc2(brainLearnings.confidence));
14625
14385
  if (conditions.length > 0) {
14626
- query = query.where(and4(...conditions));
14386
+ query = query.where(and3(...conditions));
14627
14387
  }
14628
14388
  if (params.limit) {
14629
14389
  query = query.limit(params.limit);
@@ -14631,37 +14391,37 @@ var init_brain_accessor = __esm({
14631
14391
  return query;
14632
14392
  }
14633
14393
  async updateLearning(id, updates) {
14634
- await this.db.update(brainLearnings).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainLearnings.id, id));
14394
+ await this.db.update(brainLearnings).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq5(brainLearnings.id, id));
14635
14395
  }
14636
14396
  // =========================================================================
14637
14397
  // Observations CRUD
14638
14398
  // =========================================================================
14639
14399
  async addObservation(row) {
14640
14400
  await this.db.insert(brainObservations).values(row);
14641
- const result = await this.db.select().from(brainObservations).where(eq7(brainObservations.id, row.id));
14401
+ const result = await this.db.select().from(brainObservations).where(eq5(brainObservations.id, row.id));
14642
14402
  return result[0];
14643
14403
  }
14644
14404
  async getObservation(id) {
14645
- const result = await this.db.select().from(brainObservations).where(eq7(brainObservations.id, id));
14405
+ const result = await this.db.select().from(brainObservations).where(eq5(brainObservations.id, id));
14646
14406
  return result[0] ?? null;
14647
14407
  }
14648
14408
  async findObservations(params = {}) {
14649
14409
  const conditions = [];
14650
14410
  if (params.type) {
14651
- conditions.push(eq7(brainObservations.type, params.type));
14411
+ conditions.push(eq5(brainObservations.type, params.type));
14652
14412
  }
14653
14413
  if (params.project) {
14654
- conditions.push(eq7(brainObservations.project, params.project));
14414
+ conditions.push(eq5(brainObservations.project, params.project));
14655
14415
  }
14656
14416
  if (params.sourceType) {
14657
- conditions.push(eq7(brainObservations.sourceType, params.sourceType));
14417
+ conditions.push(eq5(brainObservations.sourceType, params.sourceType));
14658
14418
  }
14659
14419
  if (params.sourceSessionId) {
14660
- conditions.push(eq7(brainObservations.sourceSessionId, params.sourceSessionId));
14420
+ conditions.push(eq5(brainObservations.sourceSessionId, params.sourceSessionId));
14661
14421
  }
14662
14422
  let query = this.db.select().from(brainObservations).orderBy(desc2(brainObservations.createdAt));
14663
14423
  if (conditions.length > 0) {
14664
- query = query.where(and4(...conditions));
14424
+ query = query.where(and3(...conditions));
14665
14425
  }
14666
14426
  if (params.limit) {
14667
14427
  query = query.limit(params.limit);
@@ -14669,7 +14429,7 @@ var init_brain_accessor = __esm({
14669
14429
  return query;
14670
14430
  }
14671
14431
  async updateObservation(id, updates) {
14672
- await this.db.update(brainObservations).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainObservations.id, id));
14432
+ await this.db.update(brainObservations).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq5(brainObservations.id, id));
14673
14433
  }
14674
14434
  // =========================================================================
14675
14435
  // Memory Links CRUD
@@ -14679,22 +14439,22 @@ var init_brain_accessor = __esm({
14679
14439
  }
14680
14440
  async getLinksForMemory(memoryType, memoryId) {
14681
14441
  return this.db.select().from(brainMemoryLinks).where(
14682
- and4(
14683
- eq7(brainMemoryLinks.memoryType, memoryType),
14684
- eq7(brainMemoryLinks.memoryId, memoryId)
14442
+ and3(
14443
+ eq5(brainMemoryLinks.memoryType, memoryType),
14444
+ eq5(brainMemoryLinks.memoryId, memoryId)
14685
14445
  )
14686
14446
  ).orderBy(asc2(brainMemoryLinks.createdAt));
14687
14447
  }
14688
14448
  async getLinksForTask(taskId) {
14689
- return this.db.select().from(brainMemoryLinks).where(eq7(brainMemoryLinks.taskId, taskId)).orderBy(asc2(brainMemoryLinks.createdAt));
14449
+ return this.db.select().from(brainMemoryLinks).where(eq5(brainMemoryLinks.taskId, taskId)).orderBy(asc2(brainMemoryLinks.createdAt));
14690
14450
  }
14691
14451
  async removeLink(memoryType, memoryId, taskId, linkType) {
14692
14452
  await this.db.delete(brainMemoryLinks).where(
14693
- and4(
14694
- eq7(brainMemoryLinks.memoryType, memoryType),
14695
- eq7(brainMemoryLinks.memoryId, memoryId),
14696
- eq7(brainMemoryLinks.taskId, taskId),
14697
- eq7(brainMemoryLinks.linkType, linkType)
14453
+ and3(
14454
+ eq5(brainMemoryLinks.memoryType, memoryType),
14455
+ eq5(brainMemoryLinks.memoryId, memoryId),
14456
+ eq5(brainMemoryLinks.taskId, taskId),
14457
+ eq5(brainMemoryLinks.linkType, linkType)
14698
14458
  )
14699
14459
  );
14700
14460
  }
@@ -14703,27 +14463,27 @@ var init_brain_accessor = __esm({
14703
14463
  // =========================================================================
14704
14464
  async addStickyNote(row) {
14705
14465
  await this.db.insert(brainStickyNotes).values(row);
14706
- const result = await this.db.select().from(brainStickyNotes).where(eq7(brainStickyNotes.id, row.id));
14466
+ const result = await this.db.select().from(brainStickyNotes).where(eq5(brainStickyNotes.id, row.id));
14707
14467
  return result[0];
14708
14468
  }
14709
14469
  async getStickyNote(id) {
14710
- const result = await this.db.select().from(brainStickyNotes).where(eq7(brainStickyNotes.id, id));
14470
+ const result = await this.db.select().from(brainStickyNotes).where(eq5(brainStickyNotes.id, id));
14711
14471
  return result[0] ?? null;
14712
14472
  }
14713
14473
  async findStickyNotes(params = {}) {
14714
14474
  const conditions = [];
14715
14475
  if (params.status) {
14716
- conditions.push(eq7(brainStickyNotes.status, params.status));
14476
+ conditions.push(eq5(brainStickyNotes.status, params.status));
14717
14477
  }
14718
14478
  if (params.color) {
14719
- conditions.push(eq7(brainStickyNotes.color, params.color));
14479
+ conditions.push(eq5(brainStickyNotes.color, params.color));
14720
14480
  }
14721
14481
  if (params.priority) {
14722
- conditions.push(eq7(brainStickyNotes.priority, params.priority));
14482
+ conditions.push(eq5(brainStickyNotes.priority, params.priority));
14723
14483
  }
14724
14484
  let query = this.db.select().from(brainStickyNotes).orderBy(desc2(brainStickyNotes.createdAt));
14725
14485
  if (conditions.length > 0) {
14726
- query = query.where(and4(...conditions));
14486
+ query = query.where(and3(...conditions));
14727
14487
  }
14728
14488
  if (params.limit) {
14729
14489
  query = query.limit(params.limit);
@@ -14731,31 +14491,31 @@ var init_brain_accessor = __esm({
14731
14491
  return query;
14732
14492
  }
14733
14493
  async updateStickyNote(id, updates) {
14734
- await this.db.update(brainStickyNotes).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq7(brainStickyNotes.id, id));
14494
+ await this.db.update(brainStickyNotes).set({ ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19) }).where(eq5(brainStickyNotes.id, id));
14735
14495
  }
14736
14496
  async deleteStickyNote(id) {
14737
- await this.db.delete(brainStickyNotes).where(eq7(brainStickyNotes.id, id));
14497
+ await this.db.delete(brainStickyNotes).where(eq5(brainStickyNotes.id, id));
14738
14498
  }
14739
14499
  // =========================================================================
14740
14500
  // PageIndex Node CRUD (T5383)
14741
14501
  // =========================================================================
14742
14502
  async addPageNode(node) {
14743
14503
  await this.db.insert(brainPageNodes).values(node);
14744
- const result = await this.db.select().from(brainPageNodes).where(eq7(brainPageNodes.id, node.id));
14504
+ const result = await this.db.select().from(brainPageNodes).where(eq5(brainPageNodes.id, node.id));
14745
14505
  return result[0];
14746
14506
  }
14747
14507
  async getPageNode(id) {
14748
- const result = await this.db.select().from(brainPageNodes).where(eq7(brainPageNodes.id, id));
14508
+ const result = await this.db.select().from(brainPageNodes).where(eq5(brainPageNodes.id, id));
14749
14509
  return result[0] ?? null;
14750
14510
  }
14751
14511
  async findPageNodes(params = {}) {
14752
14512
  const conditions = [];
14753
14513
  if (params.nodeType) {
14754
- conditions.push(eq7(brainPageNodes.nodeType, params.nodeType));
14514
+ conditions.push(eq5(brainPageNodes.nodeType, params.nodeType));
14755
14515
  }
14756
14516
  let query = this.db.select().from(brainPageNodes).orderBy(desc2(brainPageNodes.createdAt));
14757
14517
  if (conditions.length > 0) {
14758
- query = query.where(and4(...conditions));
14518
+ query = query.where(and3(...conditions));
14759
14519
  }
14760
14520
  if (params.limit) {
14761
14521
  query = query.limit(params.limit);
@@ -14764,9 +14524,9 @@ var init_brain_accessor = __esm({
14764
14524
  }
14765
14525
  async removePageNode(id) {
14766
14526
  await this.db.delete(brainPageEdges).where(
14767
- or3(eq7(brainPageEdges.fromId, id), eq7(brainPageEdges.toId, id))
14527
+ or3(eq5(brainPageEdges.fromId, id), eq5(brainPageEdges.toId, id))
14768
14528
  );
14769
- await this.db.delete(brainPageNodes).where(eq7(brainPageNodes.id, id));
14529
+ await this.db.delete(brainPageNodes).where(eq5(brainPageNodes.id, id));
14770
14530
  }
14771
14531
  // =========================================================================
14772
14532
  // PageIndex Edge CRUD (T5383)
@@ -14774,34 +14534,34 @@ var init_brain_accessor = __esm({
14774
14534
  async addPageEdge(edge) {
14775
14535
  await this.db.insert(brainPageEdges).values(edge);
14776
14536
  const result = await this.db.select().from(brainPageEdges).where(
14777
- and4(
14778
- eq7(brainPageEdges.fromId, edge.fromId),
14779
- eq7(brainPageEdges.toId, edge.toId),
14780
- eq7(brainPageEdges.edgeType, edge.edgeType)
14537
+ and3(
14538
+ eq5(brainPageEdges.fromId, edge.fromId),
14539
+ eq5(brainPageEdges.toId, edge.toId),
14540
+ eq5(brainPageEdges.edgeType, edge.edgeType)
14781
14541
  )
14782
14542
  );
14783
14543
  return result[0];
14784
14544
  }
14785
14545
  async getPageEdges(nodeId, direction = "both") {
14786
14546
  if (direction === "out") {
14787
- return this.db.select().from(brainPageEdges).where(eq7(brainPageEdges.fromId, nodeId)).orderBy(asc2(brainPageEdges.createdAt));
14547
+ return this.db.select().from(brainPageEdges).where(eq5(brainPageEdges.fromId, nodeId)).orderBy(asc2(brainPageEdges.createdAt));
14788
14548
  }
14789
14549
  if (direction === "in") {
14790
- return this.db.select().from(brainPageEdges).where(eq7(brainPageEdges.toId, nodeId)).orderBy(asc2(brainPageEdges.createdAt));
14550
+ return this.db.select().from(brainPageEdges).where(eq5(brainPageEdges.toId, nodeId)).orderBy(asc2(brainPageEdges.createdAt));
14791
14551
  }
14792
14552
  return this.db.select().from(brainPageEdges).where(
14793
14553
  or3(
14794
- eq7(brainPageEdges.fromId, nodeId),
14795
- eq7(brainPageEdges.toId, nodeId)
14554
+ eq5(brainPageEdges.fromId, nodeId),
14555
+ eq5(brainPageEdges.toId, nodeId)
14796
14556
  )
14797
14557
  ).orderBy(asc2(brainPageEdges.createdAt));
14798
14558
  }
14799
14559
  async getNeighbors(nodeId, edgeType) {
14800
- const conditions = [eq7(brainPageEdges.fromId, nodeId)];
14560
+ const conditions = [eq5(brainPageEdges.fromId, nodeId)];
14801
14561
  if (edgeType) {
14802
- conditions.push(eq7(brainPageEdges.edgeType, edgeType));
14562
+ conditions.push(eq5(brainPageEdges.edgeType, edgeType));
14803
14563
  }
14804
- const edges = await this.db.select().from(brainPageEdges).where(and4(...conditions));
14564
+ const edges = await this.db.select().from(brainPageEdges).where(and3(...conditions));
14805
14565
  if (edges.length === 0) return [];
14806
14566
  const neighborIds = edges.map((e) => e.toId);
14807
14567
  const nodes = [];
@@ -14813,10 +14573,10 @@ var init_brain_accessor = __esm({
14813
14573
  }
14814
14574
  async removePageEdge(fromId, toId, edgeType) {
14815
14575
  await this.db.delete(brainPageEdges).where(
14816
- and4(
14817
- eq7(brainPageEdges.fromId, fromId),
14818
- eq7(brainPageEdges.toId, toId),
14819
- eq7(brainPageEdges.edgeType, edgeType)
14576
+ and3(
14577
+ eq5(brainPageEdges.fromId, fromId),
14578
+ eq5(brainPageEdges.toId, toId),
14579
+ eq5(brainPageEdges.edgeType, edgeType)
14820
14580
  )
14821
14581
  );
14822
14582
  }
@@ -14824,6 +14584,246 @@ var init_brain_accessor = __esm({
14824
14584
  }
14825
14585
  });
14826
14586
 
14587
+ // packages/core/src/agents/registry.ts
14588
+ var registry_exports2 = {};
14589
+ __export(registry_exports2, {
14590
+ checkAgentHealth: () => checkAgentHealth,
14591
+ classifyError: () => classifyError,
14592
+ deregisterAgent: () => deregisterAgent,
14593
+ generateAgentId: () => generateAgentId,
14594
+ getAgentErrorHistory: () => getAgentErrorHistory,
14595
+ getAgentInstance: () => getAgentInstance,
14596
+ getHealthReport: () => getHealthReport,
14597
+ heartbeat: () => heartbeat,
14598
+ incrementTasksCompleted: () => incrementTasksCompleted,
14599
+ listAgentInstances: () => listAgentInstances,
14600
+ markCrashed: () => markCrashed,
14601
+ registerAgent: () => registerAgent,
14602
+ updateAgentStatus: () => updateAgentStatus
14603
+ });
14604
+ import { randomBytes as randomBytes2 } from "node:crypto";
14605
+ import { and as and4, eq as eq6, inArray as inArray4, lt as lt2, sql as sql8 } from "drizzle-orm";
14606
+ function generateAgentId() {
14607
+ const now = /* @__PURE__ */ new Date();
14608
+ const ts = now.toISOString().replace(/[-:T]/g, "").substring(0, 14);
14609
+ const hex = randomBytes2(3).toString("hex");
14610
+ return `agt_${ts}_${hex}`;
14611
+ }
14612
+ async function registerAgent(opts, cwd) {
14613
+ const db = await getDb(cwd);
14614
+ const id = generateAgentId();
14615
+ const now = (/* @__PURE__ */ new Date()).toISOString();
14616
+ const row = {
14617
+ id,
14618
+ agentType: opts.agentType,
14619
+ status: "starting",
14620
+ sessionId: opts.sessionId ?? null,
14621
+ taskId: opts.taskId ?? null,
14622
+ startedAt: now,
14623
+ lastHeartbeat: now,
14624
+ stoppedAt: null,
14625
+ errorCount: 0,
14626
+ totalTasksCompleted: 0,
14627
+ capacity: "1.0",
14628
+ metadataJson: opts.metadata ? JSON.stringify(opts.metadata) : "{}",
14629
+ parentAgentId: opts.parentAgentId ?? null
14630
+ };
14631
+ await db.insert(agentInstances).values(row);
14632
+ return row;
14633
+ }
14634
+ async function deregisterAgent(id, cwd) {
14635
+ const db = await getDb(cwd);
14636
+ const now = (/* @__PURE__ */ new Date()).toISOString();
14637
+ const existing = await db.select().from(agentInstances).where(eq6(agentInstances.id, id)).get();
14638
+ if (!existing) return null;
14639
+ if (existing.status === "stopped") return existing;
14640
+ await db.update(agentInstances).set({ status: "stopped", stoppedAt: now }).where(eq6(agentInstances.id, id));
14641
+ return { ...existing, status: "stopped", stoppedAt: now };
14642
+ }
14643
+ async function heartbeat(id, cwd) {
14644
+ const db = await getDb(cwd);
14645
+ const now = (/* @__PURE__ */ new Date()).toISOString();
14646
+ const existing = await db.select().from(agentInstances).where(eq6(agentInstances.id, id)).get();
14647
+ if (!existing) return null;
14648
+ if (existing.status === "stopped" || existing.status === "crashed") {
14649
+ return existing.status;
14650
+ }
14651
+ await db.update(agentInstances).set({ lastHeartbeat: now }).where(eq6(agentInstances.id, id));
14652
+ return existing.status;
14653
+ }
14654
+ async function updateAgentStatus(id, opts, cwd) {
14655
+ const db = await getDb(cwd);
14656
+ const existing = await db.select().from(agentInstances).where(eq6(agentInstances.id, id)).get();
14657
+ if (!existing) return null;
14658
+ const updates = {
14659
+ status: opts.status
14660
+ };
14661
+ if (opts.taskId !== void 0) {
14662
+ updates.taskId = opts.taskId;
14663
+ }
14664
+ if (opts.status === "active") {
14665
+ updates.lastHeartbeat = (/* @__PURE__ */ new Date()).toISOString();
14666
+ }
14667
+ if (opts.status === "error" || opts.status === "crashed") {
14668
+ updates.errorCount = existing.errorCount + 1;
14669
+ if (opts.error) {
14670
+ const errorType = classifyError(new Error(opts.error));
14671
+ await db.insert(agentErrorLog).values({
14672
+ agentId: id,
14673
+ errorType,
14674
+ message: opts.error,
14675
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString()
14676
+ });
14677
+ }
14678
+ }
14679
+ if (opts.status === "stopped") {
14680
+ updates.stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
14681
+ }
14682
+ await db.update(agentInstances).set(updates).where(eq6(agentInstances.id, id));
14683
+ return { ...existing, ...updates };
14684
+ }
14685
+ async function incrementTasksCompleted(id, cwd) {
14686
+ const db = await getDb(cwd);
14687
+ await db.update(agentInstances).set({ totalTasksCompleted: sql8`${agentInstances.totalTasksCompleted} + 1` }).where(eq6(agentInstances.id, id));
14688
+ }
14689
+ async function listAgentInstances(filters, cwd) {
14690
+ const db = await getDb(cwd);
14691
+ const conditions = [];
14692
+ if (filters?.status) {
14693
+ const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
14694
+ conditions.push(inArray4(agentInstances.status, statuses));
14695
+ }
14696
+ if (filters?.agentType) {
14697
+ const types = Array.isArray(filters.agentType) ? filters.agentType : [filters.agentType];
14698
+ conditions.push(inArray4(agentInstances.agentType, types));
14699
+ }
14700
+ if (filters?.sessionId) {
14701
+ conditions.push(eq6(agentInstances.sessionId, filters.sessionId));
14702
+ }
14703
+ if (filters?.parentAgentId) {
14704
+ conditions.push(eq6(agentInstances.parentAgentId, filters.parentAgentId));
14705
+ }
14706
+ if (conditions.length === 0) {
14707
+ return db.select().from(agentInstances).all();
14708
+ }
14709
+ return db.select().from(agentInstances).where(and4(...conditions)).all();
14710
+ }
14711
+ async function getAgentInstance(id, cwd) {
14712
+ const db = await getDb(cwd);
14713
+ const row = await db.select().from(agentInstances).where(eq6(agentInstances.id, id)).get();
14714
+ return row ?? null;
14715
+ }
14716
+ function classifyError(error40) {
14717
+ const message = error40 instanceof Error ? error40.message : String(error40);
14718
+ for (const pattern of RETRIABLE_PATTERNS) {
14719
+ if (pattern.test(message)) return "retriable";
14720
+ }
14721
+ for (const pattern of PERMANENT_PATTERNS) {
14722
+ if (pattern.test(message)) return "permanent";
14723
+ }
14724
+ return "unknown";
14725
+ }
14726
+ async function getAgentErrorHistory(agentId, cwd) {
14727
+ const db = await getDb(cwd);
14728
+ return db.select().from(agentErrorLog).where(eq6(agentErrorLog.agentId, agentId)).all();
14729
+ }
14730
+ async function checkAgentHealth(thresholdMs = 3e4, cwd) {
14731
+ const db = await getDb(cwd);
14732
+ const cutoff = new Date(Date.now() - thresholdMs).toISOString();
14733
+ return db.select().from(agentInstances).where(
14734
+ and4(
14735
+ inArray4(agentInstances.status, ["active", "idle", "starting"]),
14736
+ lt2(agentInstances.lastHeartbeat, cutoff)
14737
+ )
14738
+ ).all();
14739
+ }
14740
+ async function markCrashed(id, reason, cwd) {
14741
+ return updateAgentStatus(
14742
+ id,
14743
+ { status: "crashed", error: reason ?? "Heartbeat timeout \u2014 agent presumed crashed" },
14744
+ cwd
14745
+ );
14746
+ }
14747
+ async function getHealthReport(thresholdMs = 3e4, cwd) {
14748
+ const allAgents = await listAgentInstances(void 0, cwd);
14749
+ const staleAgents = await checkAgentHealth(thresholdMs, cwd);
14750
+ const report = {
14751
+ total: allAgents.length,
14752
+ active: 0,
14753
+ idle: 0,
14754
+ starting: 0,
14755
+ error: 0,
14756
+ crashed: 0,
14757
+ stopped: 0,
14758
+ totalErrors: 0,
14759
+ staleAgents
14760
+ };
14761
+ for (const agent of allAgents) {
14762
+ switch (agent.status) {
14763
+ case "active":
14764
+ report.active++;
14765
+ break;
14766
+ case "idle":
14767
+ report.idle++;
14768
+ break;
14769
+ case "starting":
14770
+ report.starting++;
14771
+ break;
14772
+ case "error":
14773
+ report.error++;
14774
+ break;
14775
+ case "crashed":
14776
+ report.crashed++;
14777
+ break;
14778
+ case "stopped":
14779
+ report.stopped++;
14780
+ break;
14781
+ }
14782
+ report.totalErrors += agent.errorCount;
14783
+ }
14784
+ return report;
14785
+ }
14786
+ var RETRIABLE_PATTERNS, PERMANENT_PATTERNS;
14787
+ var init_registry2 = __esm({
14788
+ "packages/core/src/agents/registry.ts"() {
14789
+ "use strict";
14790
+ init_sqlite2();
14791
+ init_agent_schema();
14792
+ RETRIABLE_PATTERNS = [
14793
+ /timeout/i,
14794
+ /ECONNREFUSED/,
14795
+ /ECONNRESET/,
14796
+ /EPIPE/,
14797
+ /ETIMEDOUT/,
14798
+ /rate.?limit/i,
14799
+ /429/,
14800
+ /503/,
14801
+ /502/,
14802
+ /SQLITE_BUSY/i,
14803
+ /database is locked/i,
14804
+ /temporarily unavailable/i,
14805
+ /too many requests/i,
14806
+ /network/i,
14807
+ /socket hang up/i
14808
+ ];
14809
+ PERMANENT_PATTERNS = [
14810
+ /permission denied/i,
14811
+ /EACCES/,
14812
+ /authentication/i,
14813
+ /unauthorized/i,
14814
+ /401/,
14815
+ /403/,
14816
+ /404/,
14817
+ /not found/i,
14818
+ /invalid.*token/i,
14819
+ /SQLITE_CONSTRAINT/i,
14820
+ /syntax error/i,
14821
+ /type error/i,
14822
+ /reference error/i
14823
+ ];
14824
+ }
14825
+ });
14826
+
14827
14827
  // packages/core/src/store/project-detect.ts
14828
14828
  var project_detect_exports = {};
14829
14829
  __export(project_detect_exports, {
@@ -17866,19 +17866,19 @@ async function queryAudit(options) {
17866
17866
  try {
17867
17867
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
17868
17868
  const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_tasks_schema(), tasks_schema_exports));
17869
- const { and: and8, eq: eq11, gte: gte3, or: or4 } = await import("drizzle-orm");
17869
+ const { and: and9, eq: eq12, gte: gte3, or: or4 } = await import("drizzle-orm");
17870
17870
  const db = await getDb3(process.cwd());
17871
17871
  const conditions = [];
17872
- if (options?.sessionId) conditions.push(eq11(auditLog2.sessionId, options.sessionId));
17873
- if (options?.domain) conditions.push(eq11(auditLog2.domain, options.domain));
17872
+ if (options?.sessionId) conditions.push(eq12(auditLog2.sessionId, options.sessionId));
17873
+ if (options?.domain) conditions.push(eq12(auditLog2.domain, options.domain));
17874
17874
  if (options?.operation)
17875
17875
  conditions.push(
17876
- or4(eq11(auditLog2.operation, options.operation), eq11(auditLog2.action, options.operation))
17876
+ or4(eq12(auditLog2.operation, options.operation), eq12(auditLog2.action, options.operation))
17877
17877
  );
17878
- if (options?.taskId) conditions.push(eq11(auditLog2.taskId, options.taskId));
17878
+ if (options?.taskId) conditions.push(eq12(auditLog2.taskId, options.taskId));
17879
17879
  if (options?.since) conditions.push(gte3(auditLog2.timestamp, options.since));
17880
17880
  const limit = options?.limit ?? 1e3;
17881
- const rows = await db.select().from(auditLog2).where(conditions.length > 0 ? and8(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
17881
+ const rows = await db.select().from(auditLog2).where(conditions.length > 0 ? and9(...conditions) : void 0).orderBy(auditLog2.timestamp).limit(limit);
17882
17882
  return rows.map((row) => ({
17883
17883
  timestamp: row.timestamp,
17884
17884
  sessionId: row.sessionId,
@@ -19102,6 +19102,7 @@ import { execFile as execFile3 } from "node:child_process";
19102
19102
  import { randomUUID } from "node:crypto";
19103
19103
  import { existsSync as existsSync33, constants as fsConstants3, readFileSync as readFileSync22, statSync as statSync8 } from "node:fs";
19104
19104
  import { access as access3, mkdir as mkdir5, readFile as readFile6, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
19105
+ import { homedir as getHomedir } from "node:os";
19105
19106
  import { dirname as dirname8, join as join37, resolve as resolve5 } from "node:path";
19106
19107
  import { fileURLToPath as fileURLToPath4 } from "node:url";
19107
19108
  import { promisify as promisify3 } from "node:util";
@@ -19913,12 +19914,30 @@ function checkGlobalTemplates() {
19913
19914
  fix: "cleo init (or restart MCP server)"
19914
19915
  };
19915
19916
  }
19917
+ const xdgContent = readFileSync22(injectionPath, "utf-8");
19918
+ const xdgVersion = xdgContent.match(/^Version:\s*(.+)$/m)?.[1]?.trim();
19919
+ const home = getHomedir();
19920
+ const legacyPath = join37(home, ".cleo", "templates", "CLEO-INJECTION.md");
19921
+ if (existsSync33(legacyPath)) {
19922
+ const legacyContent = readFileSync22(legacyPath, "utf-8");
19923
+ const legacyVersion = legacyContent.match(/^Version:\s*(.+)$/m)?.[1]?.trim();
19924
+ if (legacyVersion && xdgVersion && legacyVersion !== xdgVersion) {
19925
+ return {
19926
+ id: "global_templates",
19927
+ category: "global",
19928
+ status: "warning",
19929
+ message: `Legacy template version (${legacyVersion}) out of sync with XDG (${xdgVersion})`,
19930
+ details: { path: injectionPath, exists: true, xdgVersion, legacyVersion, legacyPath },
19931
+ fix: "npm install -g @cleocode/cleo (reinstall syncs both paths)"
19932
+ };
19933
+ }
19934
+ }
19916
19935
  return {
19917
19936
  id: "global_templates",
19918
19937
  category: "global",
19919
19938
  status: "passed",
19920
- message: "Global injection template present",
19921
- details: { path: injectionPath, exists: true },
19939
+ message: `Global injection template present (v${xdgVersion ?? "unknown"})`,
19940
+ details: { path: injectionPath, exists: true, version: xdgVersion },
19922
19941
  fix: null
19923
19942
  };
19924
19943
  }
@@ -20061,8 +20080,8 @@ function detectEnvMode() {
20061
20080
  const devKv = {};
20062
20081
  const devLines = devContent.trim().split("\n");
20063
20082
  for (let i = 1; i < devLines.length; i++) {
20064
- const eq11 = devLines[i].indexOf("=");
20065
- if (eq11 > 0) devKv[devLines[i].slice(0, eq11).trim()] = devLines[i].slice(eq11 + 1).trim();
20083
+ const eq12 = devLines[i].indexOf("=");
20084
+ if (eq12 > 0) devKv[devLines[i].slice(0, eq12).trim()] = devLines[i].slice(eq12 + 1).trim();
20066
20085
  }
20067
20086
  if (devKv["mode"] === "dev-ts" && devKv["source"]) {
20068
20087
  const devSource = devKv["source"].replace(/\\/g, "/");
@@ -20375,7 +20394,7 @@ var init_config = __esm({
20375
20394
  "session.autoStart": false,
20376
20395
  "session.requireNotes": true,
20377
20396
  "session.multiSession": false,
20378
- "hierarchy.requireAcceptanceCriteria": true,
20397
+ "enforcement.acceptance.mode": "block",
20379
20398
  "lifecycle.mode": "strict"
20380
20399
  }
20381
20400
  },
@@ -20385,7 +20404,7 @@ var init_config = __esm({
20385
20404
  "session.autoStart": false,
20386
20405
  "session.requireNotes": false,
20387
20406
  "session.multiSession": true,
20388
- "hierarchy.requireAcceptanceCriteria": false,
20407
+ "enforcement.acceptance.mode": "warn",
20389
20408
  "lifecycle.mode": "advisory"
20390
20409
  }
20391
20410
  },
@@ -20395,7 +20414,7 @@ var init_config = __esm({
20395
20414
  "session.autoStart": false,
20396
20415
  "session.requireNotes": false,
20397
20416
  "session.multiSession": true,
20398
- "hierarchy.requireAcceptanceCriteria": false,
20417
+ "enforcement.acceptance.mode": "off",
20399
20418
  "lifecycle.mode": "off"
20400
20419
  }
20401
20420
  }
@@ -20774,13 +20793,13 @@ __export(pipeline_exports, {
20774
20793
  listPipelines: () => listPipelines,
20775
20794
  pipelineExists: () => pipelineExists
20776
20795
  });
20777
- import { and as and5, asc as asc3, desc as desc3, eq as eq8, sql as sql9 } from "drizzle-orm";
20796
+ import { and as and6, asc as asc3, desc as desc3, eq as eq9, sql as sql9 } from "drizzle-orm";
20778
20797
  async function initializePipeline(taskId, options = {}) {
20779
20798
  const db = await getDb();
20780
20799
  const now = /* @__PURE__ */ new Date();
20781
20800
  const startStage2 = options.startStage || "research";
20782
20801
  const initialStatus = options.initialStatus || "active";
20783
- const existing = await db.select().from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
20802
+ const existing = await db.select().from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
20784
20803
  if (existing.length > 0) {
20785
20804
  throw new CleoError(101 /* ALREADY_EXISTS */, `Pipeline already exists for task ${taskId}`);
20786
20805
  }
@@ -20829,13 +20848,13 @@ async function initializePipeline(taskId, options = {}) {
20829
20848
  }
20830
20849
  async function getPipeline(taskId) {
20831
20850
  const db = await getDb();
20832
- const result = await db.select().from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
20851
+ const result = await db.select().from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
20833
20852
  if (result.length === 0) {
20834
20853
  return null;
20835
20854
  }
20836
20855
  const row = result[0];
20837
20856
  const isActive = row.status === "active";
20838
- const transitionResult = await db.select({ count: sql9`count(*)` }).from(lifecycleTransitions).where(eq8(lifecycleTransitions.pipelineId, row.id)).all();
20857
+ const transitionResult = await db.select({ count: sql9`count(*)` }).from(lifecycleTransitions).where(eq9(lifecycleTransitions.pipelineId, row.id)).all();
20839
20858
  const transitionCount = Number(transitionResult[0]?.count || 0);
20840
20859
  return {
20841
20860
  id: taskId,
@@ -20858,7 +20877,7 @@ async function advanceStage(taskId, options) {
20858
20877
  if (!options.initiatedBy) {
20859
20878
  throw new CleoError(2 /* INVALID_INPUT */, "advanceStage() requires initiatedBy agent/user");
20860
20879
  }
20861
- const pipelineResult = await db.select().from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
20880
+ const pipelineResult = await db.select().from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
20862
20881
  if (pipelineResult.length === 0) {
20863
20882
  throw new CleoError(4 /* NOT_FOUND */, `No pipeline found for task ${taskId}`);
20864
20883
  }
@@ -20866,9 +20885,9 @@ async function advanceStage(taskId, options) {
20866
20885
  const fromStage = pipeline2.currentStageId;
20867
20886
  const toStage = options.toStage;
20868
20887
  const currentStageResult = await db.select().from(lifecycleStages).where(
20869
- and5(
20870
- eq8(lifecycleStages.pipelineId, pipeline2.id),
20871
- eq8(lifecycleStages.stageName, fromStage)
20888
+ and6(
20889
+ eq9(lifecycleStages.pipelineId, pipeline2.id),
20890
+ eq9(lifecycleStages.stageName, fromStage)
20872
20891
  )
20873
20892
  ).limit(1).all();
20874
20893
  if (currentStageResult.length === 0) {
@@ -20879,9 +20898,9 @@ async function advanceStage(taskId, options) {
20879
20898
  }
20880
20899
  const currentStageRecord = currentStageResult[0];
20881
20900
  const targetStageResult = await db.select().from(lifecycleStages).where(
20882
- and5(
20883
- eq8(lifecycleStages.pipelineId, pipeline2.id),
20884
- eq8(lifecycleStages.stageName, toStage)
20901
+ and6(
20902
+ eq9(lifecycleStages.pipelineId, pipeline2.id),
20903
+ eq9(lifecycleStages.stageName, toStage)
20885
20904
  )
20886
20905
  ).limit(1).all();
20887
20906
  if (targetStageResult.length === 0) {
@@ -20894,14 +20913,14 @@ async function advanceStage(taskId, options) {
20894
20913
  await db.update(lifecycleStages).set({
20895
20914
  status: "completed",
20896
20915
  completedAt: now.toISOString()
20897
- }).where(eq8(lifecycleStages.id, currentStageRecord.id)).run();
20916
+ }).where(eq9(lifecycleStages.id, currentStageRecord.id)).run();
20898
20917
  await db.update(lifecycleStages).set({
20899
20918
  status: "in_progress",
20900
20919
  startedAt: now.toISOString()
20901
- }).where(eq8(lifecycleStages.id, targetStageRecord.id)).run();
20920
+ }).where(eq9(lifecycleStages.id, targetStageRecord.id)).run();
20902
20921
  await db.update(lifecyclePipelines).set({
20903
20922
  currentStageId: toStage
20904
- }).where(eq8(lifecyclePipelines.id, pipeline2.id)).run();
20923
+ }).where(eq9(lifecyclePipelines.id, pipeline2.id)).run();
20905
20924
  await db.insert(lifecycleTransitions).values({
20906
20925
  id: `${pipeline2.id}_${now.getTime()}_${Math.random().toString(36).slice(2, 7)}`,
20907
20926
  pipelineId: pipeline2.id,
@@ -20918,7 +20937,7 @@ async function advanceStage(taskId, options) {
20918
20937
  }
20919
20938
  async function getCurrentStage(taskId) {
20920
20939
  const db = await getDb();
20921
- const result = await db.select({ currentStageId: lifecyclePipelines.currentStageId }).from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
20940
+ const result = await db.select({ currentStageId: lifecyclePipelines.currentStageId }).from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
20922
20941
  if (result.length === 0) {
20923
20942
  throw new CleoError(4 /* NOT_FOUND */, `No pipeline found for task ${taskId}`);
20924
20943
  }
@@ -20930,43 +20949,43 @@ async function listPipelines(options = {}) {
20930
20949
  const conditions = [];
20931
20950
  if (options.status) {
20932
20951
  conditions.push(
20933
- eq8(
20952
+ eq9(
20934
20953
  lifecyclePipelines.status,
20935
20954
  options.status
20936
20955
  )
20937
20956
  );
20938
20957
  }
20939
20958
  if (options.currentStage) {
20940
- conditions.push(eq8(lifecyclePipelines.currentStageId, options.currentStage));
20959
+ conditions.push(eq9(lifecyclePipelines.currentStageId, options.currentStage));
20941
20960
  }
20942
20961
  if (conditions.length > 0) {
20943
- const whereClause = conditions.length === 1 ? conditions[0] : and5(...conditions);
20962
+ const whereClause = conditions.length === 1 ? conditions[0] : and6(...conditions);
20944
20963
  query = db.select().from(lifecyclePipelines).where(whereClause);
20945
20964
  }
20946
20965
  if (options.orderBy) {
20947
20966
  const order = options.order === "asc" ? asc3 : desc3;
20948
20967
  switch (options.orderBy) {
20949
20968
  case "createdAt":
20950
- query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and5(...conditions) : void 0).orderBy(order(lifecyclePipelines.startedAt));
20969
+ query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and6(...conditions) : void 0).orderBy(order(lifecyclePipelines.startedAt));
20951
20970
  break;
20952
20971
  case "currentStage":
20953
- query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and5(...conditions) : void 0).orderBy(order(lifecyclePipelines.currentStageId));
20972
+ query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and6(...conditions) : void 0).orderBy(order(lifecyclePipelines.currentStageId));
20954
20973
  break;
20955
20974
  }
20956
20975
  } else {
20957
- query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and5(...conditions) : void 0).orderBy(desc3(lifecyclePipelines.startedAt));
20976
+ query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and6(...conditions) : void 0).orderBy(desc3(lifecyclePipelines.startedAt));
20958
20977
  }
20959
20978
  if (options.limit) {
20960
- query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and5(...conditions) : void 0).orderBy(desc3(lifecyclePipelines.startedAt)).limit(options.limit);
20979
+ query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and6(...conditions) : void 0).orderBy(desc3(lifecyclePipelines.startedAt)).limit(options.limit);
20961
20980
  }
20962
20981
  if (options.offset) {
20963
- query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and5(...conditions) : void 0).orderBy(desc3(lifecyclePipelines.startedAt)).limit(options.limit || 100).offset(options.offset);
20982
+ query = db.select().from(lifecyclePipelines).where(conditions.length > 0 ? and6(...conditions) : void 0).orderBy(desc3(lifecyclePipelines.startedAt)).limit(options.limit || 100).offset(options.offset);
20964
20983
  }
20965
20984
  const results = await query.all();
20966
20985
  return Promise.all(
20967
20986
  results.map(async (row) => {
20968
20987
  const isActive = row.status === "active";
20969
- const transitionResult = await db.select({ count: sql9`count(*)` }).from(lifecycleTransitions).where(eq8(lifecycleTransitions.pipelineId, row.id)).all();
20988
+ const transitionResult = await db.select({ count: sql9`count(*)` }).from(lifecycleTransitions).where(eq9(lifecycleTransitions.pipelineId, row.id)).all();
20970
20989
  const transitionCount = Number(transitionResult[0]?.count || 0);
20971
20990
  return {
20972
20991
  id: row.taskId,
@@ -20985,7 +21004,7 @@ async function listPipelines(options = {}) {
20985
21004
  async function completePipeline(taskId, reason) {
20986
21005
  const db = await getDb();
20987
21006
  const now = /* @__PURE__ */ new Date();
20988
- const pipelineResult = await db.select().from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
21007
+ const pipelineResult = await db.select().from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
20989
21008
  if (pipelineResult.length === 0) {
20990
21009
  throw new CleoError(4 /* NOT_FOUND */, `No pipeline found for task ${taskId}`);
20991
21010
  }
@@ -21000,21 +21019,21 @@ async function completePipeline(taskId, reason) {
21000
21019
  stageUpdate.metadataJson = JSON.stringify({ completionReason: reason });
21001
21020
  }
21002
21021
  await db.update(lifecycleStages).set(stageUpdate).where(
21003
- and5(
21004
- eq8(lifecycleStages.pipelineId, pipeline2.id),
21005
- eq8(lifecycleStages.stageName, pipeline2.currentStageId)
21022
+ and6(
21023
+ eq9(lifecycleStages.pipelineId, pipeline2.id),
21024
+ eq9(lifecycleStages.stageName, pipeline2.currentStageId)
21006
21025
  )
21007
21026
  ).run();
21008
21027
  }
21009
21028
  await db.update(lifecyclePipelines).set({
21010
21029
  status: "completed",
21011
21030
  completedAt: now.toISOString()
21012
- }).where(eq8(lifecyclePipelines.id, pipeline2.id)).run();
21031
+ }).where(eq9(lifecyclePipelines.id, pipeline2.id)).run();
21013
21032
  }
21014
21033
  async function cancelPipeline(taskId, reason) {
21015
21034
  const db = await getDb();
21016
21035
  const now = /* @__PURE__ */ new Date();
21017
- const pipelineResult = await db.select().from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
21036
+ const pipelineResult = await db.select().from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
21018
21037
  if (pipelineResult.length === 0) {
21019
21038
  throw new CleoError(4 /* NOT_FOUND */, `No pipeline found for task ${taskId}`);
21020
21039
  }
@@ -21031,20 +21050,20 @@ async function cancelPipeline(taskId, reason) {
21031
21050
  blockedAt: now.toISOString(),
21032
21051
  blockReason: `Pipeline cancelled: ${reason}`
21033
21052
  }).where(
21034
- and5(
21035
- eq8(lifecycleStages.pipelineId, pipeline2.id),
21036
- eq8(lifecycleStages.stageName, pipeline2.currentStageId)
21053
+ and6(
21054
+ eq9(lifecycleStages.pipelineId, pipeline2.id),
21055
+ eq9(lifecycleStages.stageName, pipeline2.currentStageId)
21037
21056
  )
21038
21057
  ).run();
21039
21058
  }
21040
21059
  await db.update(lifecyclePipelines).set({
21041
21060
  status: "cancelled",
21042
21061
  completedAt: now.toISOString()
21043
- }).where(eq8(lifecyclePipelines.id, pipeline2.id)).run();
21062
+ }).where(eq9(lifecyclePipelines.id, pipeline2.id)).run();
21044
21063
  }
21045
21064
  async function pipelineExists(taskId) {
21046
21065
  const db = await getDb();
21047
- const result = await db.select({ count: sql9`count(*)` }).from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).all();
21066
+ const result = await db.select({ count: sql9`count(*)` }).from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).all();
21048
21067
  return (result[0]?.count || 0) > 0;
21049
21068
  }
21050
21069
  async function getPipelineStatistics() {
@@ -21088,12 +21107,12 @@ async function getPipelineStatistics() {
21088
21107
  }
21089
21108
  async function getPipelineStages(taskId) {
21090
21109
  const db = await getDb();
21091
- const pipelineResult = await db.select({ id: lifecyclePipelines.id }).from(lifecyclePipelines).where(eq8(lifecyclePipelines.taskId, taskId)).limit(1).all();
21110
+ const pipelineResult = await db.select({ id: lifecyclePipelines.id }).from(lifecyclePipelines).where(eq9(lifecyclePipelines.taskId, taskId)).limit(1).all();
21092
21111
  if (pipelineResult.length === 0) {
21093
21112
  throw new CleoError(4 /* NOT_FOUND */, `No pipeline found for task ${taskId}`);
21094
21113
  }
21095
21114
  const pipelineId = pipelineResult[0].id;
21096
- const stages = await db.select().from(lifecycleStages).where(eq8(lifecycleStages.pipelineId, pipelineId)).orderBy(asc3(lifecycleStages.sequence)).all();
21115
+ const stages = await db.select().from(lifecycleStages).where(eq9(lifecycleStages.pipelineId, pipelineId)).orderBy(asc3(lifecycleStages.sequence)).all();
21097
21116
  return stages.map((stage) => ({
21098
21117
  id: stage.id,
21099
21118
  pipelineId: stage.pipelineId,
@@ -23949,9 +23968,9 @@ async function nexusRegister(projectPath, name2, permissions = "read") {
23949
23968
  const projectHash = generateProjectHash(projectPath);
23950
23969
  await nexusInit();
23951
23970
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
23952
- const { eq: eq11 } = await import("drizzle-orm");
23971
+ const { eq: eq12 } = await import("drizzle-orm");
23953
23972
  const db = await getNexusDb2();
23954
- const existingRows = await db.select().from(projectRegistry).where(eq11(projectRegistry.projectHash, projectHash));
23973
+ const existingRows = await db.select().from(projectRegistry).where(eq12(projectRegistry.projectHash, projectHash));
23955
23974
  const existing = existingRows[0];
23956
23975
  if (existing?.permissions) {
23957
23976
  throw new CleoError(
@@ -23960,7 +23979,7 @@ async function nexusRegister(projectPath, name2, permissions = "read") {
23960
23979
  );
23961
23980
  }
23962
23981
  if (!existing) {
23963
- const nameConflictRows = await db.select().from(projectRegistry).where(eq11(projectRegistry.name, projectName));
23982
+ const nameConflictRows = await db.select().from(projectRegistry).where(eq12(projectRegistry.name, projectName));
23964
23983
  if (nameConflictRows.length > 0) {
23965
23984
  throw new CleoError(
23966
23985
  6 /* VALIDATION_ERROR */,
@@ -23978,7 +23997,7 @@ async function nexusRegister(projectPath, name2, permissions = "read") {
23978
23997
  taskCount: meta.taskCount,
23979
23998
  labelsJson: JSON.stringify(meta.labels),
23980
23999
  lastSeen: now
23981
- }).where(eq11(projectRegistry.projectHash, projectHash));
24000
+ }).where(eq12(projectRegistry.projectHash, projectHash));
23982
24001
  } else {
23983
24002
  if (!projectId) {
23984
24003
  projectId = randomUUID3();
@@ -24016,9 +24035,9 @@ async function nexusUnregister(nameOrHash) {
24016
24035
  throw new CleoError(4 /* NOT_FOUND */, `Project not found in registry: ${nameOrHash}`);
24017
24036
  }
24018
24037
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
24019
- const { eq: eq11 } = await import("drizzle-orm");
24038
+ const { eq: eq12 } = await import("drizzle-orm");
24020
24039
  const db = await getNexusDb2();
24021
- await db.delete(projectRegistry).where(eq11(projectRegistry.projectHash, project.hash));
24040
+ await db.delete(projectRegistry).where(eq12(projectRegistry.projectHash, project.hash));
24022
24041
  await writeNexusAudit({
24023
24042
  action: "unregister",
24024
24043
  projectHash: project.hash,
@@ -24040,9 +24059,9 @@ async function nexusList() {
24040
24059
  async function nexusGetProject(nameOrHash) {
24041
24060
  try {
24042
24061
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
24043
- const { eq: eq11, or: or4 } = await import("drizzle-orm");
24062
+ const { eq: eq12, or: or4 } = await import("drizzle-orm");
24044
24063
  const db = await getNexusDb2();
24045
- const rows = await db.select().from(projectRegistry).where(or4(eq11(projectRegistry.projectHash, nameOrHash), eq11(projectRegistry.name, nameOrHash)));
24064
+ const rows = await db.select().from(projectRegistry).where(or4(eq12(projectRegistry.projectHash, nameOrHash), eq12(projectRegistry.name, nameOrHash)));
24046
24065
  const row = rows[0];
24047
24066
  if (!row) return null;
24048
24067
  return rowToProject(row);
@@ -24065,14 +24084,14 @@ async function nexusSync(nameOrHash) {
24065
24084
  const meta = await readProjectMeta(project.path);
24066
24085
  const now = (/* @__PURE__ */ new Date()).toISOString();
24067
24086
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
24068
- const { eq: eq11 } = await import("drizzle-orm");
24087
+ const { eq: eq12 } = await import("drizzle-orm");
24069
24088
  const db = await getNexusDb2();
24070
24089
  await db.update(projectRegistry).set({
24071
24090
  taskCount: meta.taskCount,
24072
24091
  labelsJson: JSON.stringify(meta.labels),
24073
24092
  lastSync: now,
24074
24093
  lastSeen: now
24075
- }).where(eq11(projectRegistry.projectHash, project.hash));
24094
+ }).where(eq12(projectRegistry.projectHash, project.hash));
24076
24095
  await writeNexusAudit({
24077
24096
  action: "sync",
24078
24097
  projectHash: project.hash,
@@ -24086,7 +24105,7 @@ async function nexusSyncAll() {
24086
24105
  let synced = 0;
24087
24106
  let failed = 0;
24088
24107
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
24089
- const { eq: eq11 } = await import("drizzle-orm");
24108
+ const { eq: eq12 } = await import("drizzle-orm");
24090
24109
  const db = await getNexusDb2();
24091
24110
  for (const project of projects) {
24092
24111
  try {
@@ -24097,7 +24116,7 @@ async function nexusSyncAll() {
24097
24116
  labelsJson: JSON.stringify(meta.labels),
24098
24117
  lastSync: now,
24099
24118
  lastSeen: now
24100
- }).where(eq11(projectRegistry.projectHash, project.hash));
24119
+ }).where(eq12(projectRegistry.projectHash, project.hash));
24101
24120
  synced++;
24102
24121
  } catch {
24103
24122
  failed++;
@@ -24117,9 +24136,9 @@ async function nexusSetPermission(nameOrHash, permission) {
24117
24136
  throw new CleoError(4 /* NOT_FOUND */, `Project not found in registry: ${nameOrHash}`);
24118
24137
  }
24119
24138
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
24120
- const { eq: eq11 } = await import("drizzle-orm");
24139
+ const { eq: eq12 } = await import("drizzle-orm");
24121
24140
  const db = await getNexusDb2();
24122
- await db.update(projectRegistry).set({ permissions: permission }).where(eq11(projectRegistry.projectHash, project.hash));
24141
+ await db.update(projectRegistry).set({ permissions: permission }).where(eq12(projectRegistry.projectHash, project.hash));
24123
24142
  await writeNexusAudit({
24124
24143
  action: "set-permission",
24125
24144
  projectHash: project.hash,
@@ -24135,12 +24154,12 @@ async function nexusReconcile(projectRoot) {
24135
24154
  }
24136
24155
  await nexusInit();
24137
24156
  const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
24138
- const { eq: eq11 } = await import("drizzle-orm");
24157
+ const { eq: eq12 } = await import("drizzle-orm");
24139
24158
  const db = await getNexusDb2();
24140
24159
  const projectId = await readProjectId(projectRoot);
24141
24160
  const currentHash = generateProjectHash(projectRoot);
24142
24161
  if (projectId) {
24143
- const hashRows2 = await db.select().from(projectRegistry).where(eq11(projectRegistry.projectHash, currentHash));
24162
+ const hashRows2 = await db.select().from(projectRegistry).where(eq12(projectRegistry.projectHash, currentHash));
24144
24163
  const hashMatch2 = hashRows2[0];
24145
24164
  if (hashMatch2 && hashMatch2.projectId !== projectId) {
24146
24165
  await writeNexusAudit({
@@ -24159,12 +24178,12 @@ async function nexusReconcile(projectRoot) {
24159
24178
  }
24160
24179
  }
24161
24180
  if (projectId) {
24162
- const idRows = await db.select().from(projectRegistry).where(eq11(projectRegistry.projectId, projectId));
24181
+ const idRows = await db.select().from(projectRegistry).where(eq12(projectRegistry.projectId, projectId));
24163
24182
  const existing = idRows[0];
24164
24183
  if (existing) {
24165
24184
  const now = (/* @__PURE__ */ new Date()).toISOString();
24166
24185
  if (existing.projectPath === projectRoot) {
24167
- await db.update(projectRegistry).set({ lastSeen: now }).where(eq11(projectRegistry.projectId, projectId));
24186
+ await db.update(projectRegistry).set({ lastSeen: now }).where(eq12(projectRegistry.projectId, projectId));
24168
24187
  await writeNexusAudit({
24169
24188
  action: "reconcile",
24170
24189
  projectHash: currentHash,
@@ -24180,7 +24199,7 @@ async function nexusReconcile(projectRoot) {
24180
24199
  projectPath: projectRoot,
24181
24200
  projectHash: currentHash,
24182
24201
  lastSeen: now
24183
- }).where(eq11(projectRegistry.projectId, projectId));
24202
+ }).where(eq12(projectRegistry.projectId, projectId));
24184
24203
  await writeNexusAudit({
24185
24204
  action: "reconcile",
24186
24205
  projectHash: currentHash,
@@ -24192,11 +24211,11 @@ async function nexusReconcile(projectRoot) {
24192
24211
  return { status: "path_updated", oldPath, newPath: projectRoot };
24193
24212
  }
24194
24213
  }
24195
- const hashRows = await db.select().from(projectRegistry).where(eq11(projectRegistry.projectHash, currentHash));
24214
+ const hashRows = await db.select().from(projectRegistry).where(eq12(projectRegistry.projectHash, currentHash));
24196
24215
  const hashMatch = hashRows[0];
24197
24216
  if (hashMatch) {
24198
24217
  const now = (/* @__PURE__ */ new Date()).toISOString();
24199
- await db.update(projectRegistry).set({ lastSeen: now }).where(eq11(projectRegistry.projectHash, currentHash));
24218
+ await db.update(projectRegistry).set({ lastSeen: now }).where(eq12(projectRegistry.projectHash, currentHash));
24200
24219
  await writeNexusAudit({
24201
24220
  action: "reconcile",
24202
24221
  projectHash: currentHash,
@@ -26401,7 +26420,7 @@ async function syncAdrsToDb(projectRoot) {
26401
26420
  return result;
26402
26421
  }
26403
26422
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
26404
- const { eq: eq11 } = await import("drizzle-orm");
26423
+ const { eq: eq12 } = await import("drizzle-orm");
26405
26424
  const db = await getDb3(projectRoot);
26406
26425
  const now = (/* @__PURE__ */ new Date()).toISOString();
26407
26426
  const allFiles = collectAdrFiles(adrsDir);
@@ -26435,15 +26454,15 @@ async function syncAdrsToDb(projectRoot) {
26435
26454
  topics: fm.Topics ?? null,
26436
26455
  updatedAt: now
26437
26456
  };
26438
- const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq11(architectureDecisions.id, record2.id)).all();
26457
+ const existing = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq12(architectureDecisions.id, record2.id)).all();
26439
26458
  if (existing.length > 0) {
26440
- await db.update(architectureDecisions).set(rowBase).where(eq11(architectureDecisions.id, record2.id));
26459
+ await db.update(architectureDecisions).set(rowBase).where(eq12(architectureDecisions.id, record2.id));
26441
26460
  result.updated++;
26442
26461
  } else {
26443
26462
  await db.insert(architectureDecisions).values({ ...rowBase, createdAt: now });
26444
26463
  result.inserted++;
26445
26464
  }
26446
- await db.delete(adrTaskLinks).where(eq11(adrTaskLinks.adrId, record2.id));
26465
+ await db.delete(adrTaskLinks).where(eq12(adrTaskLinks.adrId, record2.id));
26447
26466
  if (fm["Related Tasks"]) {
26448
26467
  for (const taskId of parseTaskIds2(fm["Related Tasks"])) {
26449
26468
  await db.insert(adrTaskLinks).values({ adrId: record2.id, taskId, linkType: "related" });
@@ -26545,18 +26564,27 @@ __export(agents_exports, {
26545
26564
  AGENT_INSTANCE_STATUSES: () => AGENT_INSTANCE_STATUSES,
26546
26565
  AGENT_TYPES: () => AGENT_TYPES,
26547
26566
  DEFAULT_RETRY_POLICY: () => DEFAULT_RETRY_POLICY,
26567
+ HEARTBEAT_INTERVAL_MS: () => HEARTBEAT_INTERVAL_MS,
26568
+ MAX_TASKS_PER_AGENT: () => MAX_TASKS_PER_AGENT,
26569
+ STALE_THRESHOLD_MS: () => STALE_THRESHOLD_MS,
26548
26570
  agentErrorLog: () => agentErrorLog,
26549
26571
  agentInstances: () => agentInstances,
26550
26572
  calculateDelay: () => calculateDelay,
26551
- checkAgentHealth: () => checkAgentHealth,
26573
+ checkAgentHealth: () => checkAgentHealth2,
26552
26574
  classifyError: () => classifyError,
26553
26575
  createRetryPolicy: () => createRetryPolicy,
26554
26576
  deregisterAgent: () => deregisterAgent,
26577
+ detectCrashedAgents: () => detectCrashedAgents,
26578
+ detectStaleAgents: () => detectStaleAgents,
26555
26579
  findLeastLoadedAgent: () => findLeastLoadedAgent,
26580
+ findStaleAgentRows: () => checkAgentHealth,
26556
26581
  generateAgentId: () => generateAgentId,
26582
+ getAgentCapacity: () => getAgentCapacity,
26557
26583
  getAgentErrorHistory: () => getAgentErrorHistory,
26558
26584
  getAgentInstance: () => getAgentInstance,
26559
26585
  getAgentPerformanceHistory: () => getAgentPerformanceHistory,
26586
+ getAgentSpecializations: () => getAgentSpecializations,
26587
+ getAgentsByCapacity: () => getAgentsByCapacity,
26560
26588
  getAvailableCapacity: () => getAvailableCapacity,
26561
26589
  getCapacitySummary: () => getCapacitySummary,
26562
26590
  getHealthReport: () => getHealthReport,
@@ -26568,85 +26596,35 @@ __export(agents_exports, {
26568
26596
  markCrashed: () => markCrashed,
26569
26597
  processAgentLifecycleEvent: () => processAgentLifecycleEvent,
26570
26598
  recordAgentExecution: () => recordAgentExecution,
26599
+ recordAgentPerformance: () => recordAgentPerformance,
26571
26600
  recordFailurePattern: () => recordFailurePattern,
26601
+ recordHeartbeat: () => recordHeartbeat,
26572
26602
  recoverCrashedAgents: () => recoverCrashedAgents,
26573
26603
  registerAgent: () => registerAgent,
26574
26604
  shouldRetry: () => shouldRetry,
26575
26605
  storeHealingStrategy: () => storeHealingStrategy,
26606
+ updateAgentSpecializations: () => updateAgentSpecializations,
26576
26607
  updateAgentStatus: () => updateAgentStatus,
26577
26608
  updateCapacity: () => updateCapacity,
26578
26609
  withRetry: () => withRetry
26579
26610
  });
26580
- init_agent_schema();
26581
26611
 
26582
- // packages/core/src/agents/capacity.ts
26612
+ // packages/core/src/agents/agent-registry.ts
26583
26613
  init_sqlite2();
26584
26614
  init_agent_schema();
26585
- init_registry2();
26586
- import { eq as eq6 } from "drizzle-orm";
26587
- async function updateCapacity(id, capacity, cwd) {
26588
- if (capacity < 0 || capacity > 1) {
26589
- throw new Error(`Capacity must be between 0.0 and 1.0, got ${capacity}`);
26590
- }
26591
- const db = await getDb(cwd);
26592
- const existing = await db.select().from(agentInstances).where(eq6(agentInstances.id, id)).get();
26593
- if (!existing) return null;
26594
- const capacityStr = capacity.toFixed(4);
26595
- await db.update(agentInstances).set({ capacity: capacityStr }).where(eq6(agentInstances.id, id));
26596
- return { ...existing, capacity: capacityStr };
26597
- }
26598
- async function getAvailableCapacity(cwd) {
26599
- const agents = await listAgentInstances({ status: ["active", "idle"] }, cwd);
26600
- return agents.reduce((sum, agent) => sum + parseCapacity(agent.capacity), 0);
26601
- }
26602
- async function findLeastLoadedAgent(agentType, cwd) {
26603
- const filters = agentType ? { status: ["active", "idle"], agentType } : { status: ["active", "idle"] };
26604
- const agents = await listAgentInstances(filters, cwd);
26605
- if (agents.length === 0) return null;
26606
- let best = agents[0];
26607
- let bestCapacity = parseCapacity(best.capacity);
26608
- for (let i = 1; i < agents.length; i++) {
26609
- const cap = parseCapacity(agents[i].capacity);
26610
- if (cap > bestCapacity) {
26611
- best = agents[i];
26612
- bestCapacity = cap;
26613
- }
26614
- }
26615
- return best;
26616
- }
26617
- async function isOverloaded(threshold = 0.1, cwd) {
26618
- const capacity = await getAvailableCapacity(cwd);
26619
- return capacity < threshold;
26620
- }
26621
- async function getCapacitySummary(threshold = 0.1, cwd) {
26622
- const agents = await listAgentInstances({ status: ["active", "idle"] }, cwd);
26623
- const totalCapacity = agents.reduce((sum, a) => sum + parseCapacity(a.capacity), 0);
26624
- const activeAgentCount = agents.length;
26625
- return {
26626
- totalCapacity,
26627
- activeAgentCount,
26628
- averageCapacity: activeAgentCount > 0 ? totalCapacity / activeAgentCount : 0,
26629
- overloaded: totalCapacity < threshold,
26630
- threshold
26631
- };
26632
- }
26633
- function parseCapacity(value) {
26634
- if (!value) return 0;
26635
- const parsed = parseFloat(value);
26636
- return Number.isNaN(parsed) ? 0 : Math.max(0, Math.min(1, parsed));
26637
- }
26615
+ import { and as and5, eq as eq7, inArray as inArray5 } from "drizzle-orm";
26638
26616
 
26639
26617
  // packages/core/src/agents/execution-learning.ts
26640
26618
  init_brain_accessor();
26641
- import { randomBytes as randomBytes2 } from "node:crypto";
26619
+ import { randomBytes } from "node:crypto";
26642
26620
  function generateDecisionId() {
26643
- return `AGT-${randomBytes2(5).toString("hex")}`;
26621
+ return `AGT-${randomBytes(5).toString("hex")}`;
26644
26622
  }
26645
26623
  function generatePatternId() {
26646
- return `P-agt-${randomBytes2(4).toString("hex")}`;
26624
+ return `P-agt-${randomBytes(4).toString("hex")}`;
26647
26625
  }
26648
26626
  function generateObservationId() {
26649
- return `O-agt-${randomBytes2(4).toString("hex")}`;
26627
+ return `O-agt-${randomBytes(4).toString("hex")}`;
26650
26628
  }
26651
26629
  function nowSql() {
26652
26630
  return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
@@ -26923,6 +26901,215 @@ function buildHealingSuggestion(agentType, taskType, errorType, frequency) {
26923
26901
  return `Unknown failure for ${agentType} on ${taskType} tasks (${frequency}x). Check agent logs, retry with fresh context, or reassign to a different agent type.`;
26924
26902
  }
26925
26903
 
26904
+ // packages/core/src/agents/agent-registry.ts
26905
+ init_registry2();
26906
+ var MAX_TASKS_PER_AGENT = 5;
26907
+ async function getAgentCapacity(agentId, cwd) {
26908
+ const db = await getDb(cwd);
26909
+ const agent = await db.select().from(agentInstances).where(eq7(agentInstances.id, agentId)).get();
26910
+ if (!agent) return null;
26911
+ const isTerminal = agent.status === "stopped" || agent.status === "crashed";
26912
+ if (isTerminal) {
26913
+ return {
26914
+ agentId: agent.id,
26915
+ agentType: agent.agentType,
26916
+ status: agent.status,
26917
+ activeTasks: 0,
26918
+ remainingCapacity: 0,
26919
+ maxCapacity: MAX_TASKS_PER_AGENT,
26920
+ available: false
26921
+ };
26922
+ }
26923
+ const children = await db.select({ id: agentInstances.id }).from(agentInstances).where(
26924
+ and5(
26925
+ eq7(agentInstances.parentAgentId, agentId),
26926
+ inArray5(agentInstances.status, ["starting", "active", "idle", "error"])
26927
+ )
26928
+ ).all();
26929
+ const selfTask = agent.taskId != null ? 1 : 0;
26930
+ const activeTasks = selfTask + children.length;
26931
+ const remainingCapacity = Math.max(0, MAX_TASKS_PER_AGENT - activeTasks);
26932
+ return {
26933
+ agentId: agent.id,
26934
+ agentType: agent.agentType,
26935
+ status: agent.status,
26936
+ activeTasks,
26937
+ remainingCapacity,
26938
+ maxCapacity: MAX_TASKS_PER_AGENT,
26939
+ available: remainingCapacity > 0
26940
+ };
26941
+ }
26942
+ async function getAgentsByCapacity(agentType, cwd) {
26943
+ const filters = agentType ? { status: ["active", "idle"], agentType } : { status: ["active", "idle"] };
26944
+ const activeAgents = await listAgentInstances(filters, cwd);
26945
+ const capacities = await Promise.all(
26946
+ activeAgents.map((agent) => getAgentCapacity(agent.id, cwd))
26947
+ );
26948
+ return capacities.filter((c) => c !== null).sort((a, b) => b.remainingCapacity - a.remainingCapacity);
26949
+ }
26950
+ async function getAgentSpecializations(agentId, cwd) {
26951
+ const db = await getDb(cwd);
26952
+ const agent = await db.select({ metadataJson: agentInstances.metadataJson }).from(agentInstances).where(eq7(agentInstances.id, agentId)).get();
26953
+ if (!agent) return [];
26954
+ try {
26955
+ const meta = JSON.parse(agent.metadataJson ?? "{}");
26956
+ const specs = meta.specializations;
26957
+ if (!Array.isArray(specs)) return [];
26958
+ return specs.filter((s) => typeof s === "string");
26959
+ } catch {
26960
+ return [];
26961
+ }
26962
+ }
26963
+ async function updateAgentSpecializations(agentId, specializations, cwd) {
26964
+ const db = await getDb(cwd);
26965
+ const agent = await db.select({ metadataJson: agentInstances.metadataJson }).from(agentInstances).where(eq7(agentInstances.id, agentId)).get();
26966
+ if (!agent) return null;
26967
+ let existing = {};
26968
+ try {
26969
+ existing = JSON.parse(agent.metadataJson ?? "{}");
26970
+ } catch {
26971
+ }
26972
+ const updated = { ...existing, specializations };
26973
+ await db.update(agentInstances).set({ metadataJson: JSON.stringify(updated) }).where(eq7(agentInstances.id, agentId));
26974
+ return specializations;
26975
+ }
26976
+ async function recordAgentPerformance(agentId, metrics, cwd) {
26977
+ const db = await getDb(cwd);
26978
+ const agent = await db.select({ agentType: agentInstances.agentType, sessionId: agentInstances.sessionId }).from(agentInstances).where(eq7(agentInstances.id, agentId)).get();
26979
+ if (!agent) return null;
26980
+ const event = {
26981
+ agentId,
26982
+ agentType: agent.agentType,
26983
+ taskId: metrics.taskId,
26984
+ taskType: metrics.taskType,
26985
+ outcome: metrics.outcome,
26986
+ taskLabels: metrics.taskLabels,
26987
+ sessionId: metrics.sessionId ?? agent.sessionId ?? void 0,
26988
+ durationMs: metrics.durationMs,
26989
+ errorMessage: metrics.errorMessage,
26990
+ errorType: metrics.errorType
26991
+ };
26992
+ const decision = await recordAgentExecution(event, cwd);
26993
+ return decision?.id ?? null;
26994
+ }
26995
+
26996
+ // packages/core/src/agents/index.ts
26997
+ init_agent_schema();
26998
+
26999
+ // packages/core/src/agents/capacity.ts
27000
+ init_sqlite2();
27001
+ init_agent_schema();
27002
+ init_registry2();
27003
+ import { eq as eq8 } from "drizzle-orm";
27004
+ async function updateCapacity(id, capacity, cwd) {
27005
+ if (capacity < 0 || capacity > 1) {
27006
+ throw new Error(`Capacity must be between 0.0 and 1.0, got ${capacity}`);
27007
+ }
27008
+ const db = await getDb(cwd);
27009
+ const existing = await db.select().from(agentInstances).where(eq8(agentInstances.id, id)).get();
27010
+ if (!existing) return null;
27011
+ const capacityStr = capacity.toFixed(4);
27012
+ await db.update(agentInstances).set({ capacity: capacityStr }).where(eq8(agentInstances.id, id));
27013
+ return { ...existing, capacity: capacityStr };
27014
+ }
27015
+ async function getAvailableCapacity(cwd) {
27016
+ const agents = await listAgentInstances({ status: ["active", "idle"] }, cwd);
27017
+ return agents.reduce((sum, agent) => sum + parseCapacity(agent.capacity), 0);
27018
+ }
27019
+ async function findLeastLoadedAgent(agentType, cwd) {
27020
+ const filters = agentType ? { status: ["active", "idle"], agentType } : { status: ["active", "idle"] };
27021
+ const agents = await listAgentInstances(filters, cwd);
27022
+ if (agents.length === 0) return null;
27023
+ let best = agents[0];
27024
+ let bestCapacity = parseCapacity(best.capacity);
27025
+ for (let i = 1; i < agents.length; i++) {
27026
+ const cap = parseCapacity(agents[i].capacity);
27027
+ if (cap > bestCapacity) {
27028
+ best = agents[i];
27029
+ bestCapacity = cap;
27030
+ }
27031
+ }
27032
+ return best;
27033
+ }
27034
+ async function isOverloaded(threshold = 0.1, cwd) {
27035
+ const capacity = await getAvailableCapacity(cwd);
27036
+ return capacity < threshold;
27037
+ }
27038
+ async function getCapacitySummary(threshold = 0.1, cwd) {
27039
+ const agents = await listAgentInstances({ status: ["active", "idle"] }, cwd);
27040
+ const totalCapacity = agents.reduce((sum, a) => sum + parseCapacity(a.capacity), 0);
27041
+ const activeAgentCount = agents.length;
27042
+ return {
27043
+ totalCapacity,
27044
+ activeAgentCount,
27045
+ averageCapacity: activeAgentCount > 0 ? totalCapacity / activeAgentCount : 0,
27046
+ overloaded: totalCapacity < threshold,
27047
+ threshold
27048
+ };
27049
+ }
27050
+ function parseCapacity(value) {
27051
+ if (!value) return 0;
27052
+ const parsed = parseFloat(value);
27053
+ return Number.isNaN(parsed) ? 0 : Math.max(0, Math.min(1, parsed));
27054
+ }
27055
+
27056
+ // packages/core/src/agents/health-monitor.ts
27057
+ init_registry2();
27058
+ var HEARTBEAT_INTERVAL_MS = 3e4;
27059
+ var STALE_THRESHOLD_MS = 3 * 6e4;
27060
+ var ALIVE_STATUSES = ["starting", "active", "idle"];
27061
+ async function recordHeartbeat(agentId, cwd) {
27062
+ return heartbeat(agentId, cwd);
27063
+ }
27064
+ async function checkAgentHealth2(agentId, thresholdMs = STALE_THRESHOLD_MS, cwd) {
27065
+ const all = await listAgentInstances(void 0, cwd);
27066
+ const agent = all.find((a) => a.id === agentId);
27067
+ if (!agent) return null;
27068
+ return buildHealthStatus(agent, thresholdMs);
27069
+ }
27070
+ async function detectStaleAgents(thresholdMs = STALE_THRESHOLD_MS, cwd) {
27071
+ const agents = await listAgentInstances({ status: ALIVE_STATUSES }, cwd);
27072
+ return agents.map((a) => buildHealthStatus(a, thresholdMs)).filter((s) => s.stale).sort((a, b) => b.heartbeatAgeMs - a.heartbeatAgeMs);
27073
+ }
27074
+ async function detectCrashedAgents(thresholdMs = STALE_THRESHOLD_MS, cwd) {
27075
+ const activeAgents = await listAgentInstances({ status: "active" }, cwd);
27076
+ const cutoff = new Date(Date.now() - thresholdMs).toISOString();
27077
+ const crashed = [];
27078
+ for (const agent of activeAgents) {
27079
+ if (agent.lastHeartbeat < cutoff) {
27080
+ const updated = await markCrashed(
27081
+ agent.id,
27082
+ `Heartbeat timeout \u2014 no heartbeat for >${Math.round(thresholdMs / 1e3)}s`,
27083
+ cwd
27084
+ );
27085
+ if (updated) {
27086
+ crashed.push(updated);
27087
+ }
27088
+ }
27089
+ }
27090
+ crashed.sort((a, b) => {
27091
+ const aHb = a.lastHeartbeat ?? "";
27092
+ const bHb = b.lastHeartbeat ?? "";
27093
+ return aHb < bHb ? -1 : aHb > bHb ? 1 : 0;
27094
+ });
27095
+ return crashed;
27096
+ }
27097
+ function buildHealthStatus(agent, thresholdMs) {
27098
+ const lastHeartbeatMs = new Date(agent.lastHeartbeat).getTime();
27099
+ const heartbeatAgeMs = Date.now() - lastHeartbeatMs;
27100
+ const stale = ALIVE_STATUSES.includes(agent.status) ? heartbeatAgeMs > thresholdMs : false;
27101
+ const healthy = !stale && ALIVE_STATUSES.includes(agent.status);
27102
+ return {
27103
+ agentId: agent.id,
27104
+ status: agent.status,
27105
+ lastHeartbeat: agent.lastHeartbeat,
27106
+ heartbeatAgeMs,
27107
+ healthy,
27108
+ stale,
27109
+ thresholdMs
27110
+ };
27111
+ }
27112
+
26926
27113
  // packages/core/src/agents/index.ts
26927
27114
  init_registry2();
26928
27115
 
@@ -39185,6 +39372,7 @@ __export(intelligence_exports, {
39185
39372
  gatherLearningContext: () => gatherLearningContext,
39186
39373
  matchPatterns: () => matchPatterns,
39187
39374
  predictAndStore: () => predictAndStore,
39375
+ predictImpact: () => predictImpact,
39188
39376
  predictValidationOutcome: () => predictValidationOutcome,
39189
39377
  scoreVerificationConfidence: () => scoreVerificationConfidence,
39190
39378
  storeDetectedPattern: () => storeDetectedPattern,
@@ -40374,6 +40562,116 @@ function generateRecommendation2(changeType, affectedCount, cascadeDepth, taskId
40374
40562
  return `${severity} impact: reprioritizing ${taskId} may reorder ${affectedCount} downstream task(s) across ${cascadeDepth} level(s) of dependencies.`;
40375
40563
  }
40376
40564
  }
40565
+ function scoreTaskMatch(change, task) {
40566
+ const STOP_WORDS3 = /* @__PURE__ */ new Set([
40567
+ "a",
40568
+ "an",
40569
+ "the",
40570
+ "and",
40571
+ "or",
40572
+ "in",
40573
+ "of",
40574
+ "to",
40575
+ "for",
40576
+ "with",
40577
+ "on",
40578
+ "at",
40579
+ "by",
40580
+ "is",
40581
+ "it",
40582
+ "be",
40583
+ "as",
40584
+ "if",
40585
+ "do",
40586
+ "not"
40587
+ ]);
40588
+ const tokenise = (text3) => text3.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS3.has(t));
40589
+ const changeTokens = new Set(tokenise(change));
40590
+ if (changeTokens.size === 0) return 0;
40591
+ const taskText = `${task.title ?? ""} ${task.description ?? ""}`;
40592
+ const taskTokens = new Set(tokenise(taskText));
40593
+ let matches = 0;
40594
+ for (const token of changeTokens) {
40595
+ if (taskTokens.has(token)) matches++;
40596
+ }
40597
+ return matches / changeTokens.size;
40598
+ }
40599
+ async function predictImpact(change, cwd, accessor, matchLimit = 5) {
40600
+ const acc = accessor ?? await getAccessor(cwd);
40601
+ const tasks2 = await loadAllTasks2(acc);
40602
+ const taskMap = new Map(tasks2.map((t) => [t.id, t]));
40603
+ const dependentsMap = buildDependentsMap(tasks2);
40604
+ const scored = tasks2.map((t) => ({ task: t, score: scoreTaskMatch(change, t) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score);
40605
+ const seeds = scored.slice(0, matchLimit).map(({ task }) => task);
40606
+ if (seeds.length === 0) {
40607
+ return {
40608
+ change,
40609
+ matchedTasks: [],
40610
+ affectedTasks: [],
40611
+ totalAffected: 0,
40612
+ summary: `No tasks matched the change description "${change}".`
40613
+ };
40614
+ }
40615
+ const directMatchIds = new Set(seeds.map((t) => t.id));
40616
+ const exposureMap = /* @__PURE__ */ new Map();
40617
+ for (const id of directMatchIds) {
40618
+ exposureMap.set(id, "direct");
40619
+ }
40620
+ for (const seed of seeds) {
40621
+ const transitive = collectTransitiveDependents(seed.id, dependentsMap);
40622
+ for (const depId of transitive) {
40623
+ if (!exposureMap.has(depId)) {
40624
+ const isDirectDependent = (dependentsMap.get(seed.id) ?? /* @__PURE__ */ new Set()).has(depId);
40625
+ exposureMap.set(depId, isDirectDependent ? "dependent" : "transitive");
40626
+ }
40627
+ }
40628
+ }
40629
+ const EXPOSURE_ORDER = {
40630
+ direct: 0,
40631
+ dependent: 1,
40632
+ transitive: 2
40633
+ };
40634
+ const affectedTasks = [];
40635
+ for (const [id, exposure] of exposureMap) {
40636
+ const task = taskMap.get(id);
40637
+ if (!task) continue;
40638
+ const downstreamTransitive = collectTransitiveDependents(id, dependentsMap);
40639
+ const downstreamCount = downstreamTransitive.size;
40640
+ let reason;
40641
+ if (exposure === "direct") {
40642
+ reason = `Task title/description matched "${change}".`;
40643
+ } else if (exposure === "dependent") {
40644
+ const seedNames = seeds.filter((s) => (dependentsMap.get(s.id) ?? /* @__PURE__ */ new Set()).has(id)).map((s) => s.id).join(", ");
40645
+ reason = `Directly depends on matched task(s): ${seedNames}.`;
40646
+ } else {
40647
+ reason = "Downstream of a matched task via transitive dependency chain.";
40648
+ }
40649
+ affectedTasks.push({
40650
+ id,
40651
+ title: task.title,
40652
+ status: task.status,
40653
+ priority: task.priority,
40654
+ exposure,
40655
+ downstreamCount,
40656
+ reason
40657
+ });
40658
+ }
40659
+ affectedTasks.sort((a, b) => {
40660
+ const expDiff = EXPOSURE_ORDER[a.exposure] - EXPOSURE_ORDER[b.exposure];
40661
+ if (expDiff !== 0) return expDiff;
40662
+ return b.downstreamCount - a.downstreamCount;
40663
+ });
40664
+ const matchedTasks = affectedTasks.filter((t) => t.exposure === "direct");
40665
+ const totalAffected = affectedTasks.length;
40666
+ const summary = matchedTasks.length === 0 ? `No tasks matched "${change}".` : `${matchedTasks.length} task(s) matched "${change}"; ${totalAffected} total task(s) affected (including downstream).`;
40667
+ return {
40668
+ change,
40669
+ matchedTasks,
40670
+ affectedTasks,
40671
+ totalAffected,
40672
+ summary
40673
+ };
40674
+ }
40377
40675
 
40378
40676
  // packages/core/src/intelligence/patterns.ts
40379
40677
  import { randomBytes as randomBytes7 } from "node:crypto";
@@ -40889,13 +41187,13 @@ function extractYamlArray(content, field) {
40889
41187
  }
40890
41188
  const lines = content.split("\n");
40891
41189
  const items = [];
40892
- let inArray5 = false;
41190
+ let inArray6 = false;
40893
41191
  for (const line2 of lines) {
40894
41192
  if (line2.match(new RegExp(`^${field}:`))) {
40895
- inArray5 = true;
41193
+ inArray6 = true;
40896
41194
  continue;
40897
41195
  }
40898
- if (inArray5) {
41196
+ if (inArray6) {
40899
41197
  const itemMatch = line2.match(/^\s+-\s+["']?(.+?)["']?\s*$/);
40900
41198
  if (itemMatch) {
40901
41199
  items.push(itemMatch[1].trim());
@@ -41113,6 +41411,60 @@ function addIssue(params) {
41113
41411
  };
41114
41412
  }
41115
41413
 
41414
+ // packages/core/src/lib/index.ts
41415
+ var lib_exports = {};
41416
+ __export(lib_exports, {
41417
+ computeDelay: () => computeDelay,
41418
+ withRetry: () => withRetry2
41419
+ });
41420
+
41421
+ // packages/core/src/lib/retry.ts
41422
+ async function withRetry2(fn, options) {
41423
+ const maxAttempts = options?.maxAttempts ?? 3;
41424
+ const baseDelayMs = options?.baseDelayMs ?? 2e3;
41425
+ const maxDelayMs = options?.maxDelayMs ?? 3e4;
41426
+ const retryableErrors = options?.retryableErrors;
41427
+ let lastError;
41428
+ let totalDelayMs = 0;
41429
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
41430
+ try {
41431
+ return await fn();
41432
+ } catch (err) {
41433
+ lastError = err;
41434
+ const isLastAttempt = attempt === maxAttempts;
41435
+ if (isLastAttempt) break;
41436
+ if (retryableErrors !== void 0 && !isRetryable(err, retryableErrors)) break;
41437
+ const delay = computeDelay(attempt, baseDelayMs, maxDelayMs);
41438
+ totalDelayMs += delay;
41439
+ await sleep2(delay);
41440
+ }
41441
+ }
41442
+ const context = { attempts: maxAttempts, totalDelayMs };
41443
+ augmentError(lastError, context);
41444
+ throw lastError;
41445
+ }
41446
+ function computeDelay(attempt, baseDelayMs, maxDelayMs) {
41447
+ const exponential = baseDelayMs * 2 ** (attempt - 1);
41448
+ return Math.min(exponential, maxDelayMs);
41449
+ }
41450
+ function isRetryable(err, predicates) {
41451
+ const message = err instanceof Error ? err.message : String(err);
41452
+ return predicates.some((predicate) => {
41453
+ if (predicate instanceof RegExp) return predicate.test(message);
41454
+ return predicate(err);
41455
+ });
41456
+ }
41457
+ function augmentError(err, context) {
41458
+ if (err instanceof Error) {
41459
+ const mutableErr = err;
41460
+ mutableErr.attempts = context.attempts;
41461
+ mutableErr.totalDelayMs = context.totalDelayMs;
41462
+ }
41463
+ }
41464
+ function sleep2(ms) {
41465
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
41466
+ }
41467
+
41116
41468
  // packages/core/src/lifecycle/index.ts
41117
41469
  var lifecycle_exports = {};
41118
41470
  __export(lifecycle_exports, {
@@ -41929,12 +42281,12 @@ async function getEnforcementMode(cwd) {
41929
42281
  }
41930
42282
  async function getLifecycleStatus(epicId, cwd) {
41931
42283
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
41932
- const { eq: eq11 } = await import("drizzle-orm");
42284
+ const { eq: eq12 } = await import("drizzle-orm");
41933
42285
  const db = await getDb3(cwd);
41934
42286
  const pipelineResult = await db.select({
41935
42287
  pipeline: lifecyclePipelines,
41936
42288
  task: tasks
41937
- }).from(lifecyclePipelines).innerJoin(tasks, eq11(lifecyclePipelines.taskId, tasks.id)).where(eq11(lifecyclePipelines.taskId, epicId)).limit(1);
42289
+ }).from(lifecyclePipelines).innerJoin(tasks, eq12(lifecyclePipelines.taskId, tasks.id)).where(eq12(lifecyclePipelines.taskId, epicId)).limit(1);
41938
42290
  if (pipelineResult.length === 0) {
41939
42291
  return {
41940
42292
  epicId,
@@ -41947,7 +42299,7 @@ async function getLifecycleStatus(epicId, cwd) {
41947
42299
  }
41948
42300
  const task = pipelineResult[0].task;
41949
42301
  const pipelineId = `pipeline-${epicId}`;
41950
- const stageRows = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.pipelineId, pipelineId)).orderBy(lifecycleStages.sequence);
42302
+ const stageRows = await db.select().from(lifecycleStages).where(eq12(lifecycleStages.pipelineId, pipelineId)).orderBy(lifecycleStages.sequence);
41951
42303
  const stageDataMap = /* @__PURE__ */ new Map();
41952
42304
  for (const row of stageRows) {
41953
42305
  let parsedChain;
@@ -42016,10 +42368,10 @@ async function getLifecycleStatus(epicId, cwd) {
42016
42368
  }
42017
42369
  async function getLifecycleHistory(epicId, cwd) {
42018
42370
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
42019
- const { eq: eq11 } = await import("drizzle-orm");
42371
+ const { eq: eq12 } = await import("drizzle-orm");
42020
42372
  const db = await getDb3(cwd);
42021
42373
  const pipelineId = `pipeline-${epicId}`;
42022
- const stages = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.pipelineId, pipelineId));
42374
+ const stages = await db.select().from(lifecycleStages).where(eq12(lifecycleStages.pipelineId, pipelineId));
42023
42375
  if (stages.length === 0) {
42024
42376
  return { epicId, history: [] };
42025
42377
  }
@@ -42049,7 +42401,7 @@ async function getLifecycleHistory(epicId, cwd) {
42049
42401
  }
42050
42402
  const stageIds = stages.map((s) => s.id);
42051
42403
  if (stageIds.length > 0) {
42052
- const gateResults = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.stageId, stageIds[0]));
42404
+ const gateResults = await db.select().from(lifecycleGateResults).where(eq12(lifecycleGateResults.stageId, stageIds[0]));
42053
42405
  for (const gate of gateResults) {
42054
42406
  const stageName = stageIdToName.get(gate.stageId);
42055
42407
  if (stageName) {
@@ -42062,7 +42414,7 @@ async function getLifecycleHistory(epicId, cwd) {
42062
42414
  }
42063
42415
  }
42064
42416
  for (let i = 1; i < stageIds.length; i++) {
42065
- const additionalGates = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.stageId, stageIds[i]));
42417
+ const additionalGates = await db.select().from(lifecycleGateResults).where(eq12(lifecycleGateResults.stageId, stageIds[i]));
42066
42418
  for (const gate of additionalGates) {
42067
42419
  const stageName = stageIdToName.get(gate.stageId);
42068
42420
  if (stageName) {
@@ -42081,16 +42433,16 @@ async function getLifecycleHistory(epicId, cwd) {
42081
42433
  }
42082
42434
  async function getLifecycleGates(epicId, cwd) {
42083
42435
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
42084
- const { eq: eq11 } = await import("drizzle-orm");
42436
+ const { eq: eq12 } = await import("drizzle-orm");
42085
42437
  const db = await getDb3(cwd);
42086
42438
  const pipelineId = `pipeline-${epicId}`;
42087
- const stages = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.pipelineId, pipelineId));
42439
+ const stages = await db.select().from(lifecycleStages).where(eq12(lifecycleStages.pipelineId, pipelineId));
42088
42440
  if (stages.length === 0) {
42089
42441
  return {};
42090
42442
  }
42091
42443
  const gates = {};
42092
42444
  for (const stage of stages) {
42093
- const gateRows = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.stageId, stage.id));
42445
+ const gateRows = await db.select().from(lifecycleGateResults).where(eq12(lifecycleGateResults.stageId, stage.id));
42094
42446
  if (gateRows.length > 0) {
42095
42447
  gates[stage.stageName] = {};
42096
42448
  for (const gateRow of gateRows) {
@@ -42154,7 +42506,7 @@ async function checkStagePrerequisites(epicId, targetStage, cwd) {
42154
42506
  }
42155
42507
  async function ensureLifecycleContext(epicId, stageName, cwd, options) {
42156
42508
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
42157
- const { eq: eq11 } = await import("drizzle-orm");
42509
+ const { eq: eq12 } = await import("drizzle-orm");
42158
42510
  const db = await getDb3(cwd);
42159
42511
  const pipelineId = `pipeline-${epicId}`;
42160
42512
  const stageId = `stage-${epicId}-${stageName}`;
@@ -42162,7 +42514,7 @@ async function ensureLifecycleContext(epicId, stageName, cwd, options) {
42162
42514
  getNativeDb2().prepare(
42163
42515
  `INSERT OR IGNORE INTO tasks (id, title, status, priority, created_at) VALUES (?, ?, 'pending', 'medium', datetime('now'))`
42164
42516
  ).run(epicId, `Task ${epicId}`);
42165
- const existingPipeline = await db.select().from(lifecyclePipelines).where(eq11(lifecyclePipelines.id, pipelineId)).limit(1).all();
42517
+ const existingPipeline = await db.select().from(lifecyclePipelines).where(eq12(lifecyclePipelines.id, pipelineId)).limit(1).all();
42166
42518
  if (existingPipeline.length === 0) {
42167
42519
  await db.insert(lifecyclePipelines).values({
42168
42520
  id: pipelineId,
@@ -42172,7 +42524,7 @@ async function ensureLifecycleContext(epicId, stageName, cwd, options) {
42172
42524
  startedAt: options.now
42173
42525
  }).run();
42174
42526
  }
42175
- const existingStage = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.id, stageId)).limit(1).all();
42527
+ const existingStage = await db.select().from(lifecycleStages).where(eq12(lifecycleStages.id, stageId)).limit(1).all();
42176
42528
  if (existingStage.length === 0) {
42177
42529
  const sequence = isValidStage(stageName) ? STAGE_ORDER[stageName] : 0;
42178
42530
  await db.insert(lifecycleStages).values({
@@ -42185,7 +42537,7 @@ async function ensureLifecycleContext(epicId, stageName, cwd, options) {
42185
42537
  }).run();
42186
42538
  }
42187
42539
  if (options.updateCurrentStage) {
42188
- await db.update(lifecyclePipelines).set({ currentStageId: stageId }).where(eq11(lifecyclePipelines.id, pipelineId)).run();
42540
+ await db.update(lifecyclePipelines).set({ currentStageId: stageId }).where(eq12(lifecyclePipelines.id, pipelineId)).run();
42189
42541
  }
42190
42542
  return { db, pipelineId, stageId };
42191
42543
  }
@@ -42200,7 +42552,7 @@ async function recordStageProgress(epicId, stage, status, notes, cwd) {
42200
42552
  `Invalid status: ${status}. Valid: ${validStatuses.join(", ")}`
42201
42553
  );
42202
42554
  }
42203
- const { eq: eq11 } = await import("drizzle-orm");
42555
+ const { eq: eq12 } = await import("drizzle-orm");
42204
42556
  const now = (/* @__PURE__ */ new Date()).toISOString();
42205
42557
  const stageName = stage;
42206
42558
  const { db, stageId, pipelineId } = await ensureLifecycleContext(epicId, stage, cwd, {
@@ -42216,7 +42568,7 @@ async function recordStageProgress(epicId, stage, status, notes, cwd) {
42216
42568
  status,
42217
42569
  related: artifact.related
42218
42570
  };
42219
- const existingStage = await db.select().from(lifecycleStages).where(eq11(lifecycleStages.id, stageId)).limit(1).all();
42571
+ const existingStage = await db.select().from(lifecycleStages).where(eq12(lifecycleStages.id, stageId)).limit(1).all();
42220
42572
  const sequence = STAGE_ORDER[stage];
42221
42573
  const stageValues = {
42222
42574
  status,
@@ -42243,7 +42595,7 @@ async function recordStageProgress(epicId, stage, status, notes, cwd) {
42243
42595
  provenanceChainJson: JSON.stringify(provenanceChain)
42244
42596
  }).run();
42245
42597
  } else {
42246
- await db.update(lifecycleStages).set(stageValues).where(eq11(lifecycleStages.id, stageId)).run();
42598
+ await db.update(lifecycleStages).set(stageValues).where(eq12(lifecycleStages.id, stageId)).run();
42247
42599
  }
42248
42600
  if (status === "completed") {
42249
42601
  await linkProvenance(epicId, stageName, artifact.absolutePath, cwd);
@@ -42263,7 +42615,7 @@ async function resetStage(epicId, stage, reason, cwd) {
42263
42615
  if (!PIPELINE_STAGES.includes(stage)) {
42264
42616
  throw new CleoError(2 /* INVALID_INPUT */, `Invalid stage: ${stage}`);
42265
42617
  }
42266
- const { eq: eq11 } = await import("drizzle-orm");
42618
+ const { eq: eq12 } = await import("drizzle-orm");
42267
42619
  const now = (/* @__PURE__ */ new Date()).toISOString();
42268
42620
  const { db, stageId } = await ensureLifecycleContext(epicId, stage, cwd, {
42269
42621
  now,
@@ -42276,11 +42628,11 @@ async function resetStage(epicId, stage, reason, cwd) {
42276
42628
  skippedAt: null,
42277
42629
  skipReason: null,
42278
42630
  notesJson: JSON.stringify([`Reset: ${reason}`])
42279
- }).where(eq11(lifecycleStages.id, stageId)).run();
42631
+ }).where(eq12(lifecycleStages.id, stageId)).run();
42280
42632
  return { epicId, stage, reason };
42281
42633
  }
42282
42634
  async function passGate(epicId, gateName, agent, notes, cwd) {
42283
- const { eq: eq11 } = await import("drizzle-orm");
42635
+ const { eq: eq12 } = await import("drizzle-orm");
42284
42636
  const now = (/* @__PURE__ */ new Date()).toISOString();
42285
42637
  const stageName = gateName.split("-")[0];
42286
42638
  const gateId = `gate-${epicId}-${stageName}-${gateName}`;
@@ -42289,7 +42641,7 @@ async function passGate(epicId, gateName, agent, notes, cwd) {
42289
42641
  stageStatusOnCreate: "in_progress",
42290
42642
  updateCurrentStage: true
42291
42643
  });
42292
- const existingGate = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.id, gateId)).limit(1).all();
42644
+ const existingGate = await db.select().from(lifecycleGateResults).where(eq12(lifecycleGateResults.id, gateId)).limit(1).all();
42293
42645
  const gateValues = {
42294
42646
  id: gateId,
42295
42647
  stageId,
@@ -42301,14 +42653,14 @@ async function passGate(epicId, gateName, agent, notes, cwd) {
42301
42653
  reason: null
42302
42654
  };
42303
42655
  if (existingGate.length > 0) {
42304
- await db.update(lifecycleGateResults).set(gateValues).where(eq11(lifecycleGateResults.id, gateId)).run();
42656
+ await db.update(lifecycleGateResults).set(gateValues).where(eq12(lifecycleGateResults.id, gateId)).run();
42305
42657
  } else {
42306
42658
  await db.insert(lifecycleGateResults).values(gateValues).run();
42307
42659
  }
42308
42660
  return { epicId, gateName, timestamp: now };
42309
42661
  }
42310
42662
  async function failGate(epicId, gateName, reason, cwd) {
42311
- const { eq: eq11 } = await import("drizzle-orm");
42663
+ const { eq: eq12 } = await import("drizzle-orm");
42312
42664
  const now = (/* @__PURE__ */ new Date()).toISOString();
42313
42665
  const stageName = gateName.split("-")[0];
42314
42666
  const gateId = `gate-${epicId}-${stageName}-${gateName}`;
@@ -42317,7 +42669,7 @@ async function failGate(epicId, gateName, reason, cwd) {
42317
42669
  stageStatusOnCreate: "in_progress",
42318
42670
  updateCurrentStage: true
42319
42671
  });
42320
- const existingGate = await db.select().from(lifecycleGateResults).where(eq11(lifecycleGateResults.id, gateId)).limit(1).all();
42672
+ const existingGate = await db.select().from(lifecycleGateResults).where(eq12(lifecycleGateResults.id, gateId)).limit(1).all();
42321
42673
  const gateValues = {
42322
42674
  id: gateId,
42323
42675
  stageId,
@@ -42329,7 +42681,7 @@ async function failGate(epicId, gateName, reason, cwd) {
42329
42681
  reason: reason ?? null
42330
42682
  };
42331
42683
  if (existingGate.length > 0) {
42332
- await db.update(lifecycleGateResults).set(gateValues).where(eq11(lifecycleGateResults.id, gateId)).run();
42684
+ await db.update(lifecycleGateResults).set(gateValues).where(eq12(lifecycleGateResults.id, gateId)).run();
42333
42685
  } else {
42334
42686
  await db.insert(lifecycleGateResults).values(gateValues).run();
42335
42687
  }
@@ -46463,6 +46815,7 @@ init_registry3();
46463
46815
  // packages/core/src/nexus/sharing/index.ts
46464
46816
  init_config();
46465
46817
  init_paths();
46818
+ init_git_checkpoint();
46466
46819
  import { existsSync as existsSync54, readdirSync as readdirSync22, statSync as statSync15 } from "node:fs";
46467
46820
  import { readFile as readFile10, writeFile as writeFile9 } from "node:fs/promises";
46468
46821
  import { join as join61, relative as relative5 } from "node:path";
@@ -46509,6 +46862,30 @@ function collectCleoFiles(cleoDir) {
46509
46862
  walk(cleoDir);
46510
46863
  return files.sort();
46511
46864
  }
46865
+ async function getCleoGitRemotes(cleoDir) {
46866
+ const result = await cleoGitCommand(["remote"], cleoDir);
46867
+ if (!result.success || !result.stdout) return [];
46868
+ return result.stdout.split("\n").map((r) => r.trim()).filter(Boolean);
46869
+ }
46870
+ async function hasCleoGitPendingChanges(cleoDir) {
46871
+ const result = await cleoGitCommand(["status", "--porcelain"], cleoDir);
46872
+ if (!result.success) return false;
46873
+ return result.stdout.length > 0;
46874
+ }
46875
+ async function getLastSyncTimestamp(cleoDir) {
46876
+ const result = await cleoGitCommand(["reflog", "--format=%gs %ci", "HEAD"], cleoDir);
46877
+ if (!result.success || !result.stdout) return null;
46878
+ for (const line2 of result.stdout.split("\n")) {
46879
+ const trimmed = line2.trim();
46880
+ if (/^(fetch|push|pull)\b/i.test(trimmed)) {
46881
+ const isoMatch = trimmed.match(/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [+-]\d{4})$/);
46882
+ if (isoMatch?.[1]) {
46883
+ return new Date(isoMatch[1]).toISOString();
46884
+ }
46885
+ }
46886
+ }
46887
+ return null;
46888
+ }
46512
46889
  async function getSharingStatus(cwd) {
46513
46890
  const config2 = await loadConfig(cwd);
46514
46891
  const sharing = config2.sharing;
@@ -46525,12 +46902,27 @@ async function getSharingStatus(cwd) {
46525
46902
  ignored.push(file2);
46526
46903
  }
46527
46904
  }
46905
+ const hasGit = isCleoGitInitialized(cleoDir);
46906
+ let remotes = [];
46907
+ let pendingChanges = false;
46908
+ let lastSync = null;
46909
+ if (hasGit) {
46910
+ [remotes, pendingChanges, lastSync] = await Promise.all([
46911
+ getCleoGitRemotes(cleoDir),
46912
+ hasCleoGitPendingChanges(cleoDir),
46913
+ getLastSyncTimestamp(cleoDir)
46914
+ ]);
46915
+ }
46528
46916
  return {
46529
46917
  mode: sharing.mode,
46530
46918
  allowlist: sharing.commitAllowlist,
46531
46919
  denylist: sharing.denylist,
46532
46920
  tracked,
46533
- ignored
46921
+ ignored,
46922
+ hasGit,
46923
+ remotes,
46924
+ pendingChanges,
46925
+ lastSync
46534
46926
  };
46535
46927
  }
46536
46928
  function generateGitignoreEntries(sharing) {
@@ -46585,25 +46977,25 @@ init_logger();
46585
46977
  init_sqlite2();
46586
46978
  init_tasks_schema();
46587
46979
  import { randomUUID as randomUUID4 } from "node:crypto";
46588
- import { and as and6, eq as eq9 } from "drizzle-orm";
46980
+ import { and as and7, eq as eq10 } from "drizzle-orm";
46589
46981
  async function getLinksByProvider(providerId, cwd) {
46590
46982
  const db = await getDb(cwd);
46591
- const rows = await db.select().from(externalTaskLinks).where(eq9(externalTaskLinks.providerId, providerId));
46983
+ const rows = await db.select().from(externalTaskLinks).where(eq10(externalTaskLinks.providerId, providerId));
46592
46984
  return rows.map(rowToLink);
46593
46985
  }
46594
46986
  async function getLinkByExternalId(providerId, externalId, cwd) {
46595
46987
  const db = await getDb(cwd);
46596
46988
  const rows = await db.select().from(externalTaskLinks).where(
46597
- and6(
46598
- eq9(externalTaskLinks.providerId, providerId),
46599
- eq9(externalTaskLinks.externalId, externalId)
46989
+ and7(
46990
+ eq10(externalTaskLinks.providerId, providerId),
46991
+ eq10(externalTaskLinks.externalId, externalId)
46600
46992
  )
46601
46993
  );
46602
46994
  return rows.length > 0 ? rowToLink(rows[0]) : null;
46603
46995
  }
46604
46996
  async function getLinksByTaskId(taskId, cwd) {
46605
46997
  const db = await getDb(cwd);
46606
- const rows = await db.select().from(externalTaskLinks).where(eq9(externalTaskLinks.taskId, taskId));
46998
+ const rows = await db.select().from(externalTaskLinks).where(eq10(externalTaskLinks.taskId, taskId));
46607
46999
  return rows.map(rowToLink);
46608
47000
  }
46609
47001
  async function createLink(params, cwd) {
@@ -46647,11 +47039,11 @@ async function touchLink(linkId, updates, cwd) {
46647
47039
  if (updates?.metadata !== void 0) {
46648
47040
  values.metadataJson = JSON.stringify(updates.metadata);
46649
47041
  }
46650
- await db.update(externalTaskLinks).set(values).where(eq9(externalTaskLinks.id, linkId));
47042
+ await db.update(externalTaskLinks).set(values).where(eq10(externalTaskLinks.id, linkId));
46651
47043
  }
46652
47044
  async function removeLinksByProvider(providerId, cwd) {
46653
47045
  const db = await getDb(cwd);
46654
- const result = await db.delete(externalTaskLinks).where(eq9(externalTaskLinks.providerId, providerId));
47046
+ const result = await db.delete(externalTaskLinks).where(eq10(externalTaskLinks.providerId, providerId));
46655
47047
  return Number(result.changes);
46656
47048
  }
46657
47049
  function rowToLink(row) {
@@ -49703,7 +50095,7 @@ import { execFileSync as execFileSync7 } from "node:child_process";
49703
50095
  import { existsSync as existsSync63, renameSync as renameSync5 } from "node:fs";
49704
50096
  import { readFile as readFile12 } from "node:fs/promises";
49705
50097
  import { join as join67 } from "node:path";
49706
- import { and as and7, count, desc as desc4, eq as eq10 } from "drizzle-orm";
50098
+ import { and as and8, count, desc as desc4, eq as eq11 } from "drizzle-orm";
49707
50099
  init_paths();
49708
50100
  init_tasks_schema();
49709
50101
 
@@ -50003,7 +50395,7 @@ function rowToManifest(row) {
50003
50395
  }
50004
50396
  async function findLatestPushedVersion(cwd) {
50005
50397
  const db = await getDb2(cwd);
50006
- const rows = await db.select({ version: releaseManifests.version }).from(releaseManifests).where(eq10(releaseManifests.status, "pushed")).orderBy(desc4(releaseManifests.pushedAt)).limit(1).all();
50398
+ const rows = await db.select({ version: releaseManifests.version }).from(releaseManifests).where(eq11(releaseManifests.status, "pushed")).orderBy(desc4(releaseManifests.pushedAt)).limit(1).all();
50007
50399
  return rows[0]?.version;
50008
50400
  }
50009
50401
  async function prepareRelease(version2, tasks2, notes, loadTasksFn, cwd) {
@@ -50015,7 +50407,7 @@ async function prepareRelease(version2, tasks2, notes, loadTasksFn, cwd) {
50015
50407
  }
50016
50408
  const normalizedVersion = normalizeVersion(version2);
50017
50409
  const db = await getDb2(cwd);
50018
- const existing = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50410
+ const existing = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50019
50411
  if (existing.length > 0) {
50020
50412
  throw new Error(`Release ${normalizedVersion} already exists (status: ${existing[0].status})`);
50021
50413
  }
@@ -50055,7 +50447,7 @@ async function generateReleaseChangelog(version2, loadTasksFn, cwd) {
50055
50447
  }
50056
50448
  const normalizedVersion = normalizeVersion(version2);
50057
50449
  const db = await getDb2(cwd);
50058
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50450
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50059
50451
  if (rows.length === 0) {
50060
50452
  throw new Error(`Release ${normalizedVersion} not found`);
50061
50453
  }
@@ -50192,7 +50584,7 @@ async function generateReleaseChangelog(version2, loadTasksFn, cwd) {
50192
50584
  sections.push("");
50193
50585
  }
50194
50586
  const changelog = sections.join("\n");
50195
- await db.update(releaseManifests).set({ changelog }).where(eq10(releaseManifests.version, normalizedVersion)).run();
50587
+ await db.update(releaseManifests).set({ changelog }).where(eq11(releaseManifests.version, normalizedVersion)).run();
50196
50588
  const changelogPath = join67(cwd ?? process.cwd(), "CHANGELOG.md");
50197
50589
  let existingChangelogContent = "";
50198
50590
  try {
@@ -50230,8 +50622,8 @@ async function listManifestReleases(optionsOrCwd, cwd) {
50230
50622
  const db = await getDb2(effectiveCwd);
50231
50623
  const totalRow = await db.select({ count: count() }).from(releaseManifests).get();
50232
50624
  const total = totalRow?.count ?? 0;
50233
- const conditions = options.status ? [eq10(releaseManifests.status, options.status)] : [];
50234
- const whereClause = conditions.length > 0 ? and7(...conditions) : void 0;
50625
+ const conditions = options.status ? [eq11(releaseManifests.status, options.status)] : [];
50626
+ const whereClause = conditions.length > 0 ? and8(...conditions) : void 0;
50235
50627
  const filteredRow = await db.select({ count: count() }).from(releaseManifests).where(whereClause).get();
50236
50628
  const filtered = filteredRow?.count ?? 0;
50237
50629
  let query = db.select().from(releaseManifests).where(whereClause).orderBy(desc4(releaseManifests.createdAt));
@@ -50262,7 +50654,7 @@ async function showManifestRelease(version2, cwd) {
50262
50654
  }
50263
50655
  const normalizedVersion = normalizeVersion(version2);
50264
50656
  const db = await getDb2(cwd);
50265
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50657
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50266
50658
  if (rows.length === 0) {
50267
50659
  throw new Error(`Release ${normalizedVersion} not found`);
50268
50660
  }
@@ -50274,7 +50666,7 @@ async function commitRelease(version2, cwd) {
50274
50666
  }
50275
50667
  const normalizedVersion = normalizeVersion(version2);
50276
50668
  const db = await getDb2(cwd);
50277
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50669
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50278
50670
  if (rows.length === 0) {
50279
50671
  throw new Error(`Release ${normalizedVersion} not found`);
50280
50672
  }
@@ -50284,7 +50676,7 @@ async function commitRelease(version2, cwd) {
50284
50676
  );
50285
50677
  }
50286
50678
  const committedAt = (/* @__PURE__ */ new Date()).toISOString();
50287
- await db.update(releaseManifests).set({ status: "committed", committedAt }).where(eq10(releaseManifests.version, normalizedVersion)).run();
50679
+ await db.update(releaseManifests).set({ status: "committed", committedAt }).where(eq11(releaseManifests.version, normalizedVersion)).run();
50288
50680
  return { version: normalizedVersion, status: "committed", committedAt };
50289
50681
  }
50290
50682
  async function tagRelease(version2, cwd) {
@@ -50293,12 +50685,12 @@ async function tagRelease(version2, cwd) {
50293
50685
  }
50294
50686
  const normalizedVersion = normalizeVersion(version2);
50295
50687
  const db = await getDb2(cwd);
50296
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50688
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50297
50689
  if (rows.length === 0) {
50298
50690
  throw new Error(`Release ${normalizedVersion} not found`);
50299
50691
  }
50300
50692
  const taggedAt = (/* @__PURE__ */ new Date()).toISOString();
50301
- await db.update(releaseManifests).set({ status: "tagged", taggedAt }).where(eq10(releaseManifests.version, normalizedVersion)).run();
50693
+ await db.update(releaseManifests).set({ status: "tagged", taggedAt }).where(eq11(releaseManifests.version, normalizedVersion)).run();
50302
50694
  return { version: normalizedVersion, status: "tagged", taggedAt };
50303
50695
  }
50304
50696
  async function runReleaseGates(version2, loadTasksFn, cwd, opts) {
@@ -50307,7 +50699,7 @@ async function runReleaseGates(version2, loadTasksFn, cwd, opts) {
50307
50699
  }
50308
50700
  const normalizedVersion = normalizeVersion(version2);
50309
50701
  const db = await getDb2(cwd);
50310
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50702
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50311
50703
  if (rows.length === 0) {
50312
50704
  throw new Error(`Release ${normalizedVersion} not found`);
50313
50705
  }
@@ -50455,7 +50847,7 @@ async function cancelRelease(version2, projectRoot) {
50455
50847
  }
50456
50848
  const normalizedVersion = normalizeVersion(version2);
50457
50849
  const db = await getDb2(projectRoot);
50458
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50850
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50459
50851
  if (rows.length === 0) {
50460
50852
  return {
50461
50853
  success: false,
@@ -50472,7 +50864,7 @@ async function cancelRelease(version2, projectRoot) {
50472
50864
  version: normalizedVersion
50473
50865
  };
50474
50866
  }
50475
- await db.delete(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).run();
50867
+ await db.delete(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).run();
50476
50868
  return {
50477
50869
  success: true,
50478
50870
  message: `Release ${normalizedVersion} cancelled and removed`,
@@ -50485,12 +50877,12 @@ async function rollbackRelease(version2, reason, cwd) {
50485
50877
  }
50486
50878
  const normalizedVersion = normalizeVersion(version2);
50487
50879
  const db = await getDb2(cwd);
50488
- const rows = await db.select().from(releaseManifests).where(eq10(releaseManifests.version, normalizedVersion)).limit(1).all();
50880
+ const rows = await db.select().from(releaseManifests).where(eq11(releaseManifests.version, normalizedVersion)).limit(1).all();
50489
50881
  if (rows.length === 0) {
50490
50882
  throw new Error(`Release ${normalizedVersion} not found`);
50491
50883
  }
50492
50884
  const previousStatus = rows[0].status;
50493
- await db.update(releaseManifests).set({ status: "rolled_back" }).where(eq10(releaseManifests.version, normalizedVersion)).run();
50885
+ await db.update(releaseManifests).set({ status: "rolled_back" }).where(eq11(releaseManifests.version, normalizedVersion)).run();
50494
50886
  return {
50495
50887
  version: normalizedVersion,
50496
50888
  previousStatus,
@@ -50600,7 +50992,7 @@ async function markReleasePushed(version2, pushedAt, cwd, provenance) {
50600
50992
  pushedAt,
50601
50993
  ...provenance?.commitSha != null ? { commitSha: provenance.commitSha } : {},
50602
50994
  ...provenance?.gitTag != null ? { gitTag: provenance.gitTag } : {}
50603
- }).where(eq10(releaseManifests.version, normalizedVersion)).run();
50995
+ }).where(eq11(releaseManifests.version, normalizedVersion)).run();
50604
50996
  }
50605
50997
  async function migrateReleasesJsonToSqlite(projectRoot) {
50606
50998
  const releasesPath = join67(getCleoDirAbsolute(projectRoot), "releases.json");
@@ -50620,7 +51012,7 @@ async function migrateReleasesJsonToSqlite(projectRoot) {
50620
51012
  const db = await getDb2(projectRoot);
50621
51013
  let migrated = 0;
50622
51014
  for (const r of raw.releases) {
50623
- const existing = await db.select({ id: releaseManifests.id }).from(releaseManifests).where(eq10(releaseManifests.version, r.version)).limit(1).all();
51015
+ const existing = await db.select({ id: releaseManifests.id }).from(releaseManifests).where(eq11(releaseManifests.version, r.version)).limit(1).all();
50624
51016
  if (existing.length > 0) continue;
50625
51017
  const id = `rel-${r.version.replace(/[^a-z0-9]/gi, "-")}`;
50626
51018
  await db.insert(releaseManifests).values({
@@ -56078,7 +56470,7 @@ async function queryTasks(cwd, since) {
56078
56470
  try {
56079
56471
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
56080
56472
  const { tasks: tasks2 } = await Promise.resolve().then(() => (init_tasks_schema(), tasks_schema_exports));
56081
- const { and: and8, gte: gte3 } = await import("drizzle-orm");
56473
+ const { and: and9, gte: gte3 } = await import("drizzle-orm");
56082
56474
  const db = await getDb3(cwd);
56083
56475
  const conditions = [];
56084
56476
  if (since) {
@@ -56092,7 +56484,7 @@ async function queryTasks(cwd, since) {
56092
56484
  sessionId: tasks2.sessionId,
56093
56485
  completedAt: tasks2.completedAt,
56094
56486
  createdAt: tasks2.createdAt
56095
- }).from(tasks2).where(conditions.length > 0 ? and8(...conditions) : void 0).all();
56487
+ }).from(tasks2).where(conditions.length > 0 ? and9(...conditions) : void 0).all();
56096
56488
  return rows;
56097
56489
  } catch (err) {
56098
56490
  log7.warn({ err }, "Failed to query tasks for workflow telemetry");
@@ -56103,7 +56495,7 @@ async function queryCompletionAuditRows(cwd, since) {
56103
56495
  try {
56104
56496
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
56105
56497
  const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_tasks_schema(), tasks_schema_exports));
56106
- const { and: and8, gte: gte3 } = await import("drizzle-orm");
56498
+ const { and: and9, gte: gte3 } = await import("drizzle-orm");
56107
56499
  const db = await getDb3(cwd);
56108
56500
  const conditions = [];
56109
56501
  if (since) conditions.push(gte3(auditLog2.timestamp, since));
@@ -56115,7 +56507,7 @@ async function queryCompletionAuditRows(cwd, since) {
56115
56507
  afterJson: auditLog2.afterJson,
56116
56508
  operation: auditLog2.operation,
56117
56509
  domain: auditLog2.domain
56118
- }).from(auditLog2).where(conditions.length > 0 ? and8(...conditions) : void 0).orderBy(auditLog2.timestamp).all();
56510
+ }).from(auditLog2).where(conditions.length > 0 ? and9(...conditions) : void 0).orderBy(auditLog2.timestamp).all();
56119
56511
  return allRows.filter((row) => {
56120
56512
  const isComplete = row.action === "task_completed" || row.action === "complete" || row.operation === "complete" && row.domain === "tasks";
56121
56513
  if (!isComplete && row.afterJson) {
@@ -64084,45 +64476,67 @@ async function bootstrapGlobalCleo(options) {
64084
64476
  await installSkillsGlobally(ctx);
64085
64477
  await installAgentDefinitionGlobally(ctx);
64086
64478
  await installProviderAdapters(ctx, options?.packageRoot);
64479
+ await verifyBootstrapHealth(ctx);
64087
64480
  return ctx;
64088
64481
  }
64482
+ async function writeTemplateTo(content, destPath, isDryRun) {
64483
+ if (isDryRun) return false;
64484
+ const { dirname: dirname20 } = await import("node:path");
64485
+ await mkdir17(dirname20(destPath), { recursive: true });
64486
+ await writeFile12(destPath, content);
64487
+ return true;
64488
+ }
64089
64489
  async function ensureGlobalTemplatesBootstrap(ctx, packageRootOverride) {
64090
64490
  const globalTemplatesDir = getCleoTemplatesDir();
64091
64491
  if (!ctx.isDryRun) {
64092
64492
  await mkdir17(globalTemplatesDir, { recursive: true });
64093
64493
  }
64494
+ let templateContent = null;
64094
64495
  try {
64095
64496
  const pkgRoot = packageRootOverride ?? getPackageRoot();
64096
64497
  const templatePath = join104(pkgRoot, "templates", "CLEO-INJECTION.md");
64097
64498
  if (existsSync103(templatePath)) {
64098
- const content = readFileSync77(templatePath, "utf-8");
64099
- const destPath = join104(globalTemplatesDir, "CLEO-INJECTION.md");
64100
- if (!ctx.isDryRun) {
64101
- await writeFile12(destPath, content);
64102
- }
64103
- ctx.created.push(
64104
- `~/.cleo/templates/CLEO-INJECTION.md (${ctx.isDryRun ? "would refresh" : "refreshed"})`
64105
- );
64106
- } else {
64107
- try {
64108
- const { getInjectionTemplateContent: getInjectionTemplateContent2 } = await Promise.resolve().then(() => (init_injection(), injection_exports));
64109
- const content = getInjectionTemplateContent2();
64110
- if (content) {
64111
- const destPath = join104(globalTemplatesDir, "CLEO-INJECTION.md");
64112
- if (!ctx.isDryRun) {
64113
- await writeFile12(destPath, content);
64114
- }
64115
- ctx.created.push(
64116
- `~/.cleo/templates/CLEO-INJECTION.md (${ctx.isDryRun ? "would refresh" : "refreshed"} from embedded)`
64117
- );
64118
- }
64119
- } catch {
64120
- ctx.warnings.push("Could not refresh CLEO-INJECTION.md template");
64121
- }
64499
+ templateContent = readFileSync77(templatePath, "utf-8");
64122
64500
  }
64123
64501
  } catch {
64502
+ }
64503
+ if (!templateContent) {
64504
+ try {
64505
+ const { getInjectionTemplateContent: getInjectionTemplateContent2 } = await Promise.resolve().then(() => (init_injection(), injection_exports));
64506
+ templateContent = getInjectionTemplateContent2() ?? null;
64507
+ } catch {
64508
+ ctx.warnings.push("Could not refresh CLEO-INJECTION.md template");
64509
+ return;
64510
+ }
64511
+ }
64512
+ if (!templateContent) {
64124
64513
  ctx.warnings.push("Could not refresh CLEO-INJECTION.md template");
64514
+ return;
64125
64515
  }
64516
+ const xdgDest = join104(globalTemplatesDir, "CLEO-INJECTION.md");
64517
+ const xdgWritten = await writeTemplateTo(templateContent, xdgDest, ctx.isDryRun);
64518
+ ctx.created.push(
64519
+ `${getCleoTemplatesTildePath()}/CLEO-INJECTION.md (${xdgWritten ? "refreshed" : "would refresh"})`
64520
+ );
64521
+ const home = homedir6();
64522
+ const legacyTemplatesDir = join104(home, ".cleo", "templates");
64523
+ if (legacyTemplatesDir !== globalTemplatesDir && existsSync103(join104(home, ".cleo"))) {
64524
+ const legacyDest = join104(legacyTemplatesDir, "CLEO-INJECTION.md");
64525
+ const legacyWritten = await writeTemplateTo(templateContent, legacyDest, ctx.isDryRun);
64526
+ if (legacyWritten) {
64527
+ ctx.created.push("~/.cleo/templates/CLEO-INJECTION.md (legacy sync)");
64528
+ }
64529
+ }
64530
+ }
64531
+ function sanitizeCaampFile(content) {
64532
+ let cleaned = content.replace(/(<!-- CAAMP:END -->)\s*(<!-- CAAMP:END -->)/g, "$1");
64533
+ cleaned = cleaned.replace(
64534
+ /<!-- CAAMP:END -->\s*[A-Z][A-Za-z-]*\.md\s*(?:<!-- CAAMP:END -->)?/g,
64535
+ "<!-- CAAMP:END -->"
64536
+ );
64537
+ cleaned = cleaned.replace(/^[A-Z][A-Za-z-]*\.md\s*$/gm, "");
64538
+ cleaned = cleaned.replace(/\n{3,}/g, "\n\n");
64539
+ return cleaned.trim() + "\n";
64126
64540
  }
64127
64541
  async function injectAgentsHub(ctx) {
64128
64542
  const globalAgentsDir = getAgentsHome();
@@ -64137,13 +64551,23 @@ async function injectAgentsHub(ctx) {
64137
64551
  /\n?<!-- CLEO:START[^>]*-->[\s\S]*?<!-- CLEO:END -->\n?/g,
64138
64552
  ""
64139
64553
  );
64140
- if (stripped !== content) {
64141
- await writeFile12(globalAgentsMd, stripped, "utf8");
64554
+ const sanitized = sanitizeCaampFile(stripped);
64555
+ if (sanitized !== content) {
64556
+ await writeFile12(globalAgentsMd, sanitized, "utf8");
64557
+ ctx.created.push("~/.agents/AGENTS.md (sanitized CAAMP corruption)");
64142
64558
  }
64143
64559
  }
64144
64560
  const templateRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
64145
64561
  const action = await inject2(globalAgentsMd, templateRef);
64146
64562
  ctx.created.push(`~/.agents/AGENTS.md (${action})`);
64563
+ const postContent = await readFile19(globalAgentsMd, "utf8");
64564
+ const caampBlocks = postContent.match(/<!-- CAAMP:START -->/g);
64565
+ const caampEnds = postContent.match(/<!-- CAAMP:END -->/g);
64566
+ if (caampBlocks && caampEnds && caampBlocks.length !== caampEnds.length) {
64567
+ ctx.warnings.push(
64568
+ `~/.agents/AGENTS.md has mismatched CAAMP markers (${caampBlocks.length} START vs ${caampEnds.length} END)`
64569
+ );
64570
+ }
64147
64571
  } else {
64148
64572
  ctx.created.push("~/.agents/AGENTS.md (would create/update CAAMP block)");
64149
64573
  }
@@ -64277,6 +64701,45 @@ async function installProviderAdapters(ctx, packageRootOverride) {
64277
64701
  );
64278
64702
  }
64279
64703
  }
64704
+ async function verifyBootstrapHealth(ctx) {
64705
+ if (ctx.isDryRun) return;
64706
+ try {
64707
+ const xdgTemplatePath = join104(getCleoTemplatesDir(), "CLEO-INJECTION.md");
64708
+ const agentsMd = join104(getAgentsHome(), "AGENTS.md");
64709
+ if (!existsSync103(xdgTemplatePath)) {
64710
+ ctx.warnings.push("Health: XDG template missing after bootstrap");
64711
+ return;
64712
+ }
64713
+ const xdgContent = await readFile19(xdgTemplatePath, "utf8");
64714
+ const xdgVersion = xdgContent.match(/^Version:\s*(.+)$/m)?.[1]?.trim();
64715
+ const home = homedir6();
64716
+ const legacyTemplatePath = join104(home, ".cleo", "templates", "CLEO-INJECTION.md");
64717
+ if (existsSync103(legacyTemplatePath)) {
64718
+ const legacyContent = await readFile19(legacyTemplatePath, "utf8");
64719
+ const legacyVersion = legacyContent.match(/^Version:\s*(.+)$/m)?.[1]?.trim();
64720
+ if (legacyVersion !== xdgVersion) {
64721
+ ctx.warnings.push(
64722
+ `Health: Legacy template version (${legacyVersion}) != XDG version (${xdgVersion})`
64723
+ );
64724
+ }
64725
+ }
64726
+ if (existsSync103(agentsMd)) {
64727
+ const agentsContent = await readFile19(agentsMd, "utf8");
64728
+ const expectedRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
64729
+ if (!agentsContent.includes(expectedRef)) {
64730
+ ctx.warnings.push(`Health: ~/.agents/AGENTS.md does not reference ${expectedRef}`);
64731
+ }
64732
+ const outsideCaamp = agentsContent.replace(
64733
+ /<!-- CAAMP:START -->[\s\S]*?<!-- CAAMP:END -->/g,
64734
+ ""
64735
+ );
64736
+ if (/[A-Z][A-Za-z-]*\.md/.test(outsideCaamp)) {
64737
+ ctx.warnings.push("Health: ~/.agents/AGENTS.md has orphaned content outside CAAMP blocks");
64738
+ }
64739
+ }
64740
+ } catch {
64741
+ }
64742
+ }
64280
64743
 
64281
64744
  // packages/core/src/cleo.ts
64282
64745
  import path from "node:path";
@@ -64351,7 +64814,10 @@ var Cleo = class _Cleo {
64351
64814
  ),
64352
64815
  complete: (p) => completeTask({ taskId: p.taskId, notes: p.notes }, root, store),
64353
64816
  delete: (p) => deleteTask({ taskId: p.taskId, force: p.force }, root, store),
64354
- archive: (p) => archiveTasks({ before: p?.before, taskIds: p?.taskIds, dryRun: p?.dryRun }, root, store)
64817
+ archive: (p) => archiveTasks({ before: p?.before, taskIds: p?.taskIds, dryRun: p?.dryRun }, root, store),
64818
+ start: (taskId) => startTask(taskId, root, store),
64819
+ stop: () => stopTask(root, store),
64820
+ current: () => currentTask(root, store)
64355
64821
  };
64356
64822
  }
64357
64823
  // === Sessions ===
@@ -64359,7 +64825,11 @@ var Cleo = class _Cleo {
64359
64825
  const root = this.projectRoot;
64360
64826
  const store = this._store ?? void 0;
64361
64827
  return {
64362
- start: (p) => startSession({ name: p.name, scope: p.scope, agent: p.agent }, root, store),
64828
+ start: (p) => startSession(
64829
+ { name: p.name, scope: p.scope, agent: p.agent, startTask: p.startTask },
64830
+ root,
64831
+ store
64832
+ ),
64363
64833
  end: (p) => endSession({ note: p?.note }, root, store),
64364
64834
  status: () => sessionStatus(root, store),
64365
64835
  resume: (id) => resumeSession(id, root, store),
@@ -64497,6 +64967,35 @@ var Cleo = class _Cleo {
64497
64967
  sharingStatus: () => getSharingStatus()
64498
64968
  };
64499
64969
  }
64970
+ // === Agents ===
64971
+ get agents() {
64972
+ const root = this.projectRoot;
64973
+ return {
64974
+ register: (opts) => registerAgent(opts, root),
64975
+ deregister: (agentId) => deregisterAgent(agentId, root),
64976
+ health: (agentId) => checkAgentHealth2(agentId, void 0, root),
64977
+ detectCrashed: (thresholdMs) => detectCrashedAgents(thresholdMs, root),
64978
+ recordHeartbeat: (agentId) => heartbeat(agentId, root),
64979
+ capacity: (agentId) => getAgentCapacity(agentId, root),
64980
+ isOverloaded: (threshold) => isOverloaded(threshold, root),
64981
+ list: (p) => listAgentInstances(
64982
+ {
64983
+ status: p?.status,
64984
+ agentType: p?.agentType
64985
+ },
64986
+ root
64987
+ )
64988
+ };
64989
+ }
64990
+ // === Intelligence ===
64991
+ get intelligence() {
64992
+ const root = this.projectRoot;
64993
+ const store = this._store ?? void 0;
64994
+ return {
64995
+ predictImpact: (change) => predictImpact(change, root, store ?? void 0),
64996
+ blastRadius: (taskId) => calculateBlastRadius(taskId, store ?? void 0, root)
64997
+ };
64998
+ }
64500
64999
  // === Sync (Task Reconciliation) ===
64501
65000
  get sync() {
64502
65001
  const root = this.projectRoot;
@@ -64668,6 +65167,7 @@ export {
64668
65167
  isSuccessCode,
64669
65168
  isValidStatus,
64670
65169
  issue_exports as issue,
65170
+ lib_exports as lib,
64671
65171
  lifecycle_exports as lifecycle,
64672
65172
  lifecycleEvidenceTypeSchema,
64673
65173
  lifecycleGateResultSchema,