@cleocode/cleo 2026.4.128 → 2026.4.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -758,6 +758,66 @@ var init_session2 = __esm({
758
758
  }
759
759
  });
760
760
 
761
+ // packages/contracts/src/session-journal.ts
762
+ import { z as z4 } from "zod";
763
+ var SESSION_JOURNAL_SCHEMA_VERSION, sessionJournalDoctorSummarySchema, sessionJournalDebriefSummarySchema, sessionJournalEntrySchema;
764
+ var init_session_journal = __esm({
765
+ "packages/contracts/src/session-journal.ts"() {
766
+ "use strict";
767
+ SESSION_JOURNAL_SCHEMA_VERSION = "1.0";
768
+ sessionJournalDoctorSummarySchema = z4.object({
769
+ /** `true` when zero noise patterns were detected. */
770
+ isClean: z4.boolean(),
771
+ /** Total number of noise findings across all patterns. */
772
+ findingsCount: z4.number().int().nonnegative(),
773
+ /** Pattern names that were detected (empty when isClean). */
774
+ patterns: z4.array(z4.string()),
775
+ /** Total brain entries scanned. `0` = empty or unavailable. */
776
+ totalScanned: z4.number().int().nonnegative()
777
+ });
778
+ sessionJournalDebriefSummarySchema = z4.object({
779
+ /** First 200 characters of the session end note (if provided). */
780
+ noteExcerpt: z4.string().max(200).optional(),
781
+ /** Number of tasks completed during the session. */
782
+ tasksCompletedCount: z4.number().int().nonnegative(),
783
+ /** Up to 5 task IDs (not titles) that were the focus of the session. */
784
+ tasksFocused: z4.array(z4.string()).max(5).optional()
785
+ });
786
+ sessionJournalEntrySchema = z4.object({
787
+ // Identity
788
+ /** Schema version for forward-compatibility. Always `'1.0'` in this release. */
789
+ schemaVersion: z4.literal(SESSION_JOURNAL_SCHEMA_VERSION),
790
+ /** ISO 8601 timestamp when the entry was written. */
791
+ timestamp: z4.string(),
792
+ /** CLEO session ID (e.g. `ses_20260424055456_ede571`). */
793
+ sessionId: z4.string(),
794
+ /** Event type that triggered this journal entry. */
795
+ eventType: z4.enum(["session_start", "session_end", "observation", "decision", "error"]),
796
+ // Session metadata (set on session_start / session_end)
797
+ /** Agent identifier (e.g. `cleo-prime`, `claude-code`). */
798
+ agentIdentifier: z4.string().optional(),
799
+ /** Provider adapter ID active for this session. */
800
+ providerId: z4.string().optional(),
801
+ /** Session scope string (e.g. `'global'` or `'epic:T1263'`). */
802
+ scope: z4.string().optional(),
803
+ // Session-end fields
804
+ /** Duration of the session in seconds (session_end only). */
805
+ duration: z4.number().int().nonnegative().optional(),
806
+ /** Task IDs (not titles) completed during the session. */
807
+ tasksCompleted: z4.array(z4.string()).optional(),
808
+ // Doctor summary (T1262 absorbed)
809
+ /** Compact result of `scanBrainNoise` run at session-end. */
810
+ doctorSummary: sessionJournalDoctorSummarySchema.optional(),
811
+ // Debrief summary
812
+ /** Compact excerpt from session debrief data. */
813
+ debriefSummary: sessionJournalDebriefSummarySchema.optional(),
814
+ // Optional hash chain
815
+ /** SHA-256 hex of the previous entry's raw JSON string (for integrity chain). */
816
+ prevEntryHash: z4.string().optional()
817
+ });
818
+ }
819
+ });
820
+
761
821
  // packages/contracts/src/status-registry.ts
762
822
  var TASK_STATUS_SYMBOLS_UNICODE, TASK_STATUS_SYMBOLS_ASCII;
763
823
  var init_status_registry = __esm({
@@ -792,52 +852,52 @@ var init_status_registry = __esm({
792
852
  });
793
853
 
794
854
  // packages/contracts/src/task-evidence.ts
795
- import { z as z4 } from "zod";
855
+ import { z as z5 } from "zod";
796
856
  var fileEvidenceSchema, logEvidenceSchema, screenshotEvidenceSchema, testOutputEvidenceSchema, commandOutputEvidenceSchema, taskEvidenceSchema;
797
857
  var init_task_evidence = __esm({
798
858
  "packages/contracts/src/task-evidence.ts"() {
799
859
  "use strict";
800
- fileEvidenceSchema = z4.object({
801
- kind: z4.literal("file"),
802
- sha256: z4.string().length(64),
803
- timestamp: z4.string().datetime(),
804
- path: z4.string().min(1),
805
- mime: z4.string().optional(),
806
- description: z4.string().optional()
860
+ fileEvidenceSchema = z5.object({
861
+ kind: z5.literal("file"),
862
+ sha256: z5.string().length(64),
863
+ timestamp: z5.string().datetime(),
864
+ path: z5.string().min(1),
865
+ mime: z5.string().optional(),
866
+ description: z5.string().optional()
807
867
  });
808
- logEvidenceSchema = z4.object({
809
- kind: z4.literal("log"),
810
- sha256: z4.string().length(64),
811
- timestamp: z4.string().datetime(),
812
- source: z4.string().min(1),
813
- description: z4.string().optional()
868
+ logEvidenceSchema = z5.object({
869
+ kind: z5.literal("log"),
870
+ sha256: z5.string().length(64),
871
+ timestamp: z5.string().datetime(),
872
+ source: z5.string().min(1),
873
+ description: z5.string().optional()
814
874
  });
815
- screenshotEvidenceSchema = z4.object({
816
- kind: z4.literal("screenshot"),
817
- sha256: z4.string().length(64),
818
- timestamp: z4.string().datetime(),
819
- mime: z4.enum(["image/png", "image/jpeg", "image/webp"]).optional(),
820
- description: z4.string().optional()
875
+ screenshotEvidenceSchema = z5.object({
876
+ kind: z5.literal("screenshot"),
877
+ sha256: z5.string().length(64),
878
+ timestamp: z5.string().datetime(),
879
+ mime: z5.enum(["image/png", "image/jpeg", "image/webp"]).optional(),
880
+ description: z5.string().optional()
821
881
  });
822
- testOutputEvidenceSchema = z4.object({
823
- kind: z4.literal("test-output"),
824
- sha256: z4.string().length(64),
825
- timestamp: z4.string().datetime(),
826
- passed: z4.number().int().nonnegative(),
827
- failed: z4.number().int().nonnegative(),
828
- skipped: z4.number().int().nonnegative(),
829
- exitCode: z4.number().int(),
830
- description: z4.string().optional()
882
+ testOutputEvidenceSchema = z5.object({
883
+ kind: z5.literal("test-output"),
884
+ sha256: z5.string().length(64),
885
+ timestamp: z5.string().datetime(),
886
+ passed: z5.number().int().nonnegative(),
887
+ failed: z5.number().int().nonnegative(),
888
+ skipped: z5.number().int().nonnegative(),
889
+ exitCode: z5.number().int(),
890
+ description: z5.string().optional()
831
891
  });
832
- commandOutputEvidenceSchema = z4.object({
833
- kind: z4.literal("command-output"),
834
- sha256: z4.string().length(64),
835
- timestamp: z4.string().datetime(),
836
- cmd: z4.string().min(1),
837
- exitCode: z4.number().int(),
838
- description: z4.string().optional()
892
+ commandOutputEvidenceSchema = z5.object({
893
+ kind: z5.literal("command-output"),
894
+ sha256: z5.string().length(64),
895
+ timestamp: z5.string().datetime(),
896
+ cmd: z5.string().min(1),
897
+ exitCode: z5.number().int(),
898
+ description: z5.string().optional()
839
899
  });
840
- taskEvidenceSchema = z4.discriminatedUnion("kind", [
900
+ taskEvidenceSchema = z5.discriminatedUnion("kind", [
841
901
  fileEvidenceSchema,
842
902
  logEvidenceSchema,
843
903
  screenshotEvidenceSchema,
@@ -862,6 +922,7 @@ var init_src = __esm({
862
922
  init_params();
863
923
  init_peer();
864
924
  init_session2();
925
+ init_session_journal();
865
926
  init_status_registry();
866
927
  init_task_evidence();
867
928
  }
@@ -7669,6 +7730,32 @@ var init_registry = __esm({
7669
7730
  }
7670
7731
  ]
7671
7732
  },
7733
+ // ── playbook.validate (T1261 PSYCHE E4) ──────────────────────────────────
7734
+ {
7735
+ gateway: "query",
7736
+ domain: "playbook",
7737
+ operation: "validate",
7738
+ description: "playbook.validate (query) \u2014 parse and validate a .cantbook file without executing it; exit 0 on success, exit 70 on parse error",
7739
+ tier: 1,
7740
+ idempotent: true,
7741
+ sessionRequired: false,
7742
+ requiredParams: [],
7743
+ params: [
7744
+ {
7745
+ name: "file",
7746
+ type: "string",
7747
+ required: false,
7748
+ description: "Absolute or relative path to the .cantbook file",
7749
+ cli: { positional: true }
7750
+ },
7751
+ {
7752
+ name: "name",
7753
+ type: "string",
7754
+ required: false,
7755
+ description: "Playbook name (resolved through the standard search path)"
7756
+ }
7757
+ ]
7758
+ },
7672
7759
  // ── orchestrate.{approve,reject,pending} HITL gate decisions (T935) ──────
7673
7760
  {
7674
7761
  gateway: "mutate",
@@ -9129,6 +9216,11 @@ async function sessionGc(projectRoot, maxAgeDays = 1) {
9129
9216
  await accessor.removeSingleSession(s.id);
9130
9217
  }
9131
9218
  }
9219
+ try {
9220
+ const { rotateSessionJournals } = await import("@cleocode/core/sessions/session-journal.js");
9221
+ await rotateSessionJournals(projectRoot);
9222
+ } catch {
9223
+ }
9132
9224
  return { success: true, data: { orphaned, removed } };
9133
9225
  } catch {
9134
9226
  return engineError("E_NOT_INITIALIZED", "Task database not initialized");
@@ -9782,7 +9874,7 @@ async function applyCantBodySubstitution(payload, cwd, ctx) {
9782
9874
  if (!cantPath) {
9783
9875
  return { ...empty, reason: "resolved agent has no cantPath" };
9784
9876
  }
9785
- const [{ existsSync: existsSync12, readFileSync: readFileSync15 }, { substituteCantAgentBody }] = await Promise.all([
9877
+ const [{ existsSync: existsSync12, readFileSync: readFileSync16 }, { substituteCantAgentBody }] = await Promise.all([
9786
9878
  import("node:fs"),
9787
9879
  import("@cleocode/core/internal")
9788
9880
  ]);
@@ -9791,7 +9883,7 @@ async function applyCantBodySubstitution(payload, cwd, ctx) {
9791
9883
  }
9792
9884
  let body;
9793
9885
  try {
9794
- body = readFileSync15(cantPath, "utf-8");
9886
+ body = readFileSync16(cantPath, "utf-8");
9795
9887
  } catch (err) {
9796
9888
  return {
9797
9889
  ...empty,
@@ -11714,9 +11806,9 @@ async function systemLog(projectRoot, filters) {
11714
11806
  }
11715
11807
  async function queryAuditLogSqlite(projectRoot, filters) {
11716
11808
  try {
11717
- const { join: join22 } = await import("node:path");
11809
+ const { join: join23 } = await import("node:path");
11718
11810
  const { existsSync: existsSync12 } = await import("node:fs");
11719
- const dbPath = join22(projectRoot, CLEO_DIR_NAME, TASKS_DB_FILENAME);
11811
+ const dbPath = join23(projectRoot, CLEO_DIR_NAME, TASKS_DB_FILENAME);
11720
11812
  if (!existsSync12(dbPath)) {
11721
11813
  const offset = filters?.offset ?? 0;
11722
11814
  const limit = filters?.limit ?? 20;
@@ -24527,13 +24619,15 @@ function parseAgenticNode(raw, base, index) {
24527
24619
  }
24528
24620
  inputs = acc;
24529
24621
  }
24622
+ const context_files = parseStringArray(raw.context_files, `nodes[${index}].context_files`);
24530
24623
  return {
24531
24624
  ...base,
24532
24625
  type: "agentic",
24533
24626
  skill,
24534
24627
  agent,
24535
24628
  role,
24536
- inputs
24629
+ inputs,
24630
+ ...context_files !== void 0 ? { context_files } : {}
24537
24631
  };
24538
24632
  }
24539
24633
  function parseDeterministicNode(raw, base, index) {
@@ -24893,6 +24987,105 @@ var init_parser = __esm({
24893
24987
  }
24894
24988
  });
24895
24989
 
24990
+ // packages/playbooks/src/migrate-e4.ts
24991
+ import { readFileSync as readFileSync5, writeFileSync } from "node:fs";
24992
+ function validatePlaybookCompliance(source) {
24993
+ let parsed;
24994
+ try {
24995
+ parsed = parsePlaybook(source);
24996
+ } catch (err) {
24997
+ return {
24998
+ parses: false,
24999
+ parseError: err instanceof PlaybookParseError ? err.message : String(err),
25000
+ hasErrorHandlers: false,
25001
+ nodesMissingRequires: 0,
25002
+ nodesMissingEnsures: 0,
25003
+ nodes: [],
25004
+ compliant: false
25005
+ };
25006
+ }
25007
+ const { definition } = parsed;
25008
+ const hasErrorHandlers = (definition.error_handlers?.length ?? 0) > 0;
25009
+ const nodeEntries = definition.nodes.map((n) => ({
25010
+ id: n.id,
25011
+ type: n.type,
25012
+ hasRequires: n.requires !== void 0,
25013
+ hasEnsures: n.ensures !== void 0
25014
+ }));
25015
+ const workNodes = nodeEntries.filter((e) => e.type !== "approval");
25016
+ const nodesMissingRequires = workNodes.filter((e) => !e.hasRequires).length;
25017
+ const nodesMissingEnsures = workNodes.filter((e) => !e.hasEnsures).length;
25018
+ const compliant = hasErrorHandlers && nodesMissingRequires === 0 && nodesMissingEnsures === 0;
25019
+ return {
25020
+ parses: true,
25021
+ hasErrorHandlers,
25022
+ nodesMissingRequires,
25023
+ nodesMissingEnsures,
25024
+ nodes: nodeEntries,
25025
+ compliant
25026
+ };
25027
+ }
25028
+ function migratePlaybook(source) {
25029
+ parsePlaybook(source);
25030
+ const raw = load(source);
25031
+ if (!Array.isArray(raw.error_handlers) || raw.error_handlers.length === 0) {
25032
+ raw.error_handlers = [
25033
+ {
25034
+ on: "iteration_cap_exceeded",
25035
+ action: "hitl_escalate",
25036
+ message: "Stage exhausted retries \u2014 escalate to human for direction."
25037
+ },
25038
+ {
25039
+ on: "contract_violation",
25040
+ action: "inject_hint",
25041
+ message: "Contract violated at stage boundary \u2014 check requires/ensures fields."
25042
+ }
25043
+ ];
25044
+ }
25045
+ if (Array.isArray(raw.nodes)) {
25046
+ raw.nodes = raw.nodes.map((node) => {
25047
+ if (node.type === "approval") return node;
25048
+ const patched = { ...node };
25049
+ if (!patched.requires) patched.requires = {};
25050
+ if (!patched.ensures) patched.ensures = {};
25051
+ return patched;
25052
+ });
25053
+ }
25054
+ return dump(raw, { lineWidth: 100, noRefs: true });
25055
+ }
25056
+ function migratePlaybookFile(filePath, dryRun = false) {
25057
+ const source = readFileSync5(filePath, "utf8");
25058
+ const before = validatePlaybookCompliance(source);
25059
+ if (!before.parses) {
25060
+ return {
25061
+ filePath,
25062
+ before,
25063
+ after: before,
25064
+ written: false,
25065
+ migratedSource: source
25066
+ };
25067
+ }
25068
+ const migratedSource = migratePlaybook(source);
25069
+ const after = validatePlaybookCompliance(migratedSource);
25070
+ if (!dryRun && !before.compliant) {
25071
+ writeFileSync(filePath, migratedSource, "utf8");
25072
+ }
25073
+ return {
25074
+ filePath,
25075
+ before,
25076
+ after,
25077
+ written: !dryRun && !before.compliant,
25078
+ migratedSource
25079
+ };
25080
+ }
25081
+ var init_migrate_e4 = __esm({
25082
+ "packages/playbooks/src/migrate-e4.ts"() {
25083
+ "use strict";
25084
+ init_js_yaml();
25085
+ init_parser();
25086
+ }
25087
+ });
25088
+
24896
25089
  // packages/playbooks/src/policy.ts
24897
25090
  function evaluatePolicy(command, rules = DEFAULT_POLICY_RULES) {
24898
25091
  for (const rule of rules) {
@@ -25212,6 +25405,8 @@ var init_state = __esm({
25212
25405
  });
25213
25406
 
25214
25407
  // packages/playbooks/src/runtime.ts
25408
+ import { appendFileSync, mkdirSync } from "node:fs";
25409
+ import { dirname as dirname2, join as join4 } from "node:path";
25215
25410
  function buildEdgeIndex(def) {
25216
25411
  const outgoing = /* @__PURE__ */ new Map();
25217
25412
  const incoming = /* @__PURE__ */ new Map();
@@ -25364,6 +25559,42 @@ function executeApprovalNode(node, runId, context, db, secret) {
25364
25559
  });
25365
25560
  return { kind: "awaiting_approval", token: gate.token, approvalId: gate.approvalId };
25366
25561
  }
25562
+ function checkRequires(fields, from, context) {
25563
+ for (const key of fields) {
25564
+ if (!(key in context)) {
25565
+ const source = from !== void 0 ? ` (from node '${from}')` : "";
25566
+ return `requires.fields['${key}']${source} not present in context`;
25567
+ }
25568
+ }
25569
+ return null;
25570
+ }
25571
+ function resolveEdge(fromId, toId, edges) {
25572
+ return edges.find((e) => e.from === fromId && e.to === toId);
25573
+ }
25574
+ function auditContractViolation(projectRoot, runId, nodeId, field, key, playbookName) {
25575
+ if (!projectRoot) return;
25576
+ try {
25577
+ const filePath = join4(projectRoot, ".cleo", "audit", "contract-violations.jsonl");
25578
+ mkdirSync(dirname2(filePath), { recursive: true });
25579
+ const entry = JSON.stringify({
25580
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
25581
+ runId,
25582
+ nodeId,
25583
+ field,
25584
+ key,
25585
+ message: `contract_violation: ${field}['${key}'] check failed on node '${nodeId}'`,
25586
+ playbookName
25587
+ });
25588
+ appendFileSync(filePath, `${entry}
25589
+ `, { encoding: "utf-8" });
25590
+ } catch {
25591
+ }
25592
+ }
25593
+ function handleContractErrorHandler(playbook, trigger, _message) {
25594
+ if (!playbook.error_handlers) return null;
25595
+ const handler = playbook.error_handlers.find((h) => h.on === trigger);
25596
+ return handler?.action ?? null;
25597
+ }
25367
25598
  function iterationCapFor(node, runtimeDefault) {
25368
25599
  const cap = node.on_failure?.max_iterations;
25369
25600
  if (typeof cap === "number" && Number.isFinite(cap) && cap >= 0) return cap;
@@ -25372,6 +25603,7 @@ function iterationCapFor(node, runtimeDefault) {
25372
25603
  async function runFromNode(args) {
25373
25604
  const {
25374
25605
  db,
25606
+ playbook,
25375
25607
  run,
25376
25608
  startNodeId,
25377
25609
  nodeIndex,
@@ -25397,6 +25629,35 @@ async function runFromNode(args) {
25397
25629
  currentNode: node.id,
25398
25630
  iterationCounts: { ...iterationCounts }
25399
25631
  });
25632
+ if (node.requires?.fields) {
25633
+ const violation = checkRequires(node.requires.fields, node.requires.from, context);
25634
+ if (violation !== null) {
25635
+ const contractFailure = `contract_violation: ${violation}`;
25636
+ auditContractViolation(
25637
+ args.projectRoot,
25638
+ run.runId,
25639
+ node.id,
25640
+ "requires",
25641
+ violation,
25642
+ playbook.name
25643
+ );
25644
+ const handled = handleContractErrorHandler(playbook, "contract_violation", contractFailure);
25645
+ if (handled === "abort") {
25646
+ failedNodeId = node.id;
25647
+ lastError = contractFailure;
25648
+ break;
25649
+ }
25650
+ if (handled !== null) {
25651
+ context["__lastError"] = contractFailure;
25652
+ context["__lastFailedNode"] = node.id;
25653
+ context["__contractViolation"] = violation;
25654
+ if (handled === "hitl_escalate") {
25655
+ exceededNodeId = node.id;
25656
+ break;
25657
+ }
25658
+ }
25659
+ }
25660
+ }
25400
25661
  let outcome;
25401
25662
  if (node.type === "agentic") {
25402
25663
  outcome = await executeAgenticNode(node, run.runId, context, attempt, dispatcher);
@@ -25420,7 +25681,51 @@ async function runFromNode(args) {
25420
25681
  if (outcome.kind === "success") {
25421
25682
  Object.assign(context, outcome.output);
25422
25683
  updatePlaybookRun(db, run.runId, { bindings: { ...context } });
25423
- currentId = resolveNextNodeId(node.id, edgeIndex);
25684
+ if (node.ensures?.outputFiles) {
25685
+ for (const key of node.ensures.outputFiles) {
25686
+ if (!(key in context)) {
25687
+ const violation = `ensures.outputFiles[${key}] not present in context after ${node.id}`;
25688
+ auditContractViolation(
25689
+ args.projectRoot,
25690
+ run.runId,
25691
+ node.id,
25692
+ "ensures",
25693
+ key,
25694
+ playbook.name
25695
+ );
25696
+ handleContractErrorHandler(playbook, "contract_violation", violation);
25697
+ context["__ensuresViolation"] = violation;
25698
+ }
25699
+ }
25700
+ }
25701
+ const nextId = resolveNextNodeId(node.id, edgeIndex);
25702
+ if (nextId !== null) {
25703
+ const edge = resolveEdge(node.id, nextId, playbook.edges);
25704
+ if (edge?.contract?.requires) {
25705
+ for (const key of edge.contract.requires) {
25706
+ if (!(key in context)) {
25707
+ const violation = `edge.contract.requires[${key}] missing when crossing ${node.id} \u2192 ${nextId}`;
25708
+ auditContractViolation(
25709
+ args.projectRoot,
25710
+ run.runId,
25711
+ node.id,
25712
+ "requires",
25713
+ key,
25714
+ playbook.name
25715
+ );
25716
+ const handled = handleContractErrorHandler(playbook, "contract_violation", violation);
25717
+ if (handled === "abort") {
25718
+ failedNodeId = node.id;
25719
+ lastError = violation;
25720
+ break;
25721
+ }
25722
+ context["__contractViolation"] = violation;
25723
+ }
25724
+ }
25725
+ if (failedNodeId !== void 0) break;
25726
+ }
25727
+ }
25728
+ currentId = nextId;
25424
25729
  continue;
25425
25730
  }
25426
25731
  if (outcome.kind === "awaiting_approval") {
@@ -25560,7 +25865,8 @@ async function executePlaybook(options) {
25560
25865
  deterministicRunner: options.deterministicRunner,
25561
25866
  approvalSecret,
25562
25867
  maxIterationsDefault,
25563
- now
25868
+ now,
25869
+ projectRoot: options.projectRoot
25564
25870
  };
25565
25871
  return runFromNode(runArgs);
25566
25872
  }
@@ -25660,7 +25966,8 @@ async function resumePlaybook(options) {
25660
25966
  deterministicRunner: options.deterministicRunner,
25661
25967
  approvalSecret,
25662
25968
  maxIterationsDefault,
25663
- now
25969
+ now,
25970
+ projectRoot: options.projectRoot
25664
25971
  };
25665
25972
  return runFromNode(runArgs);
25666
25973
  }
@@ -25699,28 +26006,32 @@ __export(src_exports, {
25699
26006
  getPlaybookSecret: () => getPlaybookSecret,
25700
26007
  listPlaybookApprovals: () => listPlaybookApprovals,
25701
26008
  listPlaybookRuns: () => listPlaybookRuns,
26009
+ migratePlaybook: () => migratePlaybook,
26010
+ migratePlaybookFile: () => migratePlaybookFile,
25702
26011
  parsePlaybook: () => parsePlaybook,
25703
26012
  rejectGate: () => rejectGate,
25704
26013
  resumePlaybook: () => resumePlaybook,
25705
26014
  updatePlaybookApproval: () => updatePlaybookApproval,
25706
- updatePlaybookRun: () => updatePlaybookRun
26015
+ updatePlaybookRun: () => updatePlaybookRun,
26016
+ validatePlaybookCompliance: () => validatePlaybookCompliance
25707
26017
  });
25708
26018
  var PLAYBOOKS_PACKAGE_VERSION;
25709
26019
  var init_src2 = __esm({
25710
26020
  "packages/playbooks/src/index.ts"() {
25711
26021
  init_approval();
26022
+ init_migrate_e4();
25712
26023
  init_parser();
25713
26024
  init_policy();
25714
26025
  init_runtime();
25715
26026
  init_state();
25716
- PLAYBOOKS_PACKAGE_VERSION = "2026.4.85";
26027
+ PLAYBOOKS_PACKAGE_VERSION = "2026.4.129";
25717
26028
  }
25718
26029
  });
25719
26030
 
25720
26031
  // packages/cleo/src/dispatch/domains/playbook.ts
25721
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
26032
+ import { existsSync as existsSync3, readFileSync as readFileSync6 } from "node:fs";
25722
26033
  import { homedir } from "node:os";
25723
- import { dirname as dirname2, join as join4, resolve as resolvePath2 } from "node:path";
26034
+ import { dirname as dirname3, join as join5, resolve as resolvePath2 } from "node:path";
25724
26035
  import { fileURLToPath } from "node:url";
25725
26036
  function normalizeListStatus(raw) {
25726
26037
  if (typeof raw !== "string" || raw.length === 0) return void 0;
@@ -25748,8 +26059,8 @@ function resolvePlaybookDirs() {
25748
26059
  if (__playbookRuntimeOverrides.playbookBaseDirs) {
25749
26060
  return __playbookRuntimeOverrides.playbookBaseDirs;
25750
26061
  }
25751
- const globalDir = join4(homedir(), ".local", "share", "cleo", "playbooks");
25752
- const here = dirname2(fileURLToPath(import.meta.url));
26062
+ const globalDir = join5(homedir(), ".local", "share", "cleo", "playbooks");
26063
+ const here = dirname3(fileURLToPath(import.meta.url));
25753
26064
  const sourceStarter = resolvePath2(here, "..", "..", "..", "..", "playbooks", "starter");
25754
26065
  const bundledStarter = resolvePath2(here, "..", "..", "..", "playbooks", "starter");
25755
26066
  return [globalDir, sourceStarter, bundledStarter];
@@ -25758,9 +26069,9 @@ function loadPlaybookByName(name) {
25758
26069
  const candidates = resolvePlaybookDirs();
25759
26070
  const fileName = name.endsWith(".cantbook") ? name : `${name}.cantbook`;
25760
26071
  for (const dir of candidates) {
25761
- const full = join4(dir, fileName);
26072
+ const full = join5(dir, fileName);
25762
26073
  if (existsSync3(full)) {
25763
- return { sourcePath: full, source: readFileSync5(full, "utf8") };
26074
+ return { sourcePath: full, source: readFileSync6(full, "utf8") };
25764
26075
  }
25765
26076
  }
25766
26077
  return null;
@@ -25874,7 +26185,7 @@ var init_playbook = __esm({
25874
26185
  __playbookRuntimeOverrides = {};
25875
26186
  PlaybookHandler = class {
25876
26187
  /**
25877
- * Query gateway — `status` and `list`.
26188
+ * Query gateway — `status`, `list`, and `validate`.
25878
26189
  */
25879
26190
  async query(operation, params) {
25880
26191
  const startTime = Date.now();
@@ -25884,6 +26195,8 @@ var init_playbook = __esm({
25884
26195
  return this.handleStatus(params, startTime);
25885
26196
  case "list":
25886
26197
  return this.handleList(params, startTime);
26198
+ case "validate":
26199
+ return this.handleValidate(params, startTime);
25887
26200
  default:
25888
26201
  return errorResult(
25889
26202
  "query",
@@ -25928,7 +26241,7 @@ var init_playbook = __esm({
25928
26241
  */
25929
26242
  getSupportedOperations() {
25930
26243
  return {
25931
- query: ["status", "list"],
26244
+ query: ["status", "list", "validate"],
25932
26245
  mutate: ["run", "resume"]
25933
26246
  };
25934
26247
  }
@@ -25988,6 +26301,104 @@ var init_playbook = __esm({
25988
26301
  data: envelope
25989
26302
  };
25990
26303
  }
26304
+ /**
26305
+ * Validate a `.cantbook` file at an absolute path or a playbook name.
26306
+ *
26307
+ * Accepts either:
26308
+ * - `file` — absolute or relative path to a `.cantbook` file on disk.
26309
+ * - `name` — playbook name resolved through the standard search path.
26310
+ *
26311
+ * Returns a LAFS envelope with `valid: true` on success, or an error
26312
+ * envelope with `E_PLAYBOOK_PARSE` and the field/message on failure.
26313
+ * Exit code 70 is passed through from {@link PlaybookParseError}.
26314
+ *
26315
+ * @task T1261 PSYCHE E4
26316
+ */
26317
+ async handleValidate(params, startTime) {
26318
+ const file = params?.file;
26319
+ const name = params?.name;
26320
+ if (!file && !name) {
26321
+ return errorResult(
26322
+ "query",
26323
+ "playbook",
26324
+ "validate",
26325
+ "E_INVALID_INPUT",
26326
+ "Either file (path) or name (playbook name) is required",
26327
+ startTime
26328
+ );
26329
+ }
26330
+ let source;
26331
+ let sourcePath;
26332
+ if (file) {
26333
+ const { existsSync: existsSync12, readFileSync: readFileSync16 } = await import("node:fs");
26334
+ const { resolve: resolvePath3 } = await import("node:path");
26335
+ const resolved = resolvePath3(file);
26336
+ if (!existsSync12(resolved)) {
26337
+ return errorResult(
26338
+ "query",
26339
+ "playbook",
26340
+ "validate",
26341
+ "E_NOT_FOUND",
26342
+ `playbook file not found: ${resolved}`,
26343
+ startTime
26344
+ );
26345
+ }
26346
+ sourcePath = resolved;
26347
+ source = readFileSync16(resolved, "utf8");
26348
+ } else {
26349
+ const loaded = loadPlaybookByName(name);
26350
+ if (loaded === null) {
26351
+ return errorResult(
26352
+ "query",
26353
+ "playbook",
26354
+ "validate",
26355
+ "E_NOT_FOUND",
26356
+ `playbook "${name}" not found in any search path`,
26357
+ startTime
26358
+ );
26359
+ }
26360
+ sourcePath = loaded.sourcePath;
26361
+ source = loaded.source;
26362
+ }
26363
+ try {
26364
+ const { definition, sourceHash } = parsePlaybook(source);
26365
+ return {
26366
+ meta: dispatchMeta("query", "playbook", "validate", startTime),
26367
+ success: true,
26368
+ data: {
26369
+ valid: true,
26370
+ sourcePath,
26371
+ sourceHash,
26372
+ name: definition.name,
26373
+ version: definition.version,
26374
+ nodeCount: definition.nodes.length,
26375
+ edgeCount: definition.edges.length,
26376
+ hasRequires: definition.nodes.some((n) => n.requires !== void 0),
26377
+ hasEnsures: definition.nodes.some((n) => n.ensures !== void 0),
26378
+ hasErrorHandlers: (definition.error_handlers?.length ?? 0) > 0
26379
+ }
26380
+ };
26381
+ } catch (err) {
26382
+ if (err instanceof PlaybookParseError) {
26383
+ return errorResult(
26384
+ "query",
26385
+ "playbook",
26386
+ "validate",
26387
+ err.code,
26388
+ `${err.message}${err.field ? ` [field=${err.field}]` : ""}`,
26389
+ startTime
26390
+ );
26391
+ }
26392
+ return errorResult(
26393
+ "query",
26394
+ "playbook",
26395
+ "validate",
26396
+ "E_PLAYBOOK_PARSE",
26397
+ err instanceof Error ? err.message : String(err),
26398
+ startTime
26399
+ );
26400
+ }
26401
+ }
25991
26402
  async handleRun(params, startTime) {
25992
26403
  const name = params?.name;
25993
26404
  if (!name) {
@@ -26051,12 +26462,14 @@ var init_playbook = __esm({
26051
26462
  const dispatcher = await buildDefaultDispatcher();
26052
26463
  let result;
26053
26464
  try {
26465
+ const { getProjectRoot: getProjectRoot29 } = await import("@cleocode/core/internal");
26054
26466
  const opts = {
26055
26467
  db,
26056
26468
  playbook: parsed.definition,
26057
26469
  playbookHash: parsed.sourceHash,
26058
26470
  initialContext,
26059
- dispatcher
26471
+ dispatcher,
26472
+ projectRoot: getProjectRoot29()
26060
26473
  };
26061
26474
  if (__playbookRuntimeOverrides.approvalSecret !== void 0) {
26062
26475
  opts.approvalSecret = __playbookRuntimeOverrides.approvalSecret;
@@ -26219,8 +26632,8 @@ import {
26219
26632
  async function orchestrateClassify(request, context, projectRoot) {
26220
26633
  try {
26221
26634
  const { getCleoCantWorkflowsDir: getCleoCantWorkflowsDir2 } = await import("@cleocode/core/internal");
26222
- const { readFileSync: readFileSync15, readdirSync: readdirSync4, existsSync: existsSync12 } = await import("node:fs");
26223
- const { join: join22 } = await import("node:path");
26635
+ const { readFileSync: readFileSync16, readdirSync: readdirSync4, existsSync: existsSync12 } = await import("node:fs");
26636
+ const { join: join23 } = await import("node:path");
26224
26637
  const workflowsDir = getCleoCantWorkflowsDir2();
26225
26638
  const combined = `${request} ${context ?? ""}`.toLowerCase();
26226
26639
  const matches = [];
@@ -26228,7 +26641,7 @@ async function orchestrateClassify(request, context, projectRoot) {
26228
26641
  const files = readdirSync4(workflowsDir).filter((f) => f.endsWith(".cant"));
26229
26642
  for (const file of files) {
26230
26643
  try {
26231
- const src = readFileSync15(join22(workflowsDir, file), "utf-8");
26644
+ const src = readFileSync16(join23(workflowsDir, file), "utf-8");
26232
26645
  const teamMatch = /^team\s+(\S+):/m.exec(src);
26233
26646
  if (!teamMatch) continue;
26234
26647
  const teamName = teamMatch[1];
@@ -26243,12 +26656,12 @@ async function orchestrateClassify(request, context, projectRoot) {
26243
26656
  }
26244
26657
  }
26245
26658
  }
26246
- const localCantDir = join22(projectRoot, CLEO_DIR_NAME, WORKFLOWS_SUBDIR);
26659
+ const localCantDir = join23(projectRoot, CLEO_DIR_NAME, WORKFLOWS_SUBDIR);
26247
26660
  if (existsSync12(localCantDir)) {
26248
26661
  const files = readdirSync4(localCantDir).filter((f) => f.endsWith(".cant"));
26249
26662
  for (const file of files) {
26250
26663
  try {
26251
- const src = readFileSync15(join22(localCantDir, file), "utf-8");
26664
+ const src = readFileSync16(join23(localCantDir, file), "utf-8");
26252
26665
  const teamMatch = /^team\s+(\S+):/m.exec(src);
26253
26666
  if (!teamMatch) continue;
26254
26667
  const teamName = teamMatch[1];
@@ -28226,7 +28639,7 @@ var init_pipeline2 = __esm({
28226
28639
  });
28227
28640
 
28228
28641
  // packages/cleo/src/dispatch/domains/sentient.ts
28229
- import { join as join5 } from "node:path";
28642
+ import { join as join6 } from "node:path";
28230
28643
  import { getProjectRoot as getProjectRoot11 } from "@cleocode/core";
28231
28644
  function safeParseJsonArray(json2) {
28232
28645
  if (!json2) return [];
@@ -28255,7 +28668,7 @@ async function incrementTier2Stat(projectRoot, field) {
28255
28668
  try {
28256
28669
  const { patchSentientState: patchSentientState2, readSentientState: readSentientState2 } = await import("@cleocode/core/sentient/state.js");
28257
28670
  const { SENTIENT_STATE_FILE: SENTIENT_STATE_FILE2 } = await import("@cleocode/core/sentient/daemon.js");
28258
- const statePath = join5(projectRoot, SENTIENT_STATE_FILE2);
28671
+ const statePath = join6(projectRoot, SENTIENT_STATE_FILE2);
28259
28672
  const state = await readSentientState2(statePath);
28260
28673
  await patchSentientState2(statePath, {
28261
28674
  tier2Stats: {
@@ -28532,7 +28945,7 @@ var init_sentient = __esm({
28532
28945
  async runProposeTick(projectRoot, params) {
28533
28946
  const { safeRunProposeTick: safeRunProposeTick2 } = await import("@cleocode/core/sentient/propose-tick.js");
28534
28947
  const { SENTIENT_STATE_FILE: SENTIENT_STATE_FILE2 } = await import("@cleocode/core/sentient/daemon.js");
28535
- const statePath = join5(projectRoot, SENTIENT_STATE_FILE2);
28948
+ const statePath = join6(projectRoot, SENTIENT_STATE_FILE2);
28536
28949
  const outcome = await safeRunProposeTick2({ projectRoot, statePath });
28537
28950
  const _ = params;
28538
28951
  void _;
@@ -28580,7 +28993,7 @@ var init_sentient = __esm({
28580
28993
  async setTier2Enabled(projectRoot, enabled) {
28581
28994
  const { patchSentientState: patchSentientState2 } = await import("@cleocode/core/sentient/state.js");
28582
28995
  const { SENTIENT_STATE_FILE: SENTIENT_STATE_FILE2 } = await import("@cleocode/core/sentient/daemon.js");
28583
- const statePath = join5(projectRoot, SENTIENT_STATE_FILE2);
28996
+ const statePath = join6(projectRoot, SENTIENT_STATE_FILE2);
28584
28997
  const updated = await patchSentientState2(statePath, { tier2Enabled: enabled });
28585
28998
  return {
28586
28999
  success: true,
@@ -29961,7 +30374,7 @@ var init_tasks3 = __esm({
29961
30374
  });
29962
30375
 
29963
30376
  // packages/cleo/src/dispatch/engines/code-engine.ts
29964
- import { join as join6 } from "node:path";
30377
+ import { join as join7 } from "node:path";
29965
30378
  import { getProjectRoot as getProjectRoot15 } from "@cleocode/core";
29966
30379
  async function codeOutline(params) {
29967
30380
  const { smartOutline } = await import("@cleocode/core/internal");
@@ -29972,7 +30385,7 @@ async function codeOutline(params) {
29972
30385
  error: { code: "E_INVALID_INPUT", message: "file parameter required" }
29973
30386
  };
29974
30387
  const root = getProjectRoot15();
29975
- const absPath = filePath.startsWith("/") ? filePath : join6(root, filePath);
30388
+ const absPath = filePath.startsWith("/") ? filePath : join7(root, filePath);
29976
30389
  return { success: true, data: smartOutline(absPath, root) };
29977
30390
  }
29978
30391
  async function codeSearch(params) {
@@ -30004,7 +30417,7 @@ async function codeUnfold(params) {
30004
30417
  error: { code: "E_INVALID_INPUT", message: "file and symbol parameters required" }
30005
30418
  };
30006
30419
  const root = getProjectRoot15();
30007
- const absPath = filePath.startsWith("/") ? filePath : join6(root, filePath);
30420
+ const absPath = filePath.startsWith("/") ? filePath : join7(root, filePath);
30008
30421
  return { success: true, data: smartUnfold(absPath, symbol, root) };
30009
30422
  }
30010
30423
  async function codeParse(params) {
@@ -30016,7 +30429,7 @@ async function codeParse(params) {
30016
30429
  error: { code: "E_INVALID_INPUT", message: "file parameter required" }
30017
30430
  };
30018
30431
  const root = getProjectRoot15();
30019
- const absPath = filePath.startsWith("/") ? filePath : join6(root, filePath);
30432
+ const absPath = filePath.startsWith("/") ? filePath : join7(root, filePath);
30020
30433
  return { success: true, data: parseFile(absPath, root) };
30021
30434
  }
30022
30435
  var init_code_engine = __esm({
@@ -31185,8 +31598,8 @@ var init_defaults = __esm({
31185
31598
  });
31186
31599
 
31187
31600
  // packages/cleo/src/dispatch/lib/config-loader.ts
31188
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
31189
- import { join as join7 } from "path";
31601
+ import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
31602
+ import { join as join8 } from "path";
31190
31603
  function loadFromEnv(key) {
31191
31604
  const envKey = `${ENV_PREFIX}${key.toUpperCase()}`;
31192
31605
  return process.env[envKey];
@@ -31207,12 +31620,12 @@ function parseEnvValue(key, value) {
31207
31620
  }
31208
31621
  function loadFromFile(projectRoot) {
31209
31622
  const root = projectRoot || process.cwd();
31210
- const configPath = join7(root, CLEO_DIR_NAME, CONFIG_JSON);
31623
+ const configPath = join8(root, CLEO_DIR_NAME, CONFIG_JSON);
31211
31624
  if (!existsSync4(configPath)) {
31212
31625
  return {};
31213
31626
  }
31214
31627
  try {
31215
- const content = readFileSync6(configPath, "utf-8");
31628
+ const content = readFileSync7(configPath, "utf-8");
31216
31629
  const config = JSON.parse(content);
31217
31630
  const result = {};
31218
31631
  if (config.lifecycleEnforcement) {
@@ -31681,7 +32094,7 @@ __export(cli_exports, {
31681
32094
  import { randomUUID as randomUUID5 } from "node:crypto";
31682
32095
  import { existsSync as existsSync5 } from "node:fs";
31683
32096
  import { createRequire as createRequire2 } from "node:module";
31684
- import { dirname as dirname3, join as join8 } from "node:path";
32097
+ import { dirname as dirname4, join as join9 } from "node:path";
31685
32098
  import { fileURLToPath as fileURLToPath2 } from "node:url";
31686
32099
  import { catalog as catalog2, registerSkillLibraryFromPath } from "@cleocode/caamp";
31687
32100
  import { autoRecordDispatchTokenUsage, getProjectRoot as getProjectRoot17, hooks } from "@cleocode/core/internal";
@@ -31692,17 +32105,17 @@ function ensureCaampLibrary() {
31692
32105
  try {
31693
32106
  const req = createRequire2(import.meta.url);
31694
32107
  const skillsPkgJson = req.resolve("@cleocode/skills/package.json");
31695
- const candidate = dirname3(skillsPkgJson);
31696
- if (existsSync5(join8(candidate, "skills.json"))) {
32108
+ const candidate = dirname4(skillsPkgJson);
32109
+ if (existsSync5(join9(candidate, "skills.json"))) {
31697
32110
  skillsRoot = candidate;
31698
32111
  }
31699
32112
  } catch {
31700
32113
  }
31701
32114
  if (!skillsRoot) {
31702
32115
  const thisFile = fileURLToPath2(import.meta.url);
31703
- const packageRoot = join8(dirname3(thisFile), "..", "..", "..", "..", "..");
31704
- const candidate = join8(packageRoot, "packages", "skills");
31705
- if (existsSync5(join8(candidate, "skills.json"))) {
32116
+ const packageRoot = join9(dirname4(thisFile), "..", "..", "..", "..", "..");
32117
+ const candidate = join9(packageRoot, "packages", "skills");
32118
+ if (existsSync5(join9(candidate, "skills.json"))) {
31706
32119
  skillsRoot = candidate;
31707
32120
  }
31708
32121
  }
@@ -31921,8 +32334,8 @@ var init_cli = __esm({
31921
32334
  });
31922
32335
 
31923
32336
  // packages/cleo/src/cli/index.ts
31924
- import { readFileSync as readFileSync14 } from "node:fs";
31925
- import { dirname as dirname9, join as join21 } from "node:path";
32337
+ import { readFileSync as readFileSync15 } from "node:fs";
32338
+ import { dirname as dirname10, join as join22 } from "node:path";
31926
32339
  import { fileURLToPath as fileURLToPath3 } from "node:url";
31927
32340
  import {
31928
32341
  detectAndRemoveLegacyGlobalFiles,
@@ -32882,7 +33295,7 @@ var addCommand = defineCommand({
32882
33295
  });
32883
33296
 
32884
33297
  // packages/cleo/src/cli/commands/add-batch.ts
32885
- import { existsSync as existsSync6, readFileSync as readFileSync7 } from "node:fs";
33298
+ import { existsSync as existsSync6, readFileSync as readFileSync8 } from "node:fs";
32886
33299
  init_cli();
32887
33300
  init_renderers();
32888
33301
  var addBatchCommand = defineCommand({
@@ -32939,7 +33352,7 @@ var addBatchCommand = defineCommand({
32939
33352
  process.exit(2);
32940
33353
  return;
32941
33354
  }
32942
- raw = readFileSync7(filePath, "utf-8");
33355
+ raw = readFileSync8(filePath, "utf-8");
32943
33356
  }
32944
33357
  let tasks;
32945
33358
  try {
@@ -33549,13 +33962,13 @@ var registerCommand = defineCommand({
33549
33962
  transportConfig: {},
33550
33963
  isActive: true
33551
33964
  });
33552
- const { existsSync: existsSync12, mkdirSync: mkdirSync4, writeFileSync: writeFileSync4 } = await import("node:fs");
33553
- const { join: join22 } = await import("node:path");
33554
- const cantDir = join22(CLEO_DIR_NAME, AGENTS_SUBDIR);
33555
- const cantPath = join22(cantDir, `${agentId}.cant`);
33965
+ const { existsSync: existsSync12, mkdirSync: mkdirSync5, writeFileSync: writeFileSync5 } = await import("node:fs");
33966
+ const { join: join23 } = await import("node:path");
33967
+ const cantDir = join23(CLEO_DIR_NAME, AGENTS_SUBDIR);
33968
+ const cantPath = join23(cantDir, `${agentId}.cant`);
33556
33969
  let cantScaffolded = false;
33557
33970
  if (!existsSync12(cantPath)) {
33558
- mkdirSync4(cantDir, { recursive: true });
33971
+ mkdirSync5(cantDir, { recursive: true });
33559
33972
  const role = classification ?? "specialist";
33560
33973
  const cantContent = `---
33561
33974
  kind: agent
@@ -33605,7 +34018,7 @@ agent ${agentId}:
33605
34018
  enforcement:
33606
34019
  1: TODO \u2014 what does this agent push back on?
33607
34020
  `;
33608
- writeFileSync4(cantPath, cantContent, "utf-8");
34021
+ writeFileSync5(cantPath, cantContent, "utf-8");
33609
34022
  cantScaffolded = true;
33610
34023
  }
33611
34024
  cliOutput(
@@ -33733,8 +34146,8 @@ var startCommand = defineCommand({
33733
34146
  try {
33734
34147
  const { AgentRegistryAccessor, getDb: getDb3 } = await import("@cleocode/core/internal");
33735
34148
  const { createRuntime } = await import("@cleocode/runtime");
33736
- const { existsSync: existsSync12, readFileSync: readFileSync15 } = await import("node:fs");
33737
- const { join: join22 } = await import("node:path");
34149
+ const { existsSync: existsSync12, readFileSync: readFileSync16 } = await import("node:fs");
34150
+ const { join: join23 } = await import("node:path");
33738
34151
  await getDb3();
33739
34152
  const registry = new AgentRegistryAccessor(process.cwd());
33740
34153
  const credential = await registry.get(args.agentId);
@@ -33754,9 +34167,9 @@ var startCommand = defineCommand({
33754
34167
  }
33755
34168
  let profile = null;
33756
34169
  let cantValidation = null;
33757
- const cantPath = args.cant ?? join22(CLEO_DIR_NAME, AGENTS_SUBDIR, `${args.agentId}.cant`);
34170
+ const cantPath = args.cant ?? join23(CLEO_DIR_NAME, AGENTS_SUBDIR, `${args.agentId}.cant`);
33758
34171
  if (existsSync12(cantPath)) {
33759
- profile = readFileSync15(cantPath, "utf-8");
34172
+ profile = readFileSync16(cantPath, "utf-8");
33760
34173
  try {
33761
34174
  const cantModule = await import("@cleocode/cant");
33762
34175
  const validate = "validate" in cantModule ? cantModule.validate : null;
@@ -34280,7 +34693,7 @@ var workCommand = defineCommand({
34280
34693
  const { AgentRegistryAccessor, getDb: getDb3 } = await import("@cleocode/core/internal");
34281
34694
  const { createRuntime } = await import("@cleocode/runtime");
34282
34695
  const { existsSync: existsSync12 } = await import("node:fs");
34283
- const { join: join22 } = await import("node:path");
34696
+ const { join: join23 } = await import("node:path");
34284
34697
  const { execFile: execFile2 } = await import("node:child_process");
34285
34698
  const { promisify: promisify2 } = await import("node:util");
34286
34699
  const execFileAsync = promisify2(execFile2);
@@ -34300,7 +34713,7 @@ var workCommand = defineCommand({
34300
34713
  }
34301
34714
  await registry.update(args.agentId, { isActive: true });
34302
34715
  await registry.markUsed(args.agentId);
34303
- const cantPath = join22(CLEO_DIR_NAME, AGENTS_SUBDIR, `${args.agentId}.cant`);
34716
+ const cantPath = join23(CLEO_DIR_NAME, AGENTS_SUBDIR, `${args.agentId}.cant`);
34304
34717
  const hasProfile = existsSync12(cantPath);
34305
34718
  const runtime = await createRuntime(registry, {
34306
34719
  agentId: args.agentId,
@@ -35151,8 +35564,8 @@ var installCommand = defineCommand({
35151
35564
  async run({ args }) {
35152
35565
  let tempDir = null;
35153
35566
  try {
35154
- const { existsSync: existsSync12, mkdirSync: mkdirSync4, statSync, readdirSync: readdirSync4, copyFileSync } = await import("node:fs");
35155
- const { join: join22, basename: basename2, resolve: resolve5, extname } = await import("node:path");
35567
+ const { existsSync: existsSync12, mkdirSync: mkdirSync5, statSync, readdirSync: readdirSync4, copyFileSync } = await import("node:fs");
35568
+ const { join: join23, basename: basename2, resolve: resolve5, extname } = await import("node:path");
35156
35569
  const { tmpdir } = await import("node:os");
35157
35570
  const resolvedPath = resolve5(args.path);
35158
35571
  if (!existsSync12(resolvedPath)) {
@@ -35176,8 +35589,8 @@ var installCommand = defineCommand({
35176
35589
  cantPath = resolvedPath;
35177
35590
  } else if (stat2.isFile() && ext === ".cantz") {
35178
35591
  const { execFileSync: execFileSync6 } = await import("node:child_process");
35179
- tempDir = join22(tmpdir(), `cleo-agent-install-${Date.now()}`);
35180
- mkdirSync4(tempDir, { recursive: true });
35592
+ tempDir = join23(tmpdir(), `cleo-agent-install-${Date.now()}`);
35593
+ mkdirSync5(tempDir, { recursive: true });
35181
35594
  try {
35182
35595
  execFileSync6("unzip", ["-o", "-q", resolvedPath, "-d", tempDir], {
35183
35596
  encoding: "utf-8",
@@ -35198,7 +35611,7 @@ var installCommand = defineCommand({
35198
35611
  return;
35199
35612
  }
35200
35613
  const topLevel = readdirSync4(tempDir).filter(
35201
- (entry) => statSync(join22(tempDir, entry)).isDirectory()
35614
+ (entry) => statSync(join23(tempDir, entry)).isDirectory()
35202
35615
  );
35203
35616
  if (topLevel.length !== 1) {
35204
35617
  cliOutput(
@@ -35215,7 +35628,7 @@ var installCommand = defineCommand({
35215
35628
  return;
35216
35629
  }
35217
35630
  const agentName = topLevel[0];
35218
- const personaPath = join22(tempDir, agentName, "persona.cant");
35631
+ const personaPath = join23(tempDir, agentName, "persona.cant");
35219
35632
  if (!existsSync12(personaPath)) {
35220
35633
  cliOutput(
35221
35634
  {
@@ -35230,11 +35643,11 @@ var installCommand = defineCommand({
35230
35643
  process.exitCode = 6;
35231
35644
  return;
35232
35645
  }
35233
- cantPath = join22(tempDir, `${agentName}.cant`);
35646
+ cantPath = join23(tempDir, `${agentName}.cant`);
35234
35647
  copyFileSync(personaPath, cantPath);
35235
35648
  } else if (stat2.isDirectory()) {
35236
35649
  const agentName = basename2(resolvedPath);
35237
- const personaPath = join22(resolvedPath, "persona.cant");
35650
+ const personaPath = join23(resolvedPath, "persona.cant");
35238
35651
  if (!existsSync12(personaPath)) {
35239
35652
  cliOutput(
35240
35653
  {
@@ -35249,9 +35662,9 @@ var installCommand = defineCommand({
35249
35662
  process.exitCode = 6;
35250
35663
  return;
35251
35664
  }
35252
- tempDir = join22(tmpdir(), `cleo-agent-install-${Date.now()}`);
35253
- mkdirSync4(tempDir, { recursive: true });
35254
- cantPath = join22(tempDir, `${agentName}.cant`);
35665
+ tempDir = join23(tmpdir(), `cleo-agent-install-${Date.now()}`);
35666
+ mkdirSync5(tempDir, { recursive: true });
35667
+ cantPath = join23(tempDir, `${agentName}.cant`);
35255
35668
  copyFileSync(personaPath, cantPath);
35256
35669
  } else {
35257
35670
  cliOutput(
@@ -35379,7 +35792,7 @@ var packCommand = defineCommand({
35379
35792
  async run({ args }) {
35380
35793
  try {
35381
35794
  const { existsSync: existsSync12, statSync } = await import("node:fs");
35382
- const { resolve: resolve5, basename: basename2, dirname: dirname10 } = await import("node:path");
35795
+ const { resolve: resolve5, basename: basename2, dirname: dirname11 } = await import("node:path");
35383
35796
  const { execFileSync: execFileSync6 } = await import("node:child_process");
35384
35797
  const resolvedDir = resolve5(args.dir);
35385
35798
  if (!existsSync12(resolvedDir) || !statSync(resolvedDir).isDirectory()) {
@@ -35396,8 +35809,8 @@ var packCommand = defineCommand({
35396
35809
  process.exitCode = 4;
35397
35810
  return;
35398
35811
  }
35399
- const { join: join22 } = await import("node:path");
35400
- const personaPath = join22(resolvedDir, "persona.cant");
35812
+ const { join: join23 } = await import("node:path");
35813
+ const personaPath = join23(resolvedDir, "persona.cant");
35401
35814
  if (!existsSync12(personaPath)) {
35402
35815
  cliOutput(
35403
35816
  {
@@ -35415,7 +35828,7 @@ var packCommand = defineCommand({
35415
35828
  const agentName = basename2(resolvedDir);
35416
35829
  const archiveName = `${agentName}.cantz`;
35417
35830
  const archivePath = resolve5(archiveName);
35418
- const parentDir = dirname10(resolvedDir);
35831
+ const parentDir = dirname11(resolvedDir);
35419
35832
  try {
35420
35833
  execFileSync6("zip", ["-r", archivePath, agentName], {
35421
35834
  cwd: parentDir,
@@ -35445,7 +35858,7 @@ var packCommand = defineCommand({
35445
35858
  if (entry.isFile()) {
35446
35859
  fileCount++;
35447
35860
  } else if (entry.isDirectory()) {
35448
- countFiles(join22(dirPath, entry.name));
35861
+ countFiles(join23(dirPath, entry.name));
35449
35862
  }
35450
35863
  }
35451
35864
  };
@@ -35514,8 +35927,8 @@ var createCommand = defineCommand({
35514
35927
  },
35515
35928
  async run({ args }) {
35516
35929
  try {
35517
- const { existsSync: existsSync12, mkdirSync: mkdirSync4, writeFileSync: writeFileSync4 } = await import("node:fs");
35518
- const { join: join22 } = await import("node:path");
35930
+ const { existsSync: existsSync12, mkdirSync: mkdirSync5, writeFileSync: writeFileSync5 } = await import("node:fs");
35931
+ const { join: join23 } = await import("node:path");
35519
35932
  const { homedir: homedir6 } = await import("node:os");
35520
35933
  const name = args.name;
35521
35934
  const role = args.role;
@@ -35575,12 +35988,12 @@ var createCommand = defineCommand({
35575
35988
  let targetRoot;
35576
35989
  if (isGlobal) {
35577
35990
  const home = homedir6();
35578
- const xdgData = process.env["XDG_DATA_HOME"] ?? join22(home, ".local", "share");
35579
- targetRoot = join22(xdgData, "cleo", "cant", "agents");
35991
+ const xdgData = process.env["XDG_DATA_HOME"] ?? join23(home, ".local", "share");
35992
+ targetRoot = join23(xdgData, "cleo", "cant", "agents");
35580
35993
  } else {
35581
- targetRoot = join22(process.cwd(), CLEO_DIR_NAME, CANT_AGENTS_SUBDIR);
35994
+ targetRoot = join23(process.cwd(), CLEO_DIR_NAME, CANT_AGENTS_SUBDIR);
35582
35995
  }
35583
- const agentDir = join22(targetRoot, name);
35996
+ const agentDir = join23(targetRoot, name);
35584
35997
  if (existsSync12(agentDir)) {
35585
35998
  cliOutput(
35586
35999
  {
@@ -35596,7 +36009,7 @@ var createCommand = defineCommand({
35596
36009
  process.exitCode = 6;
35597
36010
  return;
35598
36011
  }
35599
- mkdirSync4(agentDir, { recursive: true });
36012
+ mkdirSync5(agentDir, { recursive: true });
35600
36013
  const personaContent = generatePersonaCant({
35601
36014
  name,
35602
36015
  role,
@@ -35605,29 +36018,29 @@ var createCommand = defineCommand({
35605
36018
  domain,
35606
36019
  parent
35607
36020
  });
35608
- writeFileSync4(join22(agentDir, "persona.cant"), personaContent, "utf-8");
36021
+ writeFileSync5(join23(agentDir, "persona.cant"), personaContent, "utf-8");
35609
36022
  const manifest = generateManifest({ name, role, tier, domain });
35610
- writeFileSync4(
35611
- join22(agentDir, "manifest.json"),
36023
+ writeFileSync5(
36024
+ join23(agentDir, "manifest.json"),
35612
36025
  `${JSON.stringify(manifest, null, 2)}
35613
36026
  `,
35614
36027
  "utf-8"
35615
36028
  );
35616
36029
  const createdFiles = [
35617
- join22(agentDir, "persona.cant"),
35618
- join22(agentDir, "manifest.json")
36030
+ join23(agentDir, "persona.cant"),
36031
+ join23(agentDir, "manifest.json")
35619
36032
  ];
35620
36033
  if (team) {
35621
36034
  const teamConfigContent = generateTeamConfig(name, role, team);
35622
- writeFileSync4(join22(agentDir, "team-config.cant"), teamConfigContent, "utf-8");
35623
- createdFiles.push(join22(agentDir, "team-config.cant"));
36035
+ writeFileSync5(join23(agentDir, "team-config.cant"), teamConfigContent, "utf-8");
36036
+ createdFiles.push(join23(agentDir, "team-config.cant"));
35624
36037
  }
35625
36038
  if (seedBrain) {
35626
- const expertiseDir = join22(agentDir, "expertise");
35627
- mkdirSync4(expertiseDir, { recursive: true });
36039
+ const expertiseDir = join23(agentDir, "expertise");
36040
+ mkdirSync5(expertiseDir, { recursive: true });
35628
36041
  const seedContent = generateMentalModelSeed(name, role, domain);
35629
- writeFileSync4(join22(expertiseDir, "mental-model-seed.md"), seedContent, "utf-8");
35630
- createdFiles.push(join22(expertiseDir, "mental-model-seed.md"));
36042
+ writeFileSync5(join23(expertiseDir, "mental-model-seed.md"), seedContent, "utf-8");
36043
+ createdFiles.push(join23(expertiseDir, "mental-model-seed.md"));
35631
36044
  try {
35632
36045
  const { execFile: execFile2 } = await import("node:child_process");
35633
36046
  const { promisify: promisify2 } = await import("node:util");
@@ -35725,8 +36138,8 @@ var mintCommand = defineCommand({
35725
36138
  },
35726
36139
  async run({ args }) {
35727
36140
  try {
35728
- const { existsSync: existsSync12, readFileSync: readFileSync15, mkdirSync: mkdirSync4 } = await import("node:fs");
35729
- const { resolve: resolve5, join: join22 } = await import("node:path");
36141
+ const { existsSync: existsSync12, readFileSync: readFileSync16, mkdirSync: mkdirSync5 } = await import("node:fs");
36142
+ const { resolve: resolve5, join: join23 } = await import("node:path");
35730
36143
  const specPath = resolve5(args.spec);
35731
36144
  if (!existsSync12(specPath)) {
35732
36145
  const errEnv = {
@@ -35743,10 +36156,10 @@ var mintCommand = defineCommand({
35743
36156
  process.exitCode = 4;
35744
36157
  return;
35745
36158
  }
35746
- const specContent = readFileSync15(specPath, "utf-8");
36159
+ const specContent = readFileSync16(specPath, "utf-8");
35747
36160
  const projectRoot = process.cwd();
35748
- const outputDir = args["output-dir"] ? resolve5(args["output-dir"]) : join22(projectRoot, ".cleo", "cant", "agents");
35749
- mkdirSync4(outputDir, { recursive: true });
36161
+ const outputDir = args["output-dir"] ? resolve5(args["output-dir"]) : join23(projectRoot, ".cleo", "cant", "agents");
36162
+ mkdirSync5(outputDir, { recursive: true });
35750
36163
  if (args["dry-run"]) {
35751
36164
  const preview = {
35752
36165
  success: true,
@@ -37753,7 +38166,7 @@ var briefingCommand = defineCommand({
37753
38166
  // packages/cleo/src/cli/commands/bug.ts
37754
38167
  import { existsSync as existsSync7 } from "node:fs";
37755
38168
  import { appendFile as appendFile2, mkdir as mkdir2, readFile as readFile2 } from "node:fs/promises";
37756
- import { dirname as dirname4, join as join9 } from "node:path";
38169
+ import { dirname as dirname5, join as join10 } from "node:path";
37757
38170
  import { getCleoDirAbsolute as getCleoDirAbsolute2, getCleoIdentity, getConfigPath, signAuditLine } from "@cleocode/core";
37758
38171
  init_cli();
37759
38172
  var SEVERITY_MAP = {
@@ -37806,8 +38219,8 @@ async function appendSignedBugSeverity(record) {
37806
38219
  const sig = await signAuditLine(id, canonical);
37807
38220
  const line = `${JSON.stringify({ ...full, _sig: sig })}
37808
38221
  `;
37809
- const auditPath = join9(getCleoDirAbsolute2(), "audit", "bug-severity.jsonl");
37810
- await mkdir2(dirname4(auditPath), { recursive: true });
38222
+ const auditPath = join10(getCleoDirAbsolute2(), "audit", "bug-severity.jsonl");
38223
+ await mkdir2(dirname5(auditPath), { recursive: true });
37811
38224
  await appendFile2(auditPath, line, { encoding: "utf-8" });
37812
38225
  }
37813
38226
  var bugCommand = defineCommand({
@@ -37919,8 +38332,8 @@ var cancelCommand = defineCommand({
37919
38332
  });
37920
38333
 
37921
38334
  // packages/cleo/src/cli/commands/cant.ts
37922
- import { existsSync as existsSync8, mkdirSync, readFileSync as readFileSync8, writeFileSync } from "node:fs";
37923
- import { dirname as dirname5, isAbsolute, join as join10, resolve as resolve3 } from "node:path";
38335
+ import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "node:fs";
38336
+ import { dirname as dirname6, isAbsolute, join as join11, resolve as resolve3 } from "node:path";
37924
38337
  init_renderers();
37925
38338
  function resolveFilePath(file) {
37926
38339
  return isAbsolute(file) ? file : resolve3(process.cwd(), file);
@@ -38070,7 +38483,7 @@ var cantMigrateCommand = defineCommand({
38070
38483
  if (!ensureExists(filePath, "cant.migrate")) return;
38071
38484
  try {
38072
38485
  const mod = await loadMigrateEngine();
38073
- const content = readFileSync8(filePath, "utf-8");
38486
+ const content = readFileSync9(filePath, "utf-8");
38074
38487
  const result = mod.migrateMarkdown(content, filePath, {
38075
38488
  write: isWrite,
38076
38489
  verbose: isVerbose,
@@ -38080,9 +38493,9 @@ var cantMigrateCommand = defineCommand({
38080
38493
  const projectRoot = process.cwd();
38081
38494
  let written = 0;
38082
38495
  for (const outputFile of result.outputFiles) {
38083
- const outputPath = isAbsolute(outputFile.path) ? outputFile.path : join10(projectRoot, outputFile.path);
38084
- mkdirSync(dirname5(outputPath), { recursive: true });
38085
- writeFileSync(outputPath, outputFile.content, "utf-8");
38496
+ const outputPath = isAbsolute(outputFile.path) ? outputFile.path : join11(projectRoot, outputFile.path);
38497
+ mkdirSync2(dirname6(outputPath), { recursive: true });
38498
+ writeFileSync2(outputPath, outputFile.content, "utf-8");
38086
38499
  written++;
38087
38500
  }
38088
38501
  cliOutput(
@@ -38130,7 +38543,7 @@ var cantCommand = defineCommand({
38130
38543
  });
38131
38544
 
38132
38545
  // packages/cleo/src/cli/commands/chain.ts
38133
- import { readFileSync as readFileSync9 } from "node:fs";
38546
+ import { readFileSync as readFileSync10 } from "node:fs";
38134
38547
  init_cli();
38135
38548
  var showCommand3 = defineCommand({
38136
38549
  meta: { name: "show", description: "Show details for a WarpChain definition" },
@@ -38167,7 +38580,7 @@ var addCommand3 = defineCommand({
38167
38580
  }
38168
38581
  },
38169
38582
  async run({ args }) {
38170
- const chainJson = JSON.parse(readFileSync9(args.file, "utf-8"));
38583
+ const chainJson = JSON.parse(readFileSync10(args.file, "utf-8"));
38171
38584
  await dispatchFromCli(
38172
38585
  "mutate",
38173
38586
  "pipeline",
@@ -38336,10 +38749,10 @@ var checkChainValidateCommand = defineCommand({
38336
38749
  }
38337
38750
  },
38338
38751
  async run({ args }) {
38339
- const { readFileSync: readFileSync15 } = await import("node:fs");
38752
+ const { readFileSync: readFileSync16 } = await import("node:fs");
38340
38753
  let chain;
38341
38754
  try {
38342
- chain = JSON.parse(readFileSync15(args.file, "utf8"));
38755
+ chain = JSON.parse(readFileSync16(args.file, "utf8"));
38343
38756
  } catch (err) {
38344
38757
  const message = err instanceof Error ? err.message : String(err);
38345
38758
  console.error(`Failed to read or parse chain file: ${message}`);
@@ -38679,9 +39092,9 @@ var codeCommand = defineCommand({
38679
39092
  async run({ args }) {
38680
39093
  await requireTreeSitter();
38681
39094
  const { smartOutline } = await import("@cleocode/core/internal");
38682
- const { join: join22 } = await import("node:path");
39095
+ const { join: join23 } = await import("node:path");
38683
39096
  const root = process.cwd();
38684
- const absPath = args.file.startsWith("/") ? args.file : join22(root, args.file);
39097
+ const absPath = args.file.startsWith("/") ? args.file : join23(root, args.file);
38685
39098
  const result = smartOutline(absPath, root);
38686
39099
  if (result.errors.length > 0 && result.symbols.length === 0) {
38687
39100
  console.error(`Error: ${result.errors.join(", ")}`);
@@ -38772,9 +39185,9 @@ var codeCommand = defineCommand({
38772
39185
  async run({ args }) {
38773
39186
  await requireTreeSitter();
38774
39187
  const { smartUnfold } = await import("@cleocode/core/internal");
38775
- const { join: join22 } = await import("node:path");
39188
+ const { join: join23 } = await import("node:path");
38776
39189
  const root = process.cwd();
38777
- const absPath = args.file.startsWith("/") ? args.file : join22(root, args.file);
39190
+ const absPath = args.file.startsWith("/") ? args.file : join23(root, args.file);
38778
39191
  const result = smartUnfold(absPath, args.symbol, root);
38779
39192
  if (!result.found) {
38780
39193
  console.error(`Symbol "${args.symbol}" not found in ${args.file}`);
@@ -39817,7 +40230,7 @@ var currentCommand = defineCommand({
39817
40230
 
39818
40231
  // packages/cleo/src/cli/commands/daemon.ts
39819
40232
  import { homedir as homedir2 } from "node:os";
39820
- import { join as join11 } from "node:path";
40233
+ import { join as join12 } from "node:path";
39821
40234
  import { getGCDaemonStatus, spawnGCDaemon, stopGCDaemon } from "@cleocode/core/gc/daemon.js";
39822
40235
  async function showDaemonStatus(cleoDir, json2) {
39823
40236
  try {
@@ -39870,7 +40283,7 @@ var startCommand3 = defineCommand({
39870
40283
  }
39871
40284
  },
39872
40285
  async run({ args }) {
39873
- const cleoDir = args["cleo-dir"] ?? join11(homedir2(), ".cleo");
40286
+ const cleoDir = args["cleo-dir"] ?? join12(homedir2(), ".cleo");
39874
40287
  const jsonMode = args.json ?? false;
39875
40288
  try {
39876
40289
  const status = await getGCDaemonStatus(cleoDir);
@@ -39901,7 +40314,7 @@ var startCommand3 = defineCommand({
39901
40314
  } else {
39902
40315
  process.stdout.write(`GC daemon started (PID ${pid})
39903
40316
  `);
39904
- process.stdout.write(`Logs: ${join11(cleoDir, "logs", "gc.log")}
40317
+ process.stdout.write(`Logs: ${join12(cleoDir, "logs", "gc.log")}
39905
40318
  `);
39906
40319
  }
39907
40320
  } catch (err) {
@@ -39930,7 +40343,7 @@ var stopCommand3 = defineCommand({
39930
40343
  }
39931
40344
  },
39932
40345
  async run({ args }) {
39933
- const cleoDir = args["cleo-dir"] ?? join11(homedir2(), ".cleo");
40346
+ const cleoDir = args["cleo-dir"] ?? join12(homedir2(), ".cleo");
39934
40347
  const jsonMode = args.json ?? false;
39935
40348
  try {
39936
40349
  const stopResult = await stopGCDaemon(cleoDir);
@@ -39976,7 +40389,7 @@ var statusCommand4 = defineCommand({
39976
40389
  }
39977
40390
  },
39978
40391
  async run({ args }) {
39979
- const cleoDir = args["cleo-dir"] ?? join11(homedir2(), ".cleo");
40392
+ const cleoDir = args["cleo-dir"] ?? join12(homedir2(), ".cleo");
39980
40393
  await showDaemonStatus(cleoDir, args.json ?? false);
39981
40394
  }
39982
40395
  });
@@ -40002,7 +40415,7 @@ var daemonCommand = defineCommand({
40002
40415
  },
40003
40416
  async run({ args, cmd, rawArgs }) {
40004
40417
  if (isSubCommandDispatch(rawArgs, cmd.subCommands)) return;
40005
- const cleoDir = args["cleo-dir"] ?? join11(homedir2(), ".cleo");
40418
+ const cleoDir = args["cleo-dir"] ?? join12(homedir2(), ".cleo");
40006
40419
  await showDaemonStatus(cleoDir, args.json ?? false);
40007
40420
  }
40008
40421
  });
@@ -40353,17 +40766,17 @@ var detectCommand2 = defineCommand({
40353
40766
 
40354
40767
  // packages/cleo/src/cli/commands/detect-drift.ts
40355
40768
  init_src();
40356
- import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync10 } from "node:fs";
40357
- import { dirname as dirname6, join as join12 } from "node:path";
40769
+ import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync11 } from "node:fs";
40770
+ import { dirname as dirname7, join as join13 } from "node:path";
40358
40771
  init_paths();
40359
40772
  init_renderers();
40360
40773
  function findProjectRoot() {
40361
40774
  let currentDir = process.cwd();
40362
40775
  while (currentDir !== "/") {
40363
- if (existsSync9(join12(currentDir, "package.json"))) {
40776
+ if (existsSync9(join13(currentDir, "package.json"))) {
40364
40777
  return currentDir;
40365
40778
  }
40366
- const parent = dirname6(currentDir);
40779
+ const parent = dirname7(currentDir);
40367
40780
  if (parent === currentDir) break;
40368
40781
  currentDir = parent;
40369
40782
  }
@@ -40376,11 +40789,11 @@ var detectDriftCommand = defineCommand({
40376
40789
  },
40377
40790
  async run() {
40378
40791
  const projectRoot = findProjectRoot();
40379
- const isCleoRepo = existsSync9(join12(projectRoot, "packages", "cleo", "src"));
40380
- const cleoSrcRoot = isCleoRepo ? join12(projectRoot, "packages", "cleo", "src") : join12(projectRoot, "src");
40792
+ const isCleoRepo = existsSync9(join13(projectRoot, "packages", "cleo", "src"));
40793
+ const cleoSrcRoot = isCleoRepo ? join13(projectRoot, "packages", "cleo", "src") : join13(projectRoot, "src");
40381
40794
  const safeRead = (filePath) => {
40382
40795
  try {
40383
- return readFileSync10(filePath, "utf-8");
40796
+ return readFileSync11(filePath, "utf-8");
40384
40797
  } catch {
40385
40798
  return "";
40386
40799
  }
@@ -40391,7 +40804,7 @@ var detectDriftCommand = defineCommand({
40391
40804
  checks: [],
40392
40805
  recommendations: []
40393
40806
  };
40394
- const injPath = join12(projectRoot, CLEO_DIR_NAME, TEMPLATES_SUBDIR, CLEO_INJECTION_MD);
40807
+ const injPath = join13(projectRoot, CLEO_DIR_NAME, TEMPLATES_SUBDIR, CLEO_INJECTION_MD);
40395
40808
  if (existsSync9(injPath)) {
40396
40809
  const content = safeRead(injPath);
40397
40810
  userResult.checks.push({
@@ -40443,9 +40856,9 @@ var detectDriftCommand = defineCommand({
40443
40856
  }
40444
40857
  };
40445
40858
  try {
40446
- const specPath = join12(projectRoot, "docs", "specs", "CLEO-OPERATION-CONSTITUTION.md");
40447
- const registryPath = join12(cleoSrcRoot, "dispatch", "registry.ts");
40448
- const dispatchDomainsDir = join12(cleoSrcRoot, "dispatch", "domains");
40859
+ const specPath = join13(projectRoot, "docs", "specs", "CLEO-OPERATION-CONSTITUTION.md");
40860
+ const registryPath = join13(cleoSrcRoot, "dispatch", "registry.ts");
40861
+ const dispatchDomainsDir = join13(cleoSrcRoot, "dispatch", "domains");
40449
40862
  if (!existsSync9(specPath)) {
40450
40863
  addCheck("Gateway-to-spec sync", "fail", "CLEO-OPERATION-CONSTITUTION.md missing", [
40451
40864
  {
@@ -40514,8 +40927,8 @@ var detectDriftCommand = defineCommand({
40514
40927
  ]);
40515
40928
  }
40516
40929
  try {
40517
- const cliDir = join12(cleoSrcRoot, "cli", "commands");
40518
- const coreDir = isCleoRepo ? join12(projectRoot, "packages", "core", "src") : join12(projectRoot, "src", "core");
40930
+ const cliDir = join13(cleoSrcRoot, "cli", "commands");
40931
+ const coreDir = isCleoRepo ? join13(projectRoot, "packages", "core", "src") : join13(projectRoot, "src", "core");
40519
40932
  if (!existsSync9(cliDir)) {
40520
40933
  addCheck("CLI-to-core sync", "fail", "CLI commands directory missing", [
40521
40934
  {
@@ -40542,7 +40955,7 @@ var detectDriftCommand = defineCommand({
40542
40955
  addCheck("CLI-to-core sync", "fail", `Error: ${getErrorMessage(e)}`);
40543
40956
  }
40544
40957
  try {
40545
- const domainsDir = join12(cleoSrcRoot, "dispatch", "domains");
40958
+ const domainsDir = join13(cleoSrcRoot, "dispatch", "domains");
40546
40959
  if (!existsSync9(domainsDir)) {
40547
40960
  addCheck("Domain handler coverage", "fail", "Dispatch domains directory missing", [
40548
40961
  {
@@ -40560,7 +40973,7 @@ var detectDriftCommand = defineCommand({
40560
40973
  addCheck("Domain handler coverage", "fail", `Error: ${getErrorMessage(e)}`);
40561
40974
  }
40562
40975
  try {
40563
- const matrixPath = join12(cleoSrcRoot, "dispatch", "lib", "capability-matrix.ts");
40976
+ const matrixPath = join13(cleoSrcRoot, "dispatch", "lib", "capability-matrix.ts");
40564
40977
  if (!existsSync9(matrixPath)) {
40565
40978
  addCheck("Capability matrix", "fail", "Capability matrix missing", [
40566
40979
  {
@@ -40577,7 +40990,7 @@ var detectDriftCommand = defineCommand({
40577
40990
  addCheck("Capability matrix", "fail", `Error: ${getErrorMessage(e)}`);
40578
40991
  }
40579
40992
  try {
40580
- const schemaPath = join12(projectRoot, "src", "store", "schema.ts");
40993
+ const schemaPath = join13(projectRoot, "src", "store", "schema.ts");
40581
40994
  if (!existsSync9(schemaPath)) {
40582
40995
  addCheck("Schema validation", "fail", "Schema definition missing", [
40583
40996
  {
@@ -40612,8 +41025,8 @@ var detectDriftCommand = defineCommand({
40612
41025
  addCheck("Schema validation", "fail", `Error: ${getErrorMessage(e)}`);
40613
41026
  }
40614
41027
  try {
40615
- const visionPath = join12(projectRoot, "docs", "concepts", "CLEO-VISION.md");
40616
- const specPath = join12(projectRoot, "docs", "specs", "CLEO-PORTABLE-PROJECT-BRAIN-SPEC.md");
41028
+ const visionPath = join13(projectRoot, "docs", "concepts", "CLEO-VISION.md");
41029
+ const specPath = join13(projectRoot, "docs", "specs", "CLEO-PORTABLE-PROJECT-BRAIN-SPEC.md");
40617
41030
  const issues = [];
40618
41031
  if (!existsSync9(visionPath)) {
40619
41032
  issues.push({
@@ -40668,7 +41081,7 @@ var detectDriftCommand = defineCommand({
40668
41081
  addCheck("Canonical identity", "fail", `Error: ${getErrorMessage(e)}`);
40669
41082
  }
40670
41083
  try {
40671
- const injectionPath = join12(projectRoot, CLEO_DIR_NAME, TEMPLATES_SUBDIR, CLEO_INJECTION_MD);
41084
+ const injectionPath = join13(projectRoot, CLEO_DIR_NAME, TEMPLATES_SUBDIR, CLEO_INJECTION_MD);
40672
41085
  if (!existsSync9(injectionPath)) {
40673
41086
  addCheck("Agent injection", "fail", "Agent injection template missing", [
40674
41087
  {
@@ -40698,7 +41111,7 @@ var detectDriftCommand = defineCommand({
40698
41111
  addCheck("Agent injection", "fail", `Error: ${getErrorMessage(e)}`);
40699
41112
  }
40700
41113
  try {
40701
- const exitCodesPath = join12(cleoSrcRoot, "dispatch", "lib", "exit-codes.ts");
41114
+ const exitCodesPath = join13(cleoSrcRoot, "dispatch", "lib", "exit-codes.ts");
40702
41115
  if (!existsSync9(exitCodesPath)) {
40703
41116
  addCheck("Exit codes", "fail", "Exit codes definition missing", [
40704
41117
  {
@@ -40831,7 +41244,7 @@ var diagnosticsCommand = defineCommand({
40831
41244
  // packages/cleo/src/cli/commands/docs.ts
40832
41245
  init_src();
40833
41246
  import { mkdir as mkdir3, readdir, readFile as readFile3, writeFile } from "node:fs/promises";
40834
- import { dirname as dirname7, isAbsolute as isAbsolute2, join as join13, resolve as resolve4 } from "node:path";
41247
+ import { dirname as dirname8, isAbsolute as isAbsolute2, join as join14, resolve as resolve4 } from "node:path";
40835
41248
  import {
40836
41249
  buildDocsGraph,
40837
41250
  CleoError as CleoError3,
@@ -40849,7 +41262,7 @@ import {
40849
41262
  init_cli();
40850
41263
  init_renderers();
40851
41264
  async function getScriptNames(projectRoot) {
40852
- const scriptsDir = join13(projectRoot, "scripts");
41265
+ const scriptsDir = join14(projectRoot, "scripts");
40853
41266
  try {
40854
41267
  const files = await readdir(scriptsDir);
40855
41268
  return files.filter((f) => f.endsWith(".sh")).map((f) => f.replace(".sh", "")).sort();
@@ -40858,7 +41271,7 @@ async function getScriptNames(projectRoot) {
40858
41271
  }
40859
41272
  }
40860
41273
  async function getIndexedCommands(projectRoot) {
40861
- const indexPath = join13(projectRoot, "docs", "commands", "COMMANDS-INDEX.json");
41274
+ const indexPath = join14(projectRoot, "docs", "commands", "COMMANDS-INDEX.json");
40862
41275
  const index = await readJson(indexPath);
40863
41276
  if (!index) return [];
40864
41277
  return index.commands.map((c) => c.name).sort();
@@ -40891,7 +41304,7 @@ async function runGapCheck(_projectRoot, filterId) {
40891
41304
  const reviewFiles = files.filter((f) => f.endsWith(".md"));
40892
41305
  for (const file of reviewFiles) {
40893
41306
  if (filterId && !file.includes(filterId)) continue;
40894
- const filePath = join13(reviewDir, file);
41307
+ const filePath = join14(reviewDir, file);
40895
41308
  const content = await readFile3(filePath, "utf-8");
40896
41309
  const taskMatch = file.match(/^(T\d+)/);
40897
41310
  const taskId = taskMatch ? taskMatch[1] : "UNKNOWN";
@@ -41138,7 +41551,7 @@ var exportCommand4 = defineCommand({
41138
41551
  let writtenPath;
41139
41552
  if (typeof args.out === "string" && args.out.length > 0) {
41140
41553
  const outPath = isAbsolute2(args.out) ? args.out : resolve4(projectRoot, args.out);
41141
- await mkdir3(dirname7(outPath), { recursive: true });
41554
+ await mkdir3(dirname8(outPath), { recursive: true });
41142
41555
  await writeFile(outPath, result.markdown, "utf8");
41143
41556
  writtenPath = outPath;
41144
41557
  }
@@ -41253,7 +41666,7 @@ var mergeCommand = defineCommand({
41253
41666
  });
41254
41667
  if (typeof args.out === "string" && args.out.length > 0) {
41255
41668
  const outPath = isAbsolute2(args.out) ? args.out : resolve4(projectRoot, args.out);
41256
- await mkdir3(dirname7(outPath), { recursive: true });
41669
+ await mkdir3(dirname8(outPath), { recursive: true });
41257
41670
  await writeFile(outPath, result.merged, "utf8");
41258
41671
  process.stderr.write(`Wrote merged content to ${outPath}
41259
41672
  `);
@@ -41325,7 +41738,7 @@ var graphCommand = defineCommand({
41325
41738
  }
41326
41739
  if (typeof args.out === "string" && args.out.length > 0) {
41327
41740
  const outPath = isAbsolute2(args.out) ? args.out : resolve4(projectRoot, args.out);
41328
- await mkdir3(dirname7(outPath), { recursive: true });
41741
+ await mkdir3(dirname8(outPath), { recursive: true });
41329
41742
  await writeFile(outPath, output, "utf8");
41330
41743
  process.stderr.write(`Wrote graph to ${outPath}
41331
41744
  `);
@@ -42249,7 +42662,7 @@ var findCommand2 = defineCommand({
42249
42662
 
42250
42663
  // packages/cleo/src/cli/commands/gc.ts
42251
42664
  import { homedir as homedir3 } from "node:os";
42252
- import { join as join14 } from "node:path";
42665
+ import { join as join15 } from "node:path";
42253
42666
  import { runGC } from "@cleocode/core/gc/runner.js";
42254
42667
  import { readGCState } from "@cleocode/core/gc/state.js";
42255
42668
  function formatBytes(bytes) {
@@ -42281,7 +42694,7 @@ var runCommand2 = defineCommand({
42281
42694
  }
42282
42695
  },
42283
42696
  async run({ args }) {
42284
- const cleoDir = args["cleo-dir"] ?? join14(homedir3(), ".cleo");
42697
+ const cleoDir = args["cleo-dir"] ?? join15(homedir3(), ".cleo");
42285
42698
  const dryRun = args["dry-run"];
42286
42699
  try {
42287
42700
  const gcResult = await runGC({ cleoDir, dryRun });
@@ -42336,8 +42749,8 @@ var statusCommand6 = defineCommand({
42336
42749
  }
42337
42750
  },
42338
42751
  async run({ args }) {
42339
- const cleoDir = args["cleo-dir"] ?? join14(homedir3(), ".cleo");
42340
- const statePath = join14(cleoDir, "gc-state.json");
42752
+ const cleoDir = args["cleo-dir"] ?? join15(homedir3(), ".cleo");
42753
+ const statePath = join15(cleoDir, "gc-state.json");
42341
42754
  try {
42342
42755
  const state = await readGCState(statePath);
42343
42756
  const result = { success: true, data: state };
@@ -42396,14 +42809,14 @@ var gcCommand = defineCommand({
42396
42809
  // packages/cleo/src/cli/commands/generate-changelog.ts
42397
42810
  init_src();
42398
42811
  import { execFileSync as execFileSync3 } from "node:child_process";
42399
- import { existsSync as existsSync10, mkdirSync as mkdirSync2, readFileSync as readFileSync11, writeFileSync as writeFileSync2 } from "node:fs";
42400
- import { dirname as dirname8, join as join15 } from "node:path";
42812
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync3 } from "node:fs";
42813
+ import { dirname as dirname9, join as join16 } from "node:path";
42401
42814
  import { CleoError as CleoError4, formatError as formatError6, getConfigPath as getConfigPath2, getProjectRoot as getProjectRoot21 } from "@cleocode/core";
42402
42815
  init_renderers();
42403
42816
  function getChangelogSource(cwd) {
42404
42817
  const configPath = getConfigPath2(cwd);
42405
42818
  try {
42406
- const config = JSON.parse(readFileSync11(configPath, "utf-8"));
42819
+ const config = JSON.parse(readFileSync12(configPath, "utf-8"));
42407
42820
  return config?.release?.changelog?.source ?? "CHANGELOG.md";
42408
42821
  } catch {
42409
42822
  return "CHANGELOG.md";
@@ -42412,7 +42825,7 @@ function getChangelogSource(cwd) {
42412
42825
  function getEnabledPlatforms(cwd) {
42413
42826
  const configPath = getConfigPath2(cwd);
42414
42827
  try {
42415
- const config = JSON.parse(readFileSync11(configPath, "utf-8"));
42828
+ const config = JSON.parse(readFileSync12(configPath, "utf-8"));
42416
42829
  const outputs = config?.release?.changelog?.outputs ?? [];
42417
42830
  return outputs.filter((o) => o.enabled);
42418
42831
  } catch {
@@ -42556,11 +42969,11 @@ var generateChangelogCommand = defineCommand({
42556
42969
  const targetPlatform = args.platform;
42557
42970
  const dryRun = args["dry-run"] === true;
42558
42971
  const sourceFile = getChangelogSource();
42559
- const sourcePath = join15(getProjectRoot21(), sourceFile);
42972
+ const sourcePath = join16(getProjectRoot21(), sourceFile);
42560
42973
  if (!existsSync10(sourcePath)) {
42561
42974
  throw new CleoError4(4 /* NOT_FOUND */, `Changelog source not found: ${sourcePath}`);
42562
42975
  }
42563
- const sourceContent = readFileSync11(sourcePath, "utf-8");
42976
+ const sourceContent = readFileSync12(sourcePath, "utf-8");
42564
42977
  const repoSlug = getGitHubRepoSlug();
42565
42978
  const results = [];
42566
42979
  if (targetPlatform) {
@@ -42569,9 +42982,9 @@ var generateChangelogCommand = defineCommand({
42569
42982
  const outputPath = platformConfig?.path ?? getDefaultOutputPath(targetPlatform);
42570
42983
  const content = generateForPlatform(targetPlatform, sourceContent, repoSlug, limit);
42571
42984
  if (!dryRun) {
42572
- const fullPath = join15(getProjectRoot21(), outputPath);
42573
- mkdirSync2(dirname8(fullPath), { recursive: true });
42574
- writeFileSync2(fullPath, content, "utf-8");
42985
+ const fullPath = join16(getProjectRoot21(), outputPath);
42986
+ mkdirSync3(dirname9(fullPath), { recursive: true });
42987
+ writeFileSync3(fullPath, content, "utf-8");
42575
42988
  }
42576
42989
  results.push({ platform: targetPlatform, path: outputPath, written: !dryRun });
42577
42990
  } else {
@@ -42590,9 +43003,9 @@ var generateChangelogCommand = defineCommand({
42590
43003
  limit
42591
43004
  );
42592
43005
  if (!dryRun) {
42593
- const fullPath = join15(getProjectRoot21(), platformConfig.path);
42594
- mkdirSync2(dirname8(fullPath), { recursive: true });
42595
- writeFileSync2(fullPath, content, "utf-8");
43006
+ const fullPath = join16(getProjectRoot21(), platformConfig.path);
43007
+ mkdirSync3(dirname9(fullPath), { recursive: true });
43008
+ writeFileSync3(fullPath, content, "utf-8");
42596
43009
  }
42597
43010
  results.push({
42598
43011
  platform: platformConfig.platform,
@@ -44000,9 +44413,9 @@ var mapCommand = defineCommand({
44000
44413
 
44001
44414
  // packages/cleo/src/cli/commands/memory.ts
44002
44415
  import { createHash as createHash3 } from "node:crypto";
44003
- import { existsSync as existsSync11, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync3 } from "node:fs";
44416
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, readdirSync as readdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "node:fs";
44004
44417
  import { homedir as homedir4 } from "node:os";
44005
- import { join as join16 } from "node:path";
44418
+ import { join as join17 } from "node:path";
44006
44419
  import {
44007
44420
  getBrainDb as getBrainDb2,
44008
44421
  getBrainNativeDb as getBrainNativeDb3,
@@ -44046,7 +44459,7 @@ ${body}`).digest("hex").slice(0, 16);
44046
44459
  function loadImportHashes(stateFile) {
44047
44460
  try {
44048
44461
  if (!existsSync11(stateFile)) return /* @__PURE__ */ new Set();
44049
- const raw = readFileSync12(stateFile, "utf-8");
44462
+ const raw = readFileSync13(stateFile, "utf-8");
44050
44463
  const parsed = JSON.parse(raw);
44051
44464
  return new Set(parsed.hashes);
44052
44465
  } catch {
@@ -44055,8 +44468,8 @@ function loadImportHashes(stateFile) {
44055
44468
  }
44056
44469
  function saveImportHashes(stateFile, hashes) {
44057
44470
  const dir = stateFile.slice(0, stateFile.lastIndexOf("/"));
44058
- if (!existsSync11(dir)) mkdirSync3(dir, { recursive: true });
44059
- writeFileSync3(stateFile, JSON.stringify({ hashes: [...hashes] }, null, 2), "utf-8");
44471
+ if (!existsSync11(dir)) mkdirSync4(dir, { recursive: true });
44472
+ writeFileSync4(stateFile, JSON.stringify({ hashes: [...hashes] }, null, 2), "utf-8");
44060
44473
  }
44061
44474
  var storeCommand = defineCommand({
44062
44475
  meta: { name: "store", description: "Store a pattern or learning to BRAIN memory" },
@@ -45300,11 +45713,11 @@ var importCommand3 = defineCommand({
45300
45713
  }
45301
45714
  },
45302
45715
  async run({ args }) {
45303
- const sourceDir = args.from ?? join16(homedir4(), ".claude", "projects", "-mnt-projects-cleocode", "memory");
45716
+ const sourceDir = args.from ?? join17(homedir4(), ".claude", "projects", "-mnt-projects-cleocode", "memory");
45304
45717
  const isDryRun = !!args["dry-run"];
45305
45718
  const isJson = !!args.json;
45306
45719
  const projectRoot = getProjectRoot22();
45307
- const stateFile = join16(projectRoot, CLEO_DIR_NAME, MIGRATE_MEMORY_HASHES_JSON);
45720
+ const stateFile = join17(projectRoot, CLEO_DIR_NAME, MIGRATE_MEMORY_HASHES_JSON);
45308
45721
  if (!existsSync11(sourceDir)) {
45309
45722
  const msg = `Source directory not found: ${sourceDir}`;
45310
45723
  if (isJson) {
@@ -45314,7 +45727,7 @@ var importCommand3 = defineCommand({
45314
45727
  }
45315
45728
  process.exit(1);
45316
45729
  }
45317
- const files = readdirSync3(sourceDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md").map((f) => join16(sourceDir, f));
45730
+ const files = readdirSync3(sourceDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md").map((f) => join17(sourceDir, f));
45318
45731
  const importedHashes = isDryRun ? /* @__PURE__ */ new Set() : loadImportHashes(stateFile);
45319
45732
  const stats = { total: files.length, imported: 0, skipped: 0, errors: 0 };
45320
45733
  const importedEntries = [];
@@ -45329,7 +45742,7 @@ var importCommand3 = defineCommand({
45329
45742
  for (const filePath of files) {
45330
45743
  const fileName = filePath.split("/").pop() ?? filePath;
45331
45744
  try {
45332
- const raw = readFileSync12(filePath, "utf-8");
45745
+ const raw = readFileSync13(filePath, "utf-8");
45333
45746
  if (!raw.trim()) {
45334
45747
  stats.skipped++;
45335
45748
  skippedEntries.push({ file: fileName, reason: "empty file" });
@@ -49213,8 +49626,8 @@ var exportCommand6 = defineCommand({
49213
49626
  return;
49214
49627
  }
49215
49628
  if (outputFile) {
49216
- const { writeFileSync: writeFileSync4 } = await import("node:fs");
49217
- writeFileSync4(outputFile, output, "utf-8");
49629
+ const { writeFileSync: writeFileSync5 } = await import("node:fs");
49630
+ writeFileSync5(outputFile, output, "utf-8");
49218
49631
  process.stdout.write(
49219
49632
  `[nexus] Exported to ${outputFile} (${nodes.length} nodes, ${relations.length} edges)
49220
49633
  `
@@ -52440,17 +52853,41 @@ var listCommand13 = defineCommand({
52440
52853
  );
52441
52854
  }
52442
52855
  });
52856
+ var validateCommand6 = defineCommand({
52857
+ meta: {
52858
+ name: "validate",
52859
+ description: "Parse and validate a .cantbook file \u2014 exit 0 on success, exit 70 on parse error (T1261)"
52860
+ },
52861
+ args: {
52862
+ file: {
52863
+ type: "positional",
52864
+ description: "Path to .cantbook file OR playbook name to resolve via search path",
52865
+ required: true
52866
+ }
52867
+ },
52868
+ async run({ args }) {
52869
+ const isPath = args.file.includes("/") || args.file.includes("\\") || args.file.endsWith(".cantbook");
52870
+ await dispatchFromCli(
52871
+ "query",
52872
+ "playbook",
52873
+ "validate",
52874
+ isPath ? { file: args.file } : { name: args.file },
52875
+ { command: "playbook" }
52876
+ );
52877
+ }
52878
+ });
52443
52879
  var playbookCommand = defineCommand({
52444
52880
  meta: {
52445
52881
  name: "playbook",
52446
- description: "Playbook runtime operations (run, status, resume, list, create)"
52882
+ description: "Playbook runtime operations (run, status, resume, list, create, validate)"
52447
52883
  },
52448
52884
  subCommands: {
52449
52885
  run: runCommand3,
52450
52886
  status: statusCommand10,
52451
52887
  resume: resumeCommand,
52452
52888
  list: listCommand13,
52453
- create: createCommand2
52889
+ create: createCommand2,
52890
+ validate: validateCommand6
52454
52891
  },
52455
52892
  async run({ cmd, rawArgs }) {
52456
52893
  const firstArg = rawArgs?.find((a) => !a.startsWith("-"));
@@ -54566,7 +55003,7 @@ var schemaCommand = defineCommand({
54566
55003
  init_src();
54567
55004
  import { execFile } from "node:child_process";
54568
55005
  import { readFile as readFile4 } from "node:fs/promises";
54569
- import { join as join17 } from "node:path";
55006
+ import { join as join18 } from "node:path";
54570
55007
  import * as readline2 from "node:readline";
54571
55008
  import { promisify } from "node:util";
54572
55009
  import {
@@ -54585,7 +55022,7 @@ var GITHUB_REPO = BUILD_CONFIG2.repository.fullName;
54585
55022
  async function getCurrentVersion() {
54586
55023
  const cleoHome = getCleoHome2();
54587
55024
  try {
54588
- const content = await readFile4(join17(cleoHome, "VERSION"), "utf-8");
55025
+ const content = await readFile4(join18(cleoHome, "VERSION"), "utf-8");
54589
55026
  return (content.split("\n")[0] ?? "unknown").trim();
54590
55027
  } catch {
54591
55028
  return "unknown";
@@ -54639,7 +55076,7 @@ async function writeRuntimeVersionMetadata(mode, source, version) {
54639
55076
  ];
54640
55077
  await import("node:fs/promises").then(
54641
55078
  ({ writeFile: writeFile3, mkdir: mkdir5 }) => mkdir5(cleoHome, { recursive: true }).then(
54642
- () => writeFile3(join17(cleoHome, "VERSION"), `${lines.join("\n")}
55079
+ () => writeFile3(join18(cleoHome, "VERSION"), `${lines.join("\n")}
54643
55080
  `, "utf-8")
54644
55081
  )
54645
55082
  );
@@ -55040,7 +55477,7 @@ async function runPostUpdateDiagnostics(opts) {
55040
55477
  }
55041
55478
 
55042
55479
  // packages/cleo/src/cli/commands/sentient.ts
55043
- import { join as join18 } from "node:path";
55480
+ import { join as join19 } from "node:path";
55044
55481
  import { cwd as processCwd } from "node:process";
55045
55482
  import {
55046
55483
  getSentientDaemonStatus,
@@ -55111,7 +55548,7 @@ var startSub = defineCommand({
55111
55548
  return;
55112
55549
  }
55113
55550
  if (dryRun) {
55114
- const statePath2 = join18(projectRoot, SENTIENT_STATE_FILE);
55551
+ const statePath2 = join19(projectRoot, SENTIENT_STATE_FILE);
55115
55552
  const outcome = await safeRunTick({ projectRoot, statePath: statePath2, dryRun: true });
55116
55553
  emitSuccess(
55117
55554
  { dryRun: true, outcome },
@@ -55245,7 +55682,7 @@ var tickSub = defineCommand({
55245
55682
  const jsonMode = args.json === true;
55246
55683
  const dryRun = args["dry-run"] === true;
55247
55684
  try {
55248
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55685
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55249
55686
  const outcome = await safeRunTick({ projectRoot, statePath, dryRun });
55250
55687
  emitSuccess(
55251
55688
  { outcome, dryRun },
@@ -55314,7 +55751,7 @@ var proposeAcceptSub = defineCommand({
55314
55751
  return;
55315
55752
  }
55316
55753
  await db.update(tasks).set({ status: "pending", updatedAt: now }).where(eq2(tasks.id, id)).run();
55317
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55754
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55318
55755
  const state = await readSentientState(statePath);
55319
55756
  await patchSentientState(statePath, {
55320
55757
  tier2Stats: {
@@ -55366,7 +55803,7 @@ var proposeRejectSub = defineCommand({
55366
55803
  return;
55367
55804
  }
55368
55805
  await db.update(tasks).set({ status: "cancelled", cancellationReason: reason, cancelledAt: now, updatedAt: now }).where(eq2(tasks.id, id)).run();
55369
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55806
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55370
55807
  const state = await readSentientState(statePath);
55371
55808
  await patchSentientState(statePath, {
55372
55809
  tier2Stats: {
@@ -55411,7 +55848,7 @@ var proposeRunSub = defineCommand({
55411
55848
  const projectRoot = resolveProjectRoot7(args.project);
55412
55849
  const jsonMode = args.json === true;
55413
55850
  try {
55414
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55851
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55415
55852
  const outcome = await safeRunProposeTick({ projectRoot, statePath });
55416
55853
  emitSuccess(
55417
55854
  { outcome },
@@ -55431,7 +55868,7 @@ var proposeEnableSub = defineCommand({
55431
55868
  const projectRoot = resolveProjectRoot7(args.project);
55432
55869
  const jsonMode = args.json === true;
55433
55870
  try {
55434
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55871
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55435
55872
  const updated = await patchSentientState(statePath, { tier2Enabled: true });
55436
55873
  emitSuccess({ tier2Enabled: updated.tier2Enabled }, jsonMode, "Tier-2 proposals enabled");
55437
55874
  } catch (err) {
@@ -55450,7 +55887,7 @@ var proposeDisableSub = defineCommand({
55450
55887
  const projectRoot = resolveProjectRoot7(args.project);
55451
55888
  const jsonMode = args.json === true;
55452
55889
  try {
55453
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55890
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55454
55891
  const updated = await patchSentientState(statePath, { tier2Enabled: false });
55455
55892
  emitSuccess({ tier2Enabled: updated.tier2Enabled }, jsonMode, "Tier-2 proposals disabled");
55456
55893
  } catch (err) {
@@ -55481,7 +55918,7 @@ var proposeSub = defineCommand({
55481
55918
  const projectRoot = resolveProjectRoot7(args.project);
55482
55919
  const jsonMode = args.json === true;
55483
55920
  try {
55484
- const statePath = join18(projectRoot, SENTIENT_STATE_FILE);
55921
+ const statePath = join19(projectRoot, SENTIENT_STATE_FILE);
55485
55922
  const state = await readSentientState(statePath);
55486
55923
  emitSuccess(
55487
55924
  {
@@ -56364,7 +56801,7 @@ var searchCommand3 = defineCommand({
56364
56801
  );
56365
56802
  }
56366
56803
  });
56367
- var validateCommand6 = defineCommand({
56804
+ var validateCommand7 = defineCommand({
56368
56805
  meta: { name: "validate", description: "Validate skill against protocol" },
56369
56806
  args: {
56370
56807
  "skill-name": {
@@ -56631,7 +57068,7 @@ var skillsCommand2 = defineCommand({
56631
57068
  subCommands: {
56632
57069
  list: listCommand20,
56633
57070
  search: searchCommand3,
56634
- validate: validateCommand6,
57071
+ validate: validateCommand7,
56635
57072
  info: infoCommand,
56636
57073
  install: installCommand2,
56637
57074
  uninstall: uninstallCommand,
@@ -57212,10 +57649,10 @@ var reconcileCommand2 = defineCommand({
57212
57649
  }
57213
57650
  },
57214
57651
  async run({ args }) {
57215
- const { readFileSync: readFileSync15 } = await import("node:fs");
57652
+ const { readFileSync: readFileSync16 } = await import("node:fs");
57216
57653
  let externalTasks;
57217
57654
  try {
57218
- externalTasks = JSON.parse(readFileSync15(args.file, "utf8"));
57655
+ externalTasks = JSON.parse(readFileSync16(args.file, "utf8"));
57219
57656
  } catch (err) {
57220
57657
  const message = err instanceof Error ? err.message : String(err);
57221
57658
  console.error(`Failed to read or parse external tasks file: ${message}`);
@@ -57253,7 +57690,7 @@ var syncCommand5 = defineCommand({
57253
57690
 
57254
57691
  // packages/cleo/src/cli/commands/testing.ts
57255
57692
  init_cli();
57256
- var validateCommand7 = defineCommand({
57693
+ var validateCommand8 = defineCommand({
57257
57694
  meta: { name: "validate", description: "Validate testing protocol compliance for a task" },
57258
57695
  args: {
57259
57696
  taskId: {
@@ -57353,7 +57790,7 @@ var runCommand4 = defineCommand({
57353
57790
  var testingCommand = defineCommand({
57354
57791
  meta: { name: "testing", description: "Validate testing protocol compliance" },
57355
57792
  subCommands: {
57356
- validate: validateCommand7,
57793
+ validate: validateCommand8,
57357
57794
  check: checkCommand7,
57358
57795
  status: statusCommand12,
57359
57796
  coverage: coverageCommand,
@@ -57367,14 +57804,14 @@ var testingCommand = defineCommand({
57367
57804
  });
57368
57805
 
57369
57806
  // packages/cleo/src/cli/commands/token.ts
57370
- import { readFileSync as readFileSync13 } from "node:fs";
57807
+ import { readFileSync as readFileSync14 } from "node:fs";
57371
57808
  import { measureTokenExchange, recordTokenExchange as recordTokenExchange2 } from "@cleocode/core/internal";
57372
57809
  init_cli();
57373
57810
  init_renderers();
57374
57811
  function readPayload(args, textKey, fileKey) {
57375
57812
  const text = args[textKey];
57376
57813
  const file = args[fileKey];
57377
- if (file) return readFileSync13(file, "utf-8");
57814
+ if (file) return readFileSync14(file, "utf-8");
57378
57815
  return text;
57379
57816
  }
57380
57817
  var filterArgs = {
@@ -57556,7 +57993,7 @@ var tokenCommand = defineCommand({
57556
57993
 
57557
57994
  // packages/cleo/src/cli/commands/transcript.ts
57558
57995
  import { homedir as homedir5 } from "node:os";
57559
- import { join as join19 } from "node:path";
57996
+ import { join as join20 } from "node:path";
57560
57997
  import { getProjectRoot as getProjectRoot27 } from "@cleocode/core";
57561
57998
  import {
57562
57999
  parseDurationMs,
@@ -57614,7 +58051,7 @@ var scanCommand = defineCommand({
57614
58051
  }
57615
58052
  return;
57616
58053
  }
57617
- const projectsDir = args["projects-dir"] ?? join19(homedir5(), ".claude", "projects");
58054
+ const projectsDir = args["projects-dir"] ?? join20(homedir5(), ".claude", "projects");
57618
58055
  try {
57619
58056
  const result = await scanTranscripts(projectsDir);
57620
58057
  const envelope = {
@@ -57999,7 +58436,7 @@ var pruneCommand = defineCommand({
57999
58436
  process.exit(2);
58000
58437
  return;
58001
58438
  }
58002
- const projectsDir = args["projects-dir"] ?? join19(homedir5(), ".claude", "projects");
58439
+ const projectsDir = args["projects-dir"] ?? join20(homedir5(), ".claude", "projects");
58003
58440
  try {
58004
58441
  const pruneResult = await pruneTranscripts({
58005
58442
  olderThanMs,
@@ -58425,7 +58862,7 @@ var verifyCommand2 = defineCommand({
58425
58862
  init_src();
58426
58863
  import { execFileSync as execFileSync5, spawn } from "node:child_process";
58427
58864
  import { mkdir as mkdir4, open, readFile as readFile5, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
58428
- import { join as join20 } from "node:path";
58865
+ import { join as join21 } from "node:path";
58429
58866
  import { CleoError as CleoError12, formatError as formatError14, getCleoHome as getCleoHome3 } from "@cleocode/core";
58430
58867
  init_renderers();
58431
58868
  var DEFAULT_PORT = 3456;
@@ -58433,10 +58870,10 @@ var DEFAULT_HOST = "127.0.0.1";
58433
58870
  function getWebPaths() {
58434
58871
  const cleoHome = getCleoHome3();
58435
58872
  return {
58436
- pidFile: join20(cleoHome, "web-server.pid"),
58437
- configFile: join20(cleoHome, "web-server.json"),
58438
- logDir: join20(cleoHome, "logs"),
58439
- logFile: join20(cleoHome, "logs", "web-server.log")
58873
+ pidFile: join21(cleoHome, "web-server.pid"),
58874
+ configFile: join21(cleoHome, "web-server.json"),
58875
+ logDir: join21(cleoHome, "logs"),
58876
+ logFile: join21(cleoHome, "logs", "web-server.log")
58440
58877
  };
58441
58878
  }
58442
58879
  function isProcessRunning(pid) {
@@ -58475,7 +58912,7 @@ async function startWebServer(port, host) {
58475
58912
  throw new CleoError12(1 /* GENERAL_ERROR */, `Server already running (PID: ${status.pid})`);
58476
58913
  }
58477
58914
  const projectRoot = process.env["CLEO_ROOT"] ?? process.cwd();
58478
- const studioDir = process.env["CLEO_STUDIO_DIR"] ?? join20(projectRoot, "packages", "studio", "build");
58915
+ const studioDir = process.env["CLEO_STUDIO_DIR"] ?? join21(projectRoot, "packages", "studio", "build");
58479
58916
  await mkdir4(logDir, { recursive: true });
58480
58917
  await writeFile2(
58481
58918
  configFile,
@@ -58485,7 +58922,7 @@ async function startWebServer(port, host) {
58485
58922
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
58486
58923
  })
58487
58924
  );
58488
- const webIndexPath = join20(studioDir, "index.js");
58925
+ const webIndexPath = join21(studioDir, "index.js");
58489
58926
  try {
58490
58927
  await stat(webIndexPath);
58491
58928
  } catch {
@@ -58764,8 +59201,8 @@ Or via NodeSource: https://github.com/nodesource/distributions
58764
59201
  }
58765
59202
  }
58766
59203
  function getPackageVersion() {
58767
- const pkgPath = join21(dirname9(fileURLToPath3(import.meta.url)), "../../package.json");
58768
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
59204
+ const pkgPath = join22(dirname10(fileURLToPath3(import.meta.url)), "../../package.json");
59205
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
58769
59206
  return pkg.version;
58770
59207
  }
58771
59208
  var CLI_VERSION = getPackageVersion();