@cleocode/cleo 2026.5.108 → 2026.5.110

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
@@ -1719,6 +1719,189 @@ var init_credentials = __esm({
1719
1719
  }
1720
1720
  });
1721
1721
 
1722
+ // packages/contracts/src/db-inventory.json
1723
+ var db_inventory_default;
1724
+ var init_db_inventory = __esm({
1725
+ "packages/contracts/src/db-inventory.json"() {
1726
+ db_inventory_default = {
1727
+ $schemaNote: "SSoT machine-readable inventory of every CLEO SQLite database. Consumed by T10307 fleet survey, T10310 pragma drift, T10311 migration coverage, T10312 doctor integrity, T10320 cross-DB invariants. Owned by Saga T10281 SG-BRAIN-DB-RESILIENCE / Epic T10282 E1-DB-INVENTORY (task T10305). Amend together with ADR-068 charter; the CI drift gate (forthcoming under E1) compares entries to disk reality.",
1728
+ $pathTokens: {
1729
+ "<projectRoot>": "Resolved at runtime from CLEO_ROOT env var or process.cwd(). Substituted by SSoT helpers `getCleoProjectDir()` in packages/brain/src/cleo-home.ts.",
1730
+ $XDG_DATA_HOME: "Resolved via env-paths through `getCleoHome()` in @cleocode/paths. Linux: ~/.local/share/cleo/, macOS: ~/Library/Application Support/cleo/."
1731
+ },
1732
+ entries: [
1733
+ {
1734
+ role: "tasks",
1735
+ tier: "project",
1736
+ filePathTemplate: "<projectRoot>/.cleo/tasks.db",
1737
+ drizzleSchemaPath: "packages/core/src/store/tasks-schema.ts",
1738
+ migrationsDir: "packages/core/migrations/drizzle-tasks/",
1739
+ ownerPackage: "@cleocode/core",
1740
+ openedVia: "openCleoDb('tasks', cwd)",
1741
+ concurrency: "single-writer",
1742
+ privacy: "local-only",
1743
+ backupPath: ".cleo/backups/sqlite/tasks-YYYYMMDD-HHmmss.db",
1744
+ documentedIn: "ADR-068 row 1; ADR-013 \xA79"
1745
+ },
1746
+ {
1747
+ role: "brain",
1748
+ tier: "project",
1749
+ filePathTemplate: "<projectRoot>/.cleo/brain.db",
1750
+ drizzleSchemaPath: "packages/core/src/store/memory-schema.ts",
1751
+ migrationsDir: "packages/core/migrations/drizzle-brain/",
1752
+ ownerPackage: "@cleocode/brain",
1753
+ openedVia: "openCleoDb('brain', cwd)",
1754
+ concurrency: "single-writer",
1755
+ privacy: "local-only-pii",
1756
+ backupPath: ".cleo/backups/sqlite/brain-YYYYMMDD-HHmmss.db",
1757
+ documentedIn: "ADR-068 row 2; ADR-013 \xA79; audit \xA72 (P0 malformed 2026-05-23)"
1758
+ },
1759
+ {
1760
+ role: "conduit",
1761
+ tier: "project",
1762
+ filePathTemplate: "<projectRoot>/.cleo/conduit.db",
1763
+ drizzleSchemaPath: "packages/core/src/store/conduit-schema.ts",
1764
+ migrationsDir: "packages/core/migrations/drizzle-conduit/",
1765
+ ownerPackage: "@cleocode/core",
1766
+ openedVia: "openCleoDb('conduit', cwd)",
1767
+ concurrency: "single-writer",
1768
+ privacy: "local-only",
1769
+ backupPath: ".cleo/backups/sqlite/conduit-YYYYMMDD-HHmmss.db",
1770
+ documentedIn: "ADR-068 row 3; ADR-037 (signaldock\u2192conduit split)"
1771
+ },
1772
+ {
1773
+ role: "manifest",
1774
+ tier: "derived",
1775
+ filePathTemplate: "<projectRoot>/.cleo/blobs/manifest.db",
1776
+ drizzleSchemaPath: "packages/core/src/store/llmtxt-blob-adapter.ts",
1777
+ migrationsDir: null,
1778
+ ownerPackage: "@cleocode/core",
1779
+ openedVia: "CleoBlobStore via llmtxt/blob BlobFsAdapter (no openCleoDb role registered)",
1780
+ concurrency: "single-writer",
1781
+ privacy: "local-only",
1782
+ backupPath: "rebuildable-from-blob-store",
1783
+ documentedIn: "ADR-068 row 7 (derived); schema owned by llmtxt/blob BlobFsAdapter contract"
1784
+ },
1785
+ {
1786
+ role: "llmtxt",
1787
+ tier: "project",
1788
+ filePathTemplate: "<projectRoot>/.cleo/llmtxt/llmtxt.db",
1789
+ drizzleSchemaPath: null,
1790
+ migrationsDir: null,
1791
+ ownerPackage: "@cleocode/llmtxt-core",
1792
+ openedVia: "openCleoDb('llmtxt', cwd) \u2014 RESERVED; opener throws 'not yet implemented' (see open-cleo-db.ts L138)",
1793
+ concurrency: "single-writer",
1794
+ privacy: "local-only-pii",
1795
+ backupPath: ".cleo/backups/sqlite/llmtxt-YYYYMMDD-HHmmss.db",
1796
+ documentedIn: "ADR-068 row 8 (reserved); audit \xA71.1 row 4 (live at .cleo/llmtxt/llmtxt.db)"
1797
+ },
1798
+ {
1799
+ role: "nexus",
1800
+ tier: "global",
1801
+ filePathTemplate: "$XDG_DATA_HOME/cleo/nexus.db",
1802
+ drizzleSchemaPath: "packages/core/src/store/nexus-schema.ts",
1803
+ migrationsDir: "packages/core/migrations/drizzle-nexus/",
1804
+ ownerPackage: "@cleocode/core",
1805
+ openedVia: "openCleoDb('nexus')",
1806
+ concurrency: "single-writer",
1807
+ privacy: "local-only-pii",
1808
+ backupPath: "$XDG_DATA_HOME/cleo/backups/sqlite/nexus-YYYYMMDD-HHmmss.db",
1809
+ documentedIn: "ADR-068 row 5"
1810
+ },
1811
+ {
1812
+ role: "signaldock-project",
1813
+ tier: "project",
1814
+ filePathTemplate: "<projectRoot>/.cleo/signaldock.db",
1815
+ drizzleSchemaPath: "packages/core/src/store/signaldock-schema.ts",
1816
+ migrationsDir: "packages/core/migrations/drizzle-signaldock/",
1817
+ ownerPackage: "@cleocode/core",
1818
+ openedVia: "HISTORICAL \u2014 project-tier signaldock.db was migrated into conduit.db post-T310/ADR-037. No live opener; charter row retained for migration provenance and legacy backup detection.",
1819
+ concurrency: "single-writer",
1820
+ privacy: "local-only",
1821
+ backupPath: ".cleo/backups/sqlite/signaldock-project-YYYYMMDD-HHmmss.db",
1822
+ documentedIn: "ADR-068 row 4 (stale \u2014 superseded by ADR-037); audit \xA71.1 (not in live project DB list)"
1823
+ },
1824
+ {
1825
+ role: "signaldock-global",
1826
+ tier: "global",
1827
+ filePathTemplate: "$XDG_DATA_HOME/cleo/signaldock.db",
1828
+ drizzleSchemaPath: "packages/core/src/store/signaldock-schema.ts",
1829
+ migrationsDir: "packages/core/migrations/drizzle-signaldock/",
1830
+ ownerPackage: "@cleocode/core",
1831
+ openedVia: "openCleoDb('signaldock')",
1832
+ concurrency: "single-writer",
1833
+ privacy: "local-only",
1834
+ backupPath: "$XDG_DATA_HOME/cleo/backups/sqlite/signaldock-global-YYYYMMDD-HHmmss.db",
1835
+ documentedIn: "ADR-068 row 9; ADR-037 (post-split global identity registry)"
1836
+ },
1837
+ {
1838
+ role: "telemetry",
1839
+ tier: "global",
1840
+ filePathTemplate: "$XDG_DATA_HOME/cleo/telemetry.db",
1841
+ drizzleSchemaPath: "packages/core/src/telemetry/schema.ts",
1842
+ migrationsDir: "packages/core/migrations/drizzle-telemetry/",
1843
+ ownerPackage: "@cleocode/core",
1844
+ openedVia: "@cleocode/core telemetry/sqlite.ts \u2014 lazy open on first event when opted-in; not yet registered as openCleoDb role",
1845
+ concurrency: "single-writer",
1846
+ privacy: "cloud-exportable-opt-in",
1847
+ backupPath: "$XDG_DATA_HOME/cleo/backups/sqlite/telemetry-YYYYMMDD-HHmmss.db",
1848
+ documentedIn: "ADR-068 row 6; T624"
1849
+ },
1850
+ {
1851
+ role: "skills",
1852
+ tier: "global",
1853
+ filePathTemplate: "$XDG_DATA_HOME/cleo/skills.db",
1854
+ drizzleSchemaPath: "packages/core/src/store/skills-schema.ts",
1855
+ migrationsDir: "packages/core/migrations/drizzle-skills/",
1856
+ ownerPackage: "@cleocode/core",
1857
+ openedVia: "openCleoDb('skills')",
1858
+ concurrency: "single-writer",
1859
+ privacy: "local-only",
1860
+ backupPath: "$XDG_DATA_HOME/cleo/backups/sqlite/skills-YYYYMMDD-HHmmss.db",
1861
+ documentedIn: "T9651 (initial skills.db migration); audit \xA71.2 row 4 \u2014 NOT yet in ADR-068 table"
1862
+ },
1863
+ {
1864
+ role: "global-brain",
1865
+ tier: "global",
1866
+ filePathTemplate: "$XDG_DATA_HOME/cleo/brain.db",
1867
+ drizzleSchemaPath: "packages/core/src/store/memory-schema.ts",
1868
+ migrationsDir: "packages/core/migrations/drizzle-brain/",
1869
+ ownerPackage: "@cleocode/brain",
1870
+ openedVia: "UNREGISTERED \u2014 file exists on disk (audit \xA71.2 row 3) but no live opener. Provenance unclear; likely orphan from a getCleoHome()-vs-project-resolution path bug. Tracked for cleanup decision under T10282/T10307.",
1871
+ concurrency: "single-writer",
1872
+ privacy: "local-only-pii",
1873
+ backupPath: "$XDG_DATA_HOME/cleo/backups/sqlite/global-brain-YYYYMMDD-HHmmss.db",
1874
+ documentedIn: "audit \xA71.2 row 3 \u2014 NEW per saga T10281; not in ADR-068"
1875
+ },
1876
+ {
1877
+ role: "global-tasks",
1878
+ tier: "global",
1879
+ filePathTemplate: "$XDG_DATA_HOME/cleo/tasks.db",
1880
+ drizzleSchemaPath: "packages/core/src/store/tasks-schema.ts",
1881
+ migrationsDir: "packages/core/migrations/drizzle-tasks/",
1882
+ ownerPackage: "@cleocode/core",
1883
+ openedVia: "UNREGISTERED \u2014 file exists on disk (audit \xA71.2 row 5, 4 KB) but no live opener. Provenance unclear; likely orphan from a cwd-cascade bug (T9550 class). Tracked for cleanup decision under T10282/T10307.",
1884
+ concurrency: "single-writer",
1885
+ privacy: "local-only",
1886
+ backupPath: "$XDG_DATA_HOME/cleo/backups/sqlite/global-tasks-YYYYMMDD-HHmmss.db",
1887
+ documentedIn: "audit \xA71.2 row 5 \u2014 NEW per saga T10281; not in ADR-068"
1888
+ }
1889
+ ]
1890
+ };
1891
+ }
1892
+ });
1893
+
1894
+ // packages/contracts/src/db-inventory.ts
1895
+ var rawInventory, DB_INVENTORY;
1896
+ var init_db_inventory2 = __esm({
1897
+ "packages/contracts/src/db-inventory.ts"() {
1898
+ "use strict";
1899
+ init_db_inventory();
1900
+ rawInventory = db_inventory_default;
1901
+ DB_INVENTORY = rawInventory.entries;
1902
+ }
1903
+ });
1904
+
1722
1905
  // packages/contracts/src/dispatch/identity.ts
1723
1906
  var init_identity = __esm({
1724
1907
  "packages/contracts/src/dispatch/identity.ts"() {
@@ -11309,6 +11492,7 @@ var init_src2 = __esm({
11309
11492
  init_changesets();
11310
11493
  init_cli_category();
11311
11494
  init_credentials();
11495
+ init_db_inventory2();
11312
11496
  init_identity();
11313
11497
  init_operations_registry();
11314
11498
  init_docs_taxonomy();
@@ -14626,7 +14810,38 @@ function validateCanonRegistry(raw, source) {
14626
14810
  for (const [kindId, entryRaw] of Object.entries(kindsRaw)) {
14627
14811
  kinds[kindId] = validateKindEntry(kindId, entryRaw, source);
14628
14812
  }
14629
- return { version, kinds };
14813
+ const similarity = validateSimilarity(obj["similarity"], source);
14814
+ return similarity !== void 0 ? { version, kinds, similarity } : { version, kinds };
14815
+ }
14816
+ function validateSimilarity(raw, source) {
14817
+ if (raw === void 0 || raw === null) {
14818
+ return void 0;
14819
+ }
14820
+ if (typeof raw !== "object" || Array.isArray(raw)) {
14821
+ throw new Error(`${source}: 'similarity' must be an object`);
14822
+ }
14823
+ const obj = raw;
14824
+ const warnThresholdRaw = obj["warnThreshold"];
14825
+ let warnThreshold = 0.85;
14826
+ if (warnThresholdRaw !== void 0) {
14827
+ if (typeof warnThresholdRaw !== "number" || Number.isNaN(warnThresholdRaw) || warnThresholdRaw < 0 || warnThresholdRaw > 1) {
14828
+ throw new Error(
14829
+ `${source}: 'similarity.warnThreshold' must be a number in [0, 1] (got ${String(warnThresholdRaw)})`
14830
+ );
14831
+ }
14832
+ warnThreshold = warnThresholdRaw;
14833
+ }
14834
+ const modeRaw = obj["mode"];
14835
+ let mode = "warn";
14836
+ if (modeRaw !== void 0) {
14837
+ if (modeRaw !== "warn" && modeRaw !== "block") {
14838
+ throw new Error(
14839
+ `${source}: 'similarity.mode' must be 'warn' or 'block' (got ${String(modeRaw)})`
14840
+ );
14841
+ }
14842
+ mode = modeRaw;
14843
+ }
14844
+ return { warnThreshold, mode };
14630
14845
  }
14631
14846
  function validateKindEntry(kindId, raw, source) {
14632
14847
  const where = `${source} kinds.${kindId}`;
@@ -15984,6 +16199,8 @@ import {
15984
16199
  getCleoDirAbsolute,
15985
16200
  getProjectRoot as getProjectRoot5,
15986
16201
  memoryObserve as memoryObserve2,
16202
+ releaseReservedSlug,
16203
+ reserveSlugForDispatch,
15987
16204
  resolveAttachmentBackend,
15988
16205
  SlugCollisionError
15989
16206
  } from "@cleocode/core/internal";
@@ -16499,6 +16716,25 @@ var init_docs2 = __esm({
16499
16716
  return lafsError("E_SLUG_PATTERN_MISMATCH", `${patternCheck.error}${exampleHint}`, "add");
16500
16717
  }
16501
16718
  }
16719
+ if (slug !== void 0) {
16720
+ const reservation = await reserveSlugForDispatch(getProjectRoot5(), {
16721
+ kind: type2 ?? "",
16722
+ slug
16723
+ });
16724
+ if (!reservation.ok) {
16725
+ return {
16726
+ success: false,
16727
+ error: {
16728
+ code: "E_SLUG_RESERVED",
16729
+ message: `slug '${slug}' is already in use in this project`,
16730
+ details: {
16731
+ suggestions: reservation.suggestions,
16732
+ aliases: ["E_SLUG_TAKEN"]
16733
+ }
16734
+ }
16735
+ };
16736
+ }
16737
+ }
16502
16738
  const extras = {};
16503
16739
  if (slug !== void 0) extras.slug = slug;
16504
16740
  if (type2 !== void 0) extras.type = type2;
@@ -16535,13 +16771,17 @@ var init_docs2 = __esm({
16535
16771
  extras
16536
16772
  );
16537
16773
  } catch (err) {
16774
+ if (slug !== void 0) releaseReservedSlug(slug);
16538
16775
  if (err instanceof SlugCollisionError) {
16539
16776
  return {
16540
16777
  success: false,
16541
16778
  error: {
16542
- code: "E_SLUG_TAKEN",
16779
+ code: "E_SLUG_RESERVED",
16543
16780
  message: `slug '${err.slug}' is already in use in this project`,
16544
- details: { suggestions: err.suggestions }
16781
+ details: {
16782
+ suggestions: err.suggestions,
16783
+ aliases: ["E_SLUG_TAKEN"]
16784
+ }
16545
16785
  }
16546
16786
  };
16547
16787
  }
@@ -16613,13 +16853,17 @@ var init_docs2 = __esm({
16613
16853
  extras
16614
16854
  );
16615
16855
  } catch (err) {
16856
+ if (slug !== void 0) releaseReservedSlug(slug);
16616
16857
  if (err instanceof SlugCollisionError) {
16617
16858
  return {
16618
16859
  success: false,
16619
16860
  error: {
16620
- code: "E_SLUG_TAKEN",
16861
+ code: "E_SLUG_RESERVED",
16621
16862
  message: `slug '${err.slug}' is already in use in this project`,
16622
- details: { suggestions: err.suggestions }
16863
+ details: {
16864
+ suggestions: err.suggestions,
16865
+ aliases: ["E_SLUG_TAKEN"]
16866
+ }
16623
16867
  }
16624
16868
  };
16625
16869
  }
@@ -16785,6 +17029,7 @@ import {
16785
17029
  createAttachmentStore as createAttachmentStore2,
16786
17030
  memoryFind as memoryFind2,
16787
17031
  orchestrateReady as orchestrateReady2,
17032
+ sagas,
16788
17033
  taskRelates as taskRelates2,
16789
17034
  taskShow as taskShow2
16790
17035
  } from "@cleocode/core/internal";
@@ -16886,8 +17131,7 @@ async function buildFocusEnvelope(id, projectRoot) {
16886
17131
  };
16887
17132
  }
16888
17133
  const task = showResult.data.task;
16889
- const labels = Array.isArray(task.labels) ? task.labels : [];
16890
- const isSaga = labels.includes("saga");
17134
+ const isSaga = sagas.isSagaType(task);
16891
17135
  const isEpic = task.type === "epic" && !isSaga;
16892
17136
  const entityType = isSaga ? "saga" : isEpic ? "epic" : "task";
16893
17137
  const identity = {
@@ -25027,8 +25271,8 @@ async function loadPlaybookByName(name) {
25027
25271
  return null;
25028
25272
  }
25029
25273
  try {
25030
- const { getProjectRoot: getProjectRoot44 } = await import("@cleocode/core/internal");
25031
- const projectRoot = __playbookRuntimeOverrides.projectRoot ?? getProjectRoot44();
25274
+ const { getProjectRoot: getProjectRoot48 } = await import("@cleocode/core/internal");
25275
+ const projectRoot = __playbookRuntimeOverrides.projectRoot ?? getProjectRoot48();
25032
25276
  const resolved = resolvePlaybook(name, {
25033
25277
  projectRoot,
25034
25278
  globalPlaybooksDir: __playbookRuntimeOverrides.globalPlaybooksDir,
@@ -25072,8 +25316,8 @@ async function acquireDb() {
25072
25316
  async function buildDefaultDispatcher() {
25073
25317
  if (__playbookRuntimeOverrides.dispatcher) return __playbookRuntimeOverrides.dispatcher;
25074
25318
  const { orchestrateSpawnExecute: orchestrateSpawnExecute2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
25075
- const { getProjectRoot: getProjectRoot44 } = await import("@cleocode/core/internal");
25076
- const projectRoot = getProjectRoot44();
25319
+ const { getProjectRoot: getProjectRoot48 } = await import("@cleocode/core/internal");
25320
+ const projectRoot = getProjectRoot48();
25077
25321
  return {
25078
25322
  async dispatch(input2) {
25079
25323
  try {
@@ -25263,8 +25507,8 @@ var init_playbook2 = __esm({
25263
25507
  projectRoot = __playbookRuntimeOverrides.projectRoot;
25264
25508
  } else {
25265
25509
  try {
25266
- const { getProjectRoot: getProjectRoot44 } = await import("@cleocode/core/internal");
25267
- projectRoot = getProjectRoot44();
25510
+ const { getProjectRoot: getProjectRoot48 } = await import("@cleocode/core/internal");
25511
+ projectRoot = getProjectRoot48();
25268
25512
  } catch {
25269
25513
  projectRoot = void 0;
25270
25514
  }
@@ -25328,14 +25572,14 @@ var init_playbook2 = __esm({
25328
25572
  const dispatcher = await buildDefaultDispatcher();
25329
25573
  let result;
25330
25574
  try {
25331
- const { getProjectRoot: getProjectRoot44 } = await import("@cleocode/core/internal");
25575
+ const { getProjectRoot: getProjectRoot48 } = await import("@cleocode/core/internal");
25332
25576
  const opts = {
25333
25577
  db,
25334
25578
  playbook: parsed.definition,
25335
25579
  playbookHash: parsed.sourceHash,
25336
25580
  initialContext,
25337
25581
  dispatcher,
25338
- projectRoot: getProjectRoot44()
25582
+ projectRoot: getProjectRoot48()
25339
25583
  };
25340
25584
  if (__playbookRuntimeOverrides.approvalSecret !== void 0) {
25341
25585
  opts.approvalSecret = __playbookRuntimeOverrides.approvalSecret;
@@ -31123,11 +31367,11 @@ var init_security = __esm({
31123
31367
  });
31124
31368
 
31125
31369
  // packages/cleo/src/dispatch/middleware/sanitizer.ts
31126
- function createSanitizer(getProjectRoot44) {
31370
+ function createSanitizer(getProjectRoot48) {
31127
31371
  return async (req, next) => {
31128
31372
  if (req.params) {
31129
31373
  try {
31130
- const root = getProjectRoot44 ? getProjectRoot44() : void 0;
31374
+ const root = getProjectRoot48 ? getProjectRoot48() : void 0;
31131
31375
  req.params = sanitizeParams(req.params, root, {
31132
31376
  domain: req.domain,
31133
31377
  operation: req.operation
@@ -36113,6 +36357,282 @@ var init_backup_inspect = __esm({
36113
36357
  }
36114
36358
  });
36115
36359
 
36360
+ // packages/cleo/src/cli/lib/define-cli-command.ts
36361
+ var init_define_cli_command = __esm({
36362
+ "packages/cleo/src/cli/lib/define-cli-command.ts"() {
36363
+ "use strict";
36364
+ init_dist();
36365
+ }
36366
+ });
36367
+
36368
+ // packages/cleo/src/cli/commands/backup-recover.ts
36369
+ var backup_recover_exports = {};
36370
+ __export(backup_recover_exports, {
36371
+ backupRecoverBrainLeaf: () => backupRecoverBrainLeaf,
36372
+ backupRecoverSubCommand: () => backupRecoverSubCommand
36373
+ });
36374
+ import { getLogger as getLogger20, getProjectRoot as getProjectRoot27 } from "@cleocode/core";
36375
+ import { BackupRecoverError, runBackupRecover } from "@cleocode/core/store/backup-recover.js";
36376
+ function readBoolFlag(args, key) {
36377
+ return args[key] === true;
36378
+ }
36379
+ function readStringFlag(args, key) {
36380
+ const v = args[key];
36381
+ return typeof v === "string" ? v : "";
36382
+ }
36383
+ function executeRecover(role, args) {
36384
+ const projectRoot = getProjectRoot27();
36385
+ const dryRun = readBoolFlag(args, "dry-run");
36386
+ const fromSnapshot = readStringFlag(args, "from-snapshot");
36387
+ const noDelta = readBoolFlag(args, "no-delta");
36388
+ const operation = `backup.recover.${role}`;
36389
+ try {
36390
+ const result = runBackupRecover({
36391
+ role,
36392
+ projectRoot,
36393
+ logger: getLogger20(`backup-recover-${role}`),
36394
+ dryRun,
36395
+ fromSnapshot: fromSnapshot.length > 0 ? fromSnapshot : void 0,
36396
+ noDelta
36397
+ });
36398
+ cliOutput(result, {
36399
+ command: "backup",
36400
+ operation
36401
+ });
36402
+ if (result.dryRun) {
36403
+ humanInfo(
36404
+ `[dry-run] Would restore role "${role}" from ${result.restoredFrom} (${result.dataLossWindowHours !== null ? `~${result.dataLossWindowHours}h data-loss window` : "data-loss window unknown"}). Re-run without --dry-run to execute (project root: ${projectRoot}).`
36405
+ );
36406
+ } else {
36407
+ humanInfo(
36408
+ `Recovered "${role}" DB from ${result.restoredFrom}. Corrupt DB quarantined at ${result.quarantinedTo}.`
36409
+ );
36410
+ }
36411
+ } catch (err) {
36412
+ if (err instanceof BackupRecoverError) {
36413
+ cliError(
36414
+ err.message,
36415
+ err.code,
36416
+ {
36417
+ name: err.codeName,
36418
+ ...err.fix ? { fix: err.fix } : {}
36419
+ },
36420
+ { operation }
36421
+ );
36422
+ process.exitCode = err.code;
36423
+ return;
36424
+ }
36425
+ const message = err instanceof Error ? err.message : String(err);
36426
+ cliError(message, 1 /* GENERAL_ERROR */, { name: "E_RECOVERY_FAILED" }, { operation });
36427
+ process.exitCode = 1 /* GENERAL_ERROR */;
36428
+ }
36429
+ }
36430
+ function parseRoleArg(value) {
36431
+ const trimmed = value.trim();
36432
+ for (const entry of DB_INVENTORY) {
36433
+ if (entry.role === trimmed) {
36434
+ return entry.role;
36435
+ }
36436
+ }
36437
+ const validRoles = DB_INVENTORY.map((e) => e.role).join(", ");
36438
+ throw new BackupRecoverError(
36439
+ `Unknown DB role "${trimmed}". Valid roles: ${validRoles}.`,
36440
+ 6 /* VALIDATION_ERROR */,
36441
+ "E_UNKNOWN_ROLE",
36442
+ "Run `cleo backup recover --help` for the list of valid roles."
36443
+ );
36444
+ }
36445
+ var backupRecoverBrainLeaf, backupRecoverSubCommand;
36446
+ var init_backup_recover = __esm({
36447
+ "packages/cleo/src/cli/commands/backup-recover.ts"() {
36448
+ "use strict";
36449
+ init_src2();
36450
+ init_define_cli_command();
36451
+ init_renderers();
36452
+ backupRecoverBrainLeaf = defineCommand({
36453
+ meta: {
36454
+ name: "brain",
36455
+ description: "Recover a malformed brain.db from the freshest validated snapshot (Saga T10281 SG-BRAIN-DB-RESILIENCE)"
36456
+ },
36457
+ args: {
36458
+ "dry-run": {
36459
+ type: "boolean",
36460
+ description: "Print what would be done without quarantining or copying any files",
36461
+ default: false
36462
+ },
36463
+ "from-snapshot": {
36464
+ type: "string",
36465
+ description: "Pin recovery to a specific snapshot \u2014 absolute path or ISO timestamp prefix (e.g. 2026-05-23)",
36466
+ default: ""
36467
+ },
36468
+ "no-delta": {
36469
+ type: "boolean",
36470
+ description: "Skip the sqlite3 .recover delta-merge step (reserved \u2014 current pipeline does not delta-merge; flag plumbed for forward-compat)",
36471
+ default: false
36472
+ },
36473
+ force: {
36474
+ type: "boolean",
36475
+ description: "Bypass any safety prompts (currently a no-op; reserved)",
36476
+ default: false
36477
+ }
36478
+ },
36479
+ async run({ args }) {
36480
+ const argsBag = args;
36481
+ executeRecover("brain", argsBag);
36482
+ }
36483
+ });
36484
+ backupRecoverSubCommand = defineCommand({
36485
+ meta: {
36486
+ name: "recover",
36487
+ description: "Recover a malformed CLEO database from snapshot \u2014 accepts any role from DB_INVENTORY (T10318)"
36488
+ },
36489
+ args: {
36490
+ role: {
36491
+ type: "positional",
36492
+ description: `Canonical DB role (one of: ${DB_INVENTORY.map((e) => e.role).join(", ")})`,
36493
+ required: false
36494
+ },
36495
+ "dry-run": {
36496
+ type: "boolean",
36497
+ description: "Print what would be done without quarantining or copying any files",
36498
+ default: false
36499
+ },
36500
+ "from-snapshot": {
36501
+ type: "string",
36502
+ description: "Pin recovery to a specific snapshot \u2014 absolute path or ISO timestamp prefix (e.g. 2026-05-23)",
36503
+ default: ""
36504
+ },
36505
+ "no-delta": {
36506
+ type: "boolean",
36507
+ description: "Skip the sqlite3 .recover delta-merge step (reserved \u2014 current pipeline does not delta-merge; flag plumbed for forward-compat)",
36508
+ default: false
36509
+ },
36510
+ force: {
36511
+ type: "boolean",
36512
+ description: "Bypass any safety prompts (currently a no-op; reserved)",
36513
+ default: false
36514
+ }
36515
+ },
36516
+ subCommands: {
36517
+ brain: backupRecoverBrainLeaf
36518
+ },
36519
+ async run({ args }) {
36520
+ const argsBag = args;
36521
+ const roleArg = readStringFlag(argsBag, "role");
36522
+ if (roleArg.length === 0) {
36523
+ const validRoles = DB_INVENTORY.map((e) => e.role).join(", ");
36524
+ cliError(
36525
+ `Missing role. Try \`cleo backup recover <role>\` (one of: ${validRoles}).`,
36526
+ 6 /* VALIDATION_ERROR */,
36527
+ {
36528
+ name: "E_VALIDATION",
36529
+ fix: "Run `cleo backup recover --help` to see available roles and flags."
36530
+ },
36531
+ { operation: "backup.recover" }
36532
+ );
36533
+ process.exitCode = 6 /* VALIDATION_ERROR */;
36534
+ return;
36535
+ }
36536
+ let role;
36537
+ try {
36538
+ role = parseRoleArg(roleArg);
36539
+ } catch (err) {
36540
+ if (err instanceof BackupRecoverError) {
36541
+ cliError(
36542
+ err.message,
36543
+ err.code,
36544
+ {
36545
+ name: err.codeName,
36546
+ ...err.fix ? { fix: err.fix } : {}
36547
+ },
36548
+ { operation: "backup.recover" }
36549
+ );
36550
+ process.exitCode = err.code;
36551
+ return;
36552
+ }
36553
+ throw err;
36554
+ }
36555
+ executeRecover(role, argsBag);
36556
+ }
36557
+ });
36558
+ }
36559
+ });
36560
+
36561
+ // packages/cleo/src/cli/commands/backup-verify.ts
36562
+ import { getProjectRoot as getProjectRoot28 } from "@cleocode/core";
36563
+ import { runBackupVerify } from "@cleocode/core/store/backup-verify.js";
36564
+ var backupVerifySubCommand;
36565
+ var init_backup_verify = __esm({
36566
+ "packages/cleo/src/cli/commands/backup-verify.ts"() {
36567
+ "use strict";
36568
+ init_src2();
36569
+ init_define_cli_command();
36570
+ init_renderers();
36571
+ backupVerifySubCommand = defineCommand({
36572
+ meta: {
36573
+ name: "verify",
36574
+ description: "Walk DB_INVENTORY and report per-DB freshness + integrity for each snapshot in BOTH .cleo/backups/sqlite/ (canonical) and .cleo/backups/snapshot/ (legacy). Exits non-zero on any stale/corrupt finding."
36575
+ },
36576
+ args: {
36577
+ "per-db-timeout-ms": {
36578
+ type: "string",
36579
+ description: "Per-DB integrity-check timeout in milliseconds (default: 30000).",
36580
+ default: "30000"
36581
+ },
36582
+ json: { type: "boolean", description: "Output as JSON" },
36583
+ human: { type: "boolean", description: "Force human-readable output" },
36584
+ quiet: { type: "boolean", description: "Suppress non-essential output" }
36585
+ },
36586
+ async run({ args }) {
36587
+ const argsBag = args;
36588
+ const rawTimeout = argsBag["per-db-timeout-ms"];
36589
+ let perDbTimeoutMs = 3e4;
36590
+ if (typeof rawTimeout === "string" && rawTimeout.length > 0) {
36591
+ const parsed = Number.parseInt(rawTimeout, 10);
36592
+ if (!Number.isFinite(parsed) || parsed <= 0) {
36593
+ cliError(
36594
+ `Invalid --per-db-timeout-ms value: ${rawTimeout}`,
36595
+ 6 /* VALIDATION_ERROR */,
36596
+ {
36597
+ name: "E_VALIDATION",
36598
+ fix: "Provide a positive integer number of milliseconds (e.g. --per-db-timeout-ms 30000)."
36599
+ },
36600
+ { operation: "backup.verify" }
36601
+ );
36602
+ process.exitCode = 6 /* VALIDATION_ERROR */;
36603
+ return;
36604
+ }
36605
+ perDbTimeoutMs = parsed;
36606
+ }
36607
+ let result;
36608
+ try {
36609
+ result = runBackupVerify({
36610
+ projectRoot: getProjectRoot28(),
36611
+ perDbTimeoutMs
36612
+ });
36613
+ } catch (err) {
36614
+ const message = err instanceof Error ? err.message : String(err);
36615
+ cliError(
36616
+ message,
36617
+ 1 /* GENERAL_ERROR */,
36618
+ { name: "E_BACKUP_VERIFY_FAILED" },
36619
+ { operation: "backup.verify" }
36620
+ );
36621
+ process.exitCode = 1 /* GENERAL_ERROR */;
36622
+ return;
36623
+ }
36624
+ cliOutput(result, {
36625
+ command: "backup",
36626
+ operation: "backup.verify"
36627
+ });
36628
+ if ((result.summary.corrupt > 0 || result.summary.stale > 0) && (process.exitCode === void 0 || process.exitCode === 0)) {
36629
+ process.exitCode = 1 /* GENERAL_ERROR */;
36630
+ }
36631
+ }
36632
+ });
36633
+ }
36634
+ });
36635
+
36116
36636
  // packages/cleo/src/cli/commands/backup.ts
36117
36637
  var backup_exports = {};
36118
36638
  __export(backup_exports, {
@@ -36184,6 +36704,8 @@ var init_backup = __esm({
36184
36704
  init_paths();
36185
36705
  init_renderers();
36186
36706
  init_backup_inspect();
36707
+ init_backup_recover();
36708
+ init_backup_verify();
36187
36709
  addCommand2 = defineCommand({
36188
36710
  meta: {
36189
36711
  name: "add",
@@ -36267,9 +36789,9 @@ var init_backup = __esm({
36267
36789
  async run({ args }) {
36268
36790
  const scope = args.scope;
36269
36791
  const { packBundle } = await import("@cleocode/core/store/backup-pack.js");
36270
- const { getProjectRoot: getProjectRoot44 } = await import("@cleocode/core");
36792
+ const { getProjectRoot: getProjectRoot48 } = await import("@cleocode/core");
36271
36793
  const includesProject = scope === "project" || scope === "all";
36272
- const projectRoot = includesProject ? getProjectRoot44() : void 0;
36794
+ const projectRoot = includesProject ? getProjectRoot48() : void 0;
36273
36795
  let passphrase;
36274
36796
  if (args.encrypt === true) {
36275
36797
  passphrase = process.env["CLEO_BACKUP_PASSPHRASE"];
@@ -36345,12 +36867,12 @@ var init_backup = __esm({
36345
36867
  },
36346
36868
  async run({ args }) {
36347
36869
  const bundlePath = args.bundle;
36348
- const { getProjectRoot: getProjectRoot44, getCleoHome: getCleoHome6, getCleoVersion } = await import("@cleocode/core");
36870
+ const { getProjectRoot: getProjectRoot48, getCleoHome: getCleoHome6, getCleoVersion } = await import("@cleocode/core");
36349
36871
  const { BundleError, cleanupStaging, unpackBundle } = await import("@cleocode/core/store/backup-unpack.js");
36350
36872
  const { regenerateConfigJson, regenerateProjectContextJson, regenerateProjectInfoJson } = await import("@cleocode/core/store/regenerators.js");
36351
36873
  const { regenerateAndCompare } = await import("@cleocode/core/store/restore-json-merge.js");
36352
36874
  const { buildConflictReport, writeConflictReport } = await import("@cleocode/core/store/restore-conflict-report.js");
36353
- const projectRoot = getProjectRoot44();
36875
+ const projectRoot = getProjectRoot48();
36354
36876
  if (args.force !== true) {
36355
36877
  const existing = checkForExistingData(projectRoot, getCleoHome6());
36356
36878
  if (existing.length > 0) {
@@ -36518,7 +37040,9 @@ var init_backup = __esm({
36518
37040
  list: listCommand4,
36519
37041
  export: exportCommand,
36520
37042
  import: importCommand,
36521
- inspect: backupInspectSubCommand
37043
+ inspect: backupInspectSubCommand,
37044
+ recover: backupRecoverSubCommand,
37045
+ verify: backupVerifySubCommand
36522
37046
  },
36523
37047
  async run({ cmd, rawArgs }) {
36524
37048
  if (isSubCommandDispatch(rawArgs, cmd.subCommands)) return;
@@ -36568,7 +37092,7 @@ var brain_exports = {};
36568
37092
  __export(brain_exports, {
36569
37093
  brainCommand: () => brainCommand
36570
37094
  });
36571
- import { getProjectRoot as getProjectRoot27 } from "@cleocode/core";
37095
+ import { getProjectRoot as getProjectRoot29 } from "@cleocode/core";
36572
37096
  import {
36573
37097
  backfillBrainGraph,
36574
37098
  exportBrainAsGexf,
@@ -36613,7 +37137,7 @@ var init_brain2 = __esm({
36613
37137
  json: { type: "boolean", description: "Output results as JSON" }
36614
37138
  },
36615
37139
  async run({ args }) {
36616
- const root = getProjectRoot27();
37140
+ const root = getProjectRoot29();
36617
37141
  try {
36618
37142
  const result = await runBrainMaintenance(root, {
36619
37143
  skipDecay: !!args["skip-decay"],
@@ -36684,7 +37208,7 @@ var init_brain2 = __esm({
36684
37208
  json: { type: "boolean", description: "Output results as JSON" }
36685
37209
  },
36686
37210
  async run({ args: _args }) {
36687
- const root = getProjectRoot27();
37211
+ const root = getProjectRoot29();
36688
37212
  try {
36689
37213
  const result = await backfillBrainGraph(root);
36690
37214
  cliOutput(
@@ -36725,7 +37249,7 @@ var init_brain2 = __esm({
36725
37249
  json: { type: "boolean", description: "Output results as JSON" }
36726
37250
  },
36727
37251
  async run({ args: _args }) {
36728
- const root = getProjectRoot27();
37252
+ const root = getProjectRoot29();
36729
37253
  try {
36730
37254
  const result = await purgeBrainNoise(root);
36731
37255
  cliOutput(
@@ -36771,7 +37295,7 @@ var init_brain2 = __esm({
36771
37295
  json: { type: "boolean", description: "Output results as JSON" }
36772
37296
  },
36773
37297
  async run({ args }) {
36774
- const root = getProjectRoot27();
37298
+ const root = getProjectRoot29();
36775
37299
  const limit = Number.parseInt(args.limit, 10) || 20;
36776
37300
  try {
36777
37301
  const stats = await getPlasticityStats(root, limit);
@@ -36821,7 +37345,7 @@ var init_brain2 = __esm({
36821
37345
  json: { type: "boolean", description: "Output results as JSON" }
36822
37346
  },
36823
37347
  async run({ args: _args }) {
36824
- const root = getProjectRoot27();
37348
+ const root = getProjectRoot29();
36825
37349
  try {
36826
37350
  const report = await getMemoryQualityReport(root);
36827
37351
  cliOutput(
@@ -36870,7 +37394,7 @@ var init_brain2 = __esm({
36870
37394
  }
36871
37395
  },
36872
37396
  async run({ args }) {
36873
- const root = getProjectRoot27();
37397
+ const root = getProjectRoot29();
36874
37398
  const format = args.format ?? "gexf";
36875
37399
  if (format !== "gexf" && format !== "json") {
36876
37400
  cliError(`Invalid format: ${format}. Use 'gexf' or 'json'.`, "E_VALIDATION", {
@@ -37688,7 +38212,13 @@ __export(changeset_exports, {
37688
38212
  });
37689
38213
  import { existsSync as existsSync11 } from "node:fs";
37690
38214
  import { join as join14 } from "node:path";
37691
- import { changesets, dataTable, getProjectRoot as getProjectRoot28 } from "@cleocode/core";
38215
+ import {
38216
+ changesets,
38217
+ dataTable,
38218
+ detectStrayCleoDb,
38219
+ getProjectRoot as getProjectRoot30,
38220
+ resolveWorktreeRouting
38221
+ } from "@cleocode/core";
37692
38222
  function isValidKind(raw) {
37693
38223
  return typeof raw === "string" && CHANGESET_KINDS.includes(raw);
37694
38224
  }
@@ -37782,7 +38312,25 @@ var init_changeset = __esm({
37782
38312
  ...typeof args.notes === "string" && args.notes.length > 0 ? { notes: args.notes } : {},
37783
38313
  ...typeof args.breaking === "string" && args.breaking.length > 0 ? { breaking: args.breaking } : {}
37784
38314
  };
37785
- const projectRoot = getProjectRoot28();
38315
+ const routing = resolveWorktreeRouting();
38316
+ const strayDb = detectStrayCleoDb(routing);
38317
+ if (strayDb) {
38318
+ cliError(
38319
+ `stray .cleo/tasks.db detected inside worktree at ${routing.worktreePath}. This is a leaked CLEO state directory.`,
38320
+ 6 /* VALIDATION_ERROR */,
38321
+ {
38322
+ name: "E_STRAY_WORKTREE_DB",
38323
+ fix: `Remove it with: rm -rf ${routing.worktreePath}/.cleo \u2014 then retry. See ADR-068 \xA73 for the worktree DB isolation rationale.`
38324
+ }
38325
+ );
38326
+ process.exit(6 /* VALIDATION_ERROR */);
38327
+ }
38328
+ if (routing.isWorktree && process.env["CLEO_QUIET"] !== "1") {
38329
+ const routingLog = `[T10389] routing SSoT write from worktree cwd ${routing.cwd} \u2192 canonical project root ${routing.canonicalRoot}
38330
+ `;
38331
+ process.stderr.write(routingLog);
38332
+ }
38333
+ const projectRoot = routing.canonicalRoot;
37786
38334
  const outcome = await changesets.writeChangesetEntry(entry, {
37787
38335
  projectRoot,
37788
38336
  ...typeof args["attached-by"] === "string" && args["attached-by"].length > 0 ? { attachedBy: args["attached-by"] } : {}
@@ -37809,7 +38357,7 @@ var init_changeset = __esm({
37809
38357
  },
37810
38358
  args: {},
37811
38359
  async run() {
37812
- const projectRoot = getProjectRoot28();
38360
+ const projectRoot = getProjectRoot30();
37813
38361
  const dir = join14(projectRoot, ".changeset");
37814
38362
  if (!existsSync11(dir)) {
37815
38363
  const empty = { entries: [], count: 0, dir, note: "no .changeset/ dir" };
@@ -40543,17 +41091,18 @@ var init_colors = __esm({
40543
41091
  // packages/cleo/src/cli/renderers/generic-tree.ts
40544
41092
  import { ascii as ascii2, KindIcon as KindIcon2, pickIcon, RelationIcon } from "@cleocode/contracts/render/icon.js";
40545
41093
  function renderGenericTree(result, opts) {
41094
+ const explicitCtx = opts.ctx !== void 0;
40546
41095
  const ctx = opts.ctx ?? resolveAnimateContext();
40547
41096
  if (!ctx.enabled) return "";
40548
41097
  if (opts.quiet) return renderQuiet(result);
40549
- const useAscii = ctx.inputs.noColor;
41098
+ const useAscii = explicitCtx ? ctx.inputs.noColor : ctx.inputs.noColor || process.env["NO_COLOR"] != null;
40550
41099
  const lines = [];
40551
41100
  if (result.ancestors.length > 0) {
40552
41101
  lines.push(formatAncestorBanner(result.ancestors, useAscii));
40553
41102
  lines.push("");
40554
41103
  }
40555
41104
  const treeWithGlyphs = decorateGroupsEdges(result.tree, useAscii);
40556
- const body = renderTree(treeWithGlyphs, { ctx });
41105
+ const body = renderTree(treeWithGlyphs, { ctx, asciiBoxDrawing: useAscii });
40557
41106
  if (body) lines.push(body);
40558
41107
  if (opts.withDeps || opts.withBlockers) {
40559
41108
  const annotations = renderAnnotations(result.tree, opts);
@@ -40617,7 +41166,15 @@ function kindIconOf(kind) {
40617
41166
  }
40618
41167
  }
40619
41168
  function resolveAnimateContext() {
40620
- return createAnimateContext({ flagResolution: getFormatContext() });
41169
+ const fmt = getFormatContext();
41170
+ if (fmt.format !== "human") {
41171
+ return createAnimateContext({ flagResolution: fmt });
41172
+ }
41173
+ return createAnimateContext({
41174
+ flagResolution: fmt,
41175
+ isTTY: true,
41176
+ noColor: false
41177
+ });
40621
41178
  }
40622
41179
  var init_generic_tree = __esm({
40623
41180
  "packages/cleo/src/cli/renderers/generic-tree.ts"() {
@@ -41422,6 +41979,184 @@ var init_diagnostics2 = __esm({
41422
41979
  }
41423
41980
  });
41424
41981
 
41982
+ // packages/cleo/src/cli/lib/did-you-mean.ts
41983
+ function levenshteinDistance(input2, candidate) {
41984
+ const inputLen = input2.length;
41985
+ const candidateLen = candidate.length;
41986
+ const matrix = Array.from({ length: inputLen + 1 }, (_, i) => [i]);
41987
+ for (let j = 1; j <= candidateLen; j++) {
41988
+ matrix[0][j] = j;
41989
+ }
41990
+ for (let i = 1; i <= inputLen; i++) {
41991
+ for (let j = 1; j <= candidateLen; j++) {
41992
+ const cost = input2[i - 1] === candidate[j - 1] ? 0 : 1;
41993
+ matrix[i][j] = Math.min(
41994
+ matrix[i - 1][j] + 1,
41995
+ // deletion
41996
+ matrix[i][j - 1] + 1,
41997
+ // insertion
41998
+ matrix[i - 1][j - 1] + cost
41999
+ // substitution
42000
+ );
42001
+ }
42002
+ }
42003
+ return matrix[inputLen][candidateLen];
42004
+ }
42005
+ function didYouMean(input2, candidates, maxDistance = 2) {
42006
+ const suggestions = candidates.map((candidate) => ({
42007
+ command: candidate,
42008
+ distance: levenshteinDistance(input2, candidate)
42009
+ })).filter((item) => item.distance <= maxDistance).sort((a, b) => {
42010
+ if (a.distance !== b.distance) {
42011
+ return a.distance - b.distance;
42012
+ }
42013
+ return a.command.localeCompare(b.command);
42014
+ }).map((item) => item.command);
42015
+ return suggestions;
42016
+ }
42017
+ var init_did_you_mean = __esm({
42018
+ "packages/cleo/src/cli/lib/did-you-mean.ts"() {
42019
+ "use strict";
42020
+ }
42021
+ });
42022
+
42023
+ // packages/cleo/src/cli/lib/strict-args.ts
42024
+ function collectKnownLongFlags(schema2) {
42025
+ const known = /* @__PURE__ */ new Set();
42026
+ for (const [name, def] of Object.entries(schema2)) {
42027
+ if (!def || def.type === "positional") continue;
42028
+ known.add(`--${name}`);
42029
+ if (def.type === "boolean") {
42030
+ known.add(`--no-${name}`);
42031
+ }
42032
+ const alias2 = def.alias;
42033
+ if (typeof alias2 === "string" && alias2.length > 0) {
42034
+ known.add(alias2.length === 1 ? `-${alias2}` : `--${alias2}`);
42035
+ } else if (Array.isArray(alias2)) {
42036
+ for (const a of alias2) {
42037
+ if (typeof a !== "string" || a.length === 0) continue;
42038
+ known.add(a.length === 1 ? `-${a}` : `--${a}`);
42039
+ }
42040
+ }
42041
+ }
42042
+ return known;
42043
+ }
42044
+ function collectSuggestionCandidates(schema2) {
42045
+ const candidates = [];
42046
+ for (const [name, def] of Object.entries(schema2)) {
42047
+ if (!def || def.type === "positional") continue;
42048
+ candidates.push(`--${name}`);
42049
+ }
42050
+ return candidates.sort();
42051
+ }
42052
+ function assertKnownFlags(rawArgs, schema2, commandName) {
42053
+ if (!rawArgs || rawArgs.length === 0) return;
42054
+ if (schema2 === void 0) return;
42055
+ if (typeof schema2 === "function" || typeof schema2 === "object" && schema2 !== null && "then" in schema2) {
42056
+ return;
42057
+ }
42058
+ const resolved = schema2;
42059
+ const known = collectKnownLongFlags(resolved);
42060
+ const candidates = collectSuggestionCandidates(resolved);
42061
+ for (let i = 0; i < rawArgs.length; i++) {
42062
+ const token = rawArgs[i];
42063
+ if (token === void 0) continue;
42064
+ if (token === "--") break;
42065
+ if (!token.startsWith("-")) continue;
42066
+ if (token === "-") continue;
42067
+ if (token.startsWith("--")) {
42068
+ const eqIdx = token.indexOf("=");
42069
+ const flagName = eqIdx >= 0 ? token.slice(0, eqIdx) : token;
42070
+ if (!known.has(flagName)) {
42071
+ throw new UnknownFlagError({
42072
+ flag: flagName,
42073
+ command: commandName,
42074
+ suggestions: didYouMean(flagName, candidates, 3),
42075
+ knownFlags: [...known].sort()
42076
+ });
42077
+ }
42078
+ } else {
42079
+ const eqIdx = token.indexOf("=");
42080
+ const body = eqIdx >= 0 ? token.slice(1, eqIdx) : token.slice(1);
42081
+ const first = `-${body[0]}`;
42082
+ if (!known.has(first)) {
42083
+ throw new UnknownFlagError({
42084
+ flag: first,
42085
+ command: commandName,
42086
+ suggestions: didYouMean(first, candidates, 3),
42087
+ knownFlags: [...known].sort()
42088
+ });
42089
+ }
42090
+ if (eqIdx < 0 && body.length > 1) {
42091
+ const isBooleanShort = isBooleanAlias(resolved, body[0]);
42092
+ if (isBooleanShort) {
42093
+ for (let k = 1; k < body.length; k++) {
42094
+ const ch = body[k];
42095
+ if (ch === void 0) continue;
42096
+ const short = `-${ch}`;
42097
+ if (!known.has(short)) {
42098
+ throw new UnknownFlagError({
42099
+ flag: short,
42100
+ command: commandName,
42101
+ suggestions: didYouMean(short, candidates, 3),
42102
+ knownFlags: [...known].sort()
42103
+ });
42104
+ }
42105
+ }
42106
+ }
42107
+ }
42108
+ }
42109
+ }
42110
+ }
42111
+ function isBooleanAlias(schema2, letter) {
42112
+ if (!letter) return false;
42113
+ for (const def of Object.values(schema2)) {
42114
+ if (!def || def.type !== "boolean") continue;
42115
+ const alias2 = def.alias;
42116
+ if (alias2 === letter) return true;
42117
+ if (Array.isArray(alias2) && alias2.includes(letter)) return true;
42118
+ }
42119
+ return false;
42120
+ }
42121
+ var E_UNKNOWN_FLAG, UnknownFlagError;
42122
+ var init_strict_args = __esm({
42123
+ "packages/cleo/src/cli/lib/strict-args.ts"() {
42124
+ "use strict";
42125
+ init_did_you_mean();
42126
+ E_UNKNOWN_FLAG = "E_UNKNOWN_FLAG";
42127
+ UnknownFlagError = class extends Error {
42128
+ /** Stable LAFS error code string for envelope emission. */
42129
+ code = E_UNKNOWN_FLAG;
42130
+ /** The unknown flag token as it appeared in `rawArgs` (e.g. `--titel`, `-X`). */
42131
+ flag;
42132
+ /** Human-readable command label (e.g. `'docs add'`). */
42133
+ command;
42134
+ /** Did-you-mean suggestions, sorted by Levenshtein distance ascending. */
42135
+ suggestions;
42136
+ /** The full list of known flags accepted by the command (long form + short). */
42137
+ knownFlags;
42138
+ /** Suggested fix string for {@link CliErrorDetails.fix}. */
42139
+ fix;
42140
+ /**
42141
+ * @param input - Structured failure context: offending flag, command
42142
+ * label, ranked suggestions, and the full known-flag set.
42143
+ */
42144
+ constructor(input2) {
42145
+ const suggestionPart = input2.suggestions.length > 0 ? ` Did you mean: ${input2.suggestions.join(", ")}?` : "";
42146
+ super(
42147
+ `${E_UNKNOWN_FLAG}: unknown flag '${input2.flag}' for '${input2.command}'.${suggestionPart}`
42148
+ );
42149
+ this.name = "UnknownFlagError";
42150
+ this.flag = input2.flag;
42151
+ this.command = input2.command;
42152
+ this.suggestions = input2.suggestions;
42153
+ this.knownFlags = input2.knownFlags;
42154
+ this.fix = input2.suggestions.length > 0 ? `Try one of: ${input2.suggestions.join(", ")}. Run \`cleo ${input2.command} --help\` for the full flag list.` : `Run \`cleo ${input2.command} --help\` for the full flag list.`;
42155
+ }
42156
+ };
42157
+ }
42158
+ });
42159
+
41425
42160
  // packages/cleo/src/viewer/pidfile.ts
41426
42161
  import { mkdir, readFile as readFile2, unlink, writeFile } from "node:fs/promises";
41427
42162
  import { dirname as dirname6, join as join18 } from "node:path";
@@ -41531,7 +42266,7 @@ import { dirname as dirname7, join as join19, normalize, resolve as resolve4 } f
41531
42266
  import { fileURLToPath as fileURLToPath4 } from "node:url";
41532
42267
  import {
41533
42268
  createAttachmentStore as createAttachmentStore5,
41534
- getProjectRoot as getProjectRoot29,
42269
+ getProjectRoot as getProjectRoot31,
41535
42270
  searchAllProjectDocs
41536
42271
  } from "@cleocode/core/internal";
41537
42272
  function getViewerAssetsDir() {
@@ -41591,7 +42326,7 @@ async function serveStatic(res, assetsDir, relPath) {
41591
42326
  }
41592
42327
  }
41593
42328
  function buildViewerHandler(opts = {}) {
41594
- const projectRoot = opts.projectRoot ?? getProjectRoot29();
42329
+ const projectRoot = opts.projectRoot ?? getProjectRoot31();
41595
42330
  const assetsDir = getViewerAssetsDir();
41596
42331
  const store = createAttachmentStore5();
41597
42332
  return async (req, res) => {
@@ -41769,7 +42504,7 @@ import { spawn } from "node:child_process";
41769
42504
  import { open as fsOpen } from "node:fs/promises";
41770
42505
  import { join as join20 } from "node:path";
41771
42506
  import { fileURLToPath as fileURLToPath5 } from "node:url";
41772
- import { getCleoHome as getCleoHome3, getProjectRoot as getProjectRoot30 } from "@cleocode/core";
42507
+ import { getCleoHome as getCleoHome3, getProjectRoot as getProjectRoot32 } from "@cleocode/core";
41773
42508
  function getCleoBinPath() {
41774
42509
  const thisFile = fileURLToPath5(import.meta.url);
41775
42510
  return join20(thisFile, "..", "..", "index.js");
@@ -41820,7 +42555,7 @@ async function spawnDetachedServer(opts) {
41820
42555
  detached: true,
41821
42556
  stdio,
41822
42557
  env: { ...process.env, [DETACHED_CHILD_ENV]: "1" },
41823
- cwd: getProjectRoot30()
42558
+ cwd: getProjectRoot32()
41824
42559
  });
41825
42560
  child.unref();
41826
42561
  if (handle) await handle.close();
@@ -41972,7 +42707,7 @@ var init_docs_viewer = __esm({
41972
42707
  pid: process.pid,
41973
42708
  port: handle.port,
41974
42709
  host: handle.host,
41975
- projectRoot: getProjectRoot30(),
42710
+ projectRoot: getProjectRoot32(),
41976
42711
  startedAt: Date.now()
41977
42712
  };
41978
42713
  await writeViewerPidFile(record);
@@ -42253,10 +42988,14 @@ import {
42253
42988
  buildDocsGraph,
42254
42989
  CleoError as CleoError3,
42255
42990
  CounterMismatchError,
42991
+ checkSlugSimilarity,
42256
42992
  createAttachmentStoreDocsAccessor,
42993
+ DEFAULT_SIMILARITY_MODE,
42994
+ DEFAULT_SIMILARITY_THRESHOLD,
42995
+ detectStrayCleoDb as detectStrayCleoDb2,
42257
42996
  exportDocument,
42258
42997
  getAgentOutputsAbsolute,
42259
- getProjectRoot as getProjectRoot31,
42998
+ getProjectRoot as getProjectRoot33,
42260
42999
  listDocVersions,
42261
43000
  makeClassifierForScanRoot,
42262
43001
  mergeDocs,
@@ -42265,6 +43004,8 @@ import {
42265
43004
  rankDocs,
42266
43005
  readJson,
42267
43006
  recordPublication,
43007
+ resolveWorktreeFilePath,
43008
+ resolveWorktreeRouting as resolveWorktreeRouting2,
42268
43009
  runDocsImport,
42269
43010
  searchAllProjectDocs as searchAllProjectDocs2,
42270
43011
  searchDocs as searchDocs2,
@@ -42365,12 +43106,14 @@ var init_docs3 = __esm({
42365
43106
  init_src2();
42366
43107
  init_dist();
42367
43108
  init_cli();
43109
+ init_canon_docs();
43110
+ init_strict_args();
42368
43111
  init_renderers();
42369
43112
  init_docs_viewer();
42370
43113
  addCommand5 = defineCommand({
42371
43114
  meta: {
42372
43115
  name: "add",
42373
- description: "Attach a local file or remote URL to a CLEO entity (task, session, observation). Owner type is inferred from the ID prefix: T### \u2192 task, ses_* \u2192 session, O-* \u2192 observation. Use --slug to set a human-friendly alias (unique per project) (T9636)."
43116
+ description: 'Attach a local file or remote URL to a CLEO entity (task, session, observation). Owner type is inferred from the ID prefix: T### \u2192 task, ses_* \u2192 session, O-* \u2192 observation. Use --slug to set a human-friendly alias (unique per project) (T9636).\n\nPositional arguments:\n <owner-id> Owner entity ID (T###, ses_*, O-*) \u2014 required\n [file] Local file path to attach \u2014 optional when --url is set\n\nNamed arguments:\n --url <url> Remote URL to attach (instead of a local file)\n --desc <text> Free-text description of this attachment\n --labels <csv> Comma-separated labels (e.g. rfc,spec)\n --attached-by <name> Agent identity that created the attachment (default: "human")\n --slug <kebab> Human-friendly alias, unique per project (T9636)\n --type <kind> Taxonomy classification \u2014 run `cleo docs list-types` for kinds\n\nUnknown flags are rejected with E_UNKNOWN_FLAG + did-you-mean suggestions (T10359).'
42374
43117
  },
42375
43118
  args: {
42376
43119
  "owner-id": {
@@ -42401,17 +43144,36 @@ var init_docs3 = __esm({
42401
43144
  },
42402
43145
  slug: {
42403
43146
  type: "string",
42404
- description: "Human-friendly kebab-case alias for the attachment, unique per project (T9636). Collision returns E_SLUG_TAKEN with 3 alternative suggestions."
43147
+ description: "Human-friendly kebab-case alias for the attachment, unique per project (T9636). Collision returns E_SLUG_RESERVED with 3 alternative suggestions (legacy E_SLUG_TAKEN aliased under details.aliases for one release \u2014 T10386)."
42405
43148
  },
42406
43149
  type: {
42407
43150
  type: "string",
42408
43151
  description: "Taxonomy classification \u2014 run `cleo docs list-types` to enumerate registered kinds (T9637 / T9788)"
43152
+ },
43153
+ "allow-similar": {
43154
+ type: "boolean",
43155
+ description: "Bypass the T10361 slug-similarity check. Use when you really do mean to add a new doc with a near-duplicate slug (e.g. intentional fork). Every bypass is logged to .cleo/audit/similar-bypass.jsonl."
42409
43156
  }
42410
43157
  },
42411
- async run({ args }) {
43158
+ async run({ args, rawArgs }) {
43159
+ try {
43160
+ assertKnownFlags(rawArgs, addCommand5.args, "docs add");
43161
+ } catch (err) {
43162
+ if (err instanceof UnknownFlagError) {
43163
+ cliError(err.message, 6 /* VALIDATION_ERROR */, {
43164
+ name: err.code,
43165
+ fix: err.fix,
43166
+ alternatives: err.suggestions.map((s) => ({ action: s, command: s })),
43167
+ details: { flag: err.flag, knownFlags: err.knownFlags }
43168
+ });
43169
+ process.exit(6 /* VALIDATION_ERROR */);
43170
+ }
43171
+ throw err;
43172
+ }
42412
43173
  const ownerId = args["owner-id"];
42413
43174
  const fileArg = args.file ?? void 0;
42414
43175
  const url = args.url ?? void 0;
43176
+ const allowSimilar = args["allow-similar"] === true;
42415
43177
  if (!fileArg && !url) {
42416
43178
  cliError("provide a file path (positional argument) or --url <url>", 6, {
42417
43179
  name: "E_VALIDATION",
@@ -42419,13 +43181,113 @@ var init_docs3 = __esm({
42419
43181
  });
42420
43182
  process.exit(6);
42421
43183
  }
43184
+ let resolvedFile;
43185
+ if (fileArg) {
43186
+ const routing = resolveWorktreeRouting2();
43187
+ const strayDb = detectStrayCleoDb2(routing);
43188
+ if (strayDb) {
43189
+ cliError(
43190
+ `stray .cleo/tasks.db detected inside worktree at ${routing.worktreePath}. This is a leaked CLEO state directory.`,
43191
+ 6,
43192
+ {
43193
+ name: "E_STRAY_WORKTREE_DB",
43194
+ fix: `Remove it with: rm -rf ${routing.worktreePath}/.cleo \u2014 then retry. See ADR-068 \xA73 for the worktree DB isolation rationale.`
43195
+ }
43196
+ );
43197
+ process.exit(6);
43198
+ }
43199
+ if (routing.isWorktree && process.env["CLEO_QUIET"] !== "1") {
43200
+ const routingLog = `[T10389] routing SSoT write from worktree cwd ${routing.cwd} \u2192 canonical project root ${routing.canonicalRoot}
43201
+ `;
43202
+ process.stderr.write(routingLog);
43203
+ }
43204
+ resolvedFile = resolveWorktreeFilePath(String(fileArg), routing);
43205
+ }
43206
+ if (args.slug && args.type) {
43207
+ const projectRoot = await getProjectRoot33();
43208
+ let warnThreshold = DEFAULT_SIMILARITY_THRESHOLD;
43209
+ let mode = DEFAULT_SIMILARITY_MODE;
43210
+ try {
43211
+ const canon = loadCanonRegistry(projectRoot);
43212
+ if (canon?.similarity) {
43213
+ warnThreshold = canon.similarity.warnThreshold;
43214
+ mode = canon.similarity.mode;
43215
+ }
43216
+ } catch {
43217
+ }
43218
+ try {
43219
+ const sim = await checkSlugSimilarity({
43220
+ slug: args.slug,
43221
+ type: args.type,
43222
+ projectRoot,
43223
+ threshold: warnThreshold
43224
+ });
43225
+ if (sim.mostSimilarSlug !== null) {
43226
+ const scoreFixed = sim.score.toFixed(2);
43227
+ const hint = `Similar to '${sim.mostSimilarSlug}' (score ${scoreFixed}) \u2014 did you mean: cleo docs update ${sim.mostSimilarSlug}? Pass --allow-similar to bypass.`;
43228
+ if (mode === "block" && !allowSimilar) {
43229
+ cliError(hint, 6 /* VALIDATION_ERROR */, {
43230
+ name: "E_SLUG_SIMILARITY",
43231
+ fix: `Use \`cleo docs update ${sim.mostSimilarSlug}\` if updating, or pass --allow-similar to add as a new doc.`,
43232
+ alternatives: [
43233
+ {
43234
+ action: `update '${sim.mostSimilarSlug}' instead`,
43235
+ command: `cleo docs update ${sim.mostSimilarSlug}`
43236
+ },
43237
+ {
43238
+ action: "bypass the similarity check",
43239
+ command: `cleo docs add ${ownerId} ${fileArg ?? `--url ${url}`} --slug ${args.slug} --type ${args.type} --allow-similar`
43240
+ }
43241
+ ],
43242
+ details: {
43243
+ proposedSlug: args.slug,
43244
+ mostSimilarSlug: sim.mostSimilarSlug,
43245
+ score: sim.score,
43246
+ threshold: warnThreshold,
43247
+ kind: args.type
43248
+ }
43249
+ });
43250
+ process.exit(6 /* VALIDATION_ERROR */);
43251
+ }
43252
+ humanInfo(hint);
43253
+ if (allowSimilar) {
43254
+ const auditLine = `${JSON.stringify({
43255
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
43256
+ reason: "allow-similar-bypass",
43257
+ proposedSlug: args.slug,
43258
+ mostSimilarSlug: sim.mostSimilarSlug,
43259
+ score: sim.score,
43260
+ threshold: warnThreshold,
43261
+ kind: args.type,
43262
+ ownerId
43263
+ })}
43264
+ `;
43265
+ try {
43266
+ await mkdir2(join21(projectRoot, ".cleo", "audit"), { recursive: true });
43267
+ await appendFile(
43268
+ join21(projectRoot, ".cleo", "audit", "similar-bypass.jsonl"),
43269
+ auditLine,
43270
+ "utf-8"
43271
+ );
43272
+ } catch {
43273
+ }
43274
+ }
43275
+ }
43276
+ } catch (err) {
43277
+ if (process.env["CLEO_DEBUG"]) {
43278
+ humanInfo(
43279
+ `similarity check skipped: ${err instanceof Error ? err.message : String(err)}`
43280
+ );
43281
+ }
43282
+ }
43283
+ }
42422
43284
  await dispatchFromCli(
42423
43285
  "mutate",
42424
43286
  "docs",
42425
43287
  "add",
42426
43288
  {
42427
43289
  ownerId,
42428
- ...fileArg ? { file: fileArg } : {},
43290
+ ...resolvedFile ? { file: resolvedFile } : {},
42429
43291
  ...url ? { url } : {},
42430
43292
  ...args.desc ? { desc: args.desc } : {},
42431
43293
  ...args.labels ? { labels: args.labels } : {},
@@ -42642,7 +43504,7 @@ var init_docs3 = __esm({
42642
43504
  const taskId = String(args.task);
42643
43505
  const includeAttachments = args["include-attachments"] !== false;
42644
43506
  const includeMemoryRefs = args["include-memory-refs"] === true;
42645
- const projectRoot = getProjectRoot31();
43507
+ const projectRoot = getProjectRoot33();
42646
43508
  try {
42647
43509
  const result = await exportDocument({
42648
43510
  taskId,
@@ -42708,7 +43570,7 @@ var init_docs3 = __esm({
42708
43570
  }
42709
43571
  },
42710
43572
  async run({ args }) {
42711
- const projectRoot = getProjectRoot31();
43573
+ const projectRoot = getProjectRoot33();
42712
43574
  const limit = args.limit ? Number.parseInt(String(args.limit), 10) : 10;
42713
43575
  try {
42714
43576
  const result = args.owner ? await searchDocs2(String(args.query), {
@@ -42764,7 +43626,7 @@ var init_docs3 = __esm({
42764
43626
  }
42765
43627
  },
42766
43628
  async run({ args }) {
42767
- const projectRoot = getProjectRoot31();
43629
+ const projectRoot = getProjectRoot33();
42768
43630
  const rawStrategy = args.strategy ?? "three-way";
42769
43631
  const strategy = rawStrategy === "cherry-pick" || rawStrategy === "multi-diff" ? rawStrategy : "three-way";
42770
43632
  try {
@@ -42813,7 +43675,7 @@ var init_docs3 = __esm({
42813
43675
  }
42814
43676
  },
42815
43677
  async run({ args }) {
42816
- const projectRoot = getProjectRoot31();
43678
+ const projectRoot = getProjectRoot33();
42817
43679
  const fmt = args.format ?? "mermaid";
42818
43680
  try {
42819
43681
  const result = await buildDocsGraph({ ownerId: String(args.for), projectRoot });
@@ -42882,7 +43744,7 @@ var init_docs3 = __esm({
42882
43744
  }
42883
43745
  },
42884
43746
  async run({ args }) {
42885
- const projectRoot = getProjectRoot31();
43747
+ const projectRoot = getProjectRoot33();
42886
43748
  try {
42887
43749
  const result = await rankDocs({
42888
43750
  ownerId: String(args.for),
@@ -42920,7 +43782,7 @@ var init_docs3 = __esm({
42920
43782
  }
42921
43783
  },
42922
43784
  async run({ args }) {
42923
- const projectRoot = getProjectRoot31();
43785
+ const projectRoot = getProjectRoot33();
42924
43786
  try {
42925
43787
  const result = await listDocVersions({
42926
43788
  ownerId: String(args.for),
@@ -42963,7 +43825,7 @@ var init_docs3 = __esm({
42963
43825
  }
42964
43826
  },
42965
43827
  async run({ args }) {
42966
- const projectRoot = getProjectRoot31();
43828
+ const projectRoot = getProjectRoot33();
42967
43829
  try {
42968
43830
  const result = await publishDocs({
42969
43831
  ownerId: String(args.for),
@@ -43087,7 +43949,7 @@ var init_docs3 = __esm({
43087
43949
  },
43088
43950
  async run({ args }) {
43089
43951
  if (args.from) {
43090
- const projectRoot = getProjectRoot31();
43952
+ const projectRoot = getProjectRoot33();
43091
43953
  const ownerId = args.for ?? void 0;
43092
43954
  if (!ownerId) {
43093
43955
  cliError(
@@ -43154,7 +44016,7 @@ var init_docs3 = __esm({
43154
44016
  }
43155
44017
  },
43156
44018
  async run() {
43157
- const projectRoot = getProjectRoot31();
44019
+ const projectRoot = getProjectRoot33();
43158
44020
  try {
43159
44021
  const result = await statusDocs({ projectRoot });
43160
44022
  cliOutput(result, { command: "docs status", operation: "docs.status" });
@@ -43239,7 +44101,7 @@ var init_docs3 = __esm({
43239
44101
  }
43240
44102
  },
43241
44103
  async run({ args }) {
43242
- const projectRoot = getProjectRoot31();
44104
+ const projectRoot = getProjectRoot33();
43243
44105
  const dirArg = String(args.dir);
43244
44106
  const scanRoot = isAbsolute2(dirArg) ? dirArg : resolve5(projectRoot, dirArg);
43245
44107
  const dryRun = args["dry-run"] === true;
@@ -43313,7 +44175,7 @@ var init_docs3 = __esm({
43313
44175
  }
43314
44176
  },
43315
44177
  async run({ args }) {
43316
- const projectRoot = getProjectRoot31();
44178
+ const projectRoot = getProjectRoot33();
43317
44179
  const { registry, configError } = loadCliRegistry(projectRoot);
43318
44180
  const kinds = registry.list().map(toWireKind);
43319
44181
  const extensionsCount = kinds.filter((k) => k.isExtension).length;
@@ -43357,7 +44219,7 @@ var init_docs3 = __esm({
43357
44219
  }
43358
44220
  },
43359
44221
  async run({ args }) {
43360
- const projectRoot = getProjectRoot31();
44222
+ const projectRoot = getProjectRoot33();
43361
44223
  const { registry, configError } = loadCliRegistry(projectRoot);
43362
44224
  const kinds = registry.list().map(toWireKind);
43363
44225
  let counts2;
@@ -43435,6 +44297,235 @@ var init_docs3 = __esm({
43435
44297
  }
43436
44298
  });
43437
44299
 
44300
+ // packages/cleo/src/cli/commands/doctor-db-substrate.ts
44301
+ var doctor_db_substrate_exports = {};
44302
+ __export(doctor_db_substrate_exports, {
44303
+ doctorDbSubstrateCommand: () => doctorDbSubstrateCommand
44304
+ });
44305
+ import { getProjectRoot as getProjectRoot34, pushWarning as pushWarning2 } from "@cleocode/core";
44306
+ import { surveyDbSubstrate, surveyFleetDbSubstrate } from "@cleocode/core/doctor/db-substrate.js";
44307
+ function pushSubstrateWarnings(result) {
44308
+ for (const warning of result.warnings) {
44309
+ const context = {
44310
+ kind: warning.kind,
44311
+ path: warning.path,
44312
+ lastWriteMs: warning.lastWriteMs
44313
+ };
44314
+ if (warning.kind === "orphan-project-root") {
44315
+ context["parentWorkspace"] = warning.parentWorkspace ?? null;
44316
+ }
44317
+ pushWarning2({
44318
+ code: warning.kind === "orphan-project-root" ? "W_DB_SUBSTRATE_ORPHAN_PROJECT_ROOT" : "W_DB_SUBSTRATE_NESTED_NEXUS_DUPLICATE",
44319
+ message: warning.kind === "orphan-project-root" ? `Orphan project-root .cleo/ at ${warning.path} (T9550 regression class \u2014 review then remove)` + (warning.parentWorkspace ? ` \u2014 attributed to workspace: ${warning.parentWorkspace}` : "") : `Nested-nexus duplicate at ${warning.path} (structural duplicate of the canonical flat layout)`,
44320
+ severity: "warn",
44321
+ context
44322
+ });
44323
+ }
44324
+ for (const projectSurvey of result.projects) {
44325
+ for (const [role, entry] of Object.entries(projectSurvey.dbs)) {
44326
+ if (entry.pragmaDrift === null || entry.pragmaDrift.length === 0) continue;
44327
+ for (const drift of entry.pragmaDrift) {
44328
+ pushWarning2({
44329
+ code: "W_DB_SUBSTRATE_PRAGMA_DRIFT",
44330
+ message: `Pragma drift on ${role} (${entry.filePath}): expected ${drift.pragma}=${drift.expected}, actual=${drift.actual ?? "<unmeasurable>"}`,
44331
+ severity: "warn",
44332
+ context: {
44333
+ role,
44334
+ filePath: entry.filePath,
44335
+ pragma: drift.pragma,
44336
+ expected: drift.expected,
44337
+ actual: drift.actual
44338
+ }
44339
+ });
44340
+ }
44341
+ }
44342
+ }
44343
+ for (const report of result.crossDbOrphans) {
44344
+ if (report.skipped || report.orphanCount === 0) continue;
44345
+ pushWarning2({
44346
+ code: `W_DB_SUBSTRATE_CROSS_DB_${report.invariant}`,
44347
+ message: `${report.invariant}: ${report.orphanCount} orphan row${report.orphanCount === 1 ? "" : "s"} \u2014 ${report.description}. ${report.suggestedFix}`,
44348
+ severity: "warn",
44349
+ context: {
44350
+ invariant: report.invariant,
44351
+ orphanCount: report.orphanCount,
44352
+ sample: report.sample.join(","),
44353
+ suggestedFix: report.suggestedFix
44354
+ }
44355
+ });
44356
+ }
44357
+ }
44358
+ function pushPerDbWarnings(result) {
44359
+ for (const projectSurvey of result.projects) {
44360
+ for (const [role, dbEntry] of Object.entries(projectSurvey.dbs)) {
44361
+ if (dbEntry.quarantinedTo !== null) {
44362
+ pushWarning2({
44363
+ code: "W_DB_SUBSTRATE_AUTO_QUARANTINED",
44364
+ message: `Auto-quarantined corrupt ${role} DB at ${dbEntry.filePath} \u2192 ${dbEntry.quarantinedTo}. Recover via: cleo backup recover ${role}`,
44365
+ severity: "warn",
44366
+ context: {
44367
+ role,
44368
+ filePath: dbEntry.filePath,
44369
+ quarantinedTo: dbEntry.quarantinedTo,
44370
+ integrityCheckMs: dbEntry.integrityCheckMs
44371
+ }
44372
+ });
44373
+ }
44374
+ if (dbEntry.timedOut) {
44375
+ pushWarning2({
44376
+ code: "W_DB_SUBSTRATE_INTEGRITY_TIMEOUT",
44377
+ message: `integrity_check on ${role} DB at ${dbEntry.filePath} took ${dbEntry.integrityCheckMs}ms \u2014 slow substrate flagged for operator attention`,
44378
+ severity: "warn",
44379
+ context: {
44380
+ role,
44381
+ filePath: dbEntry.filePath,
44382
+ integrityCheckMs: dbEntry.integrityCheckMs
44383
+ }
44384
+ });
44385
+ }
44386
+ }
44387
+ }
44388
+ }
44389
+ var DEFAULT_FLEET_ROOT, doctorDbSubstrateCommand;
44390
+ var init_doctor_db_substrate = __esm({
44391
+ "packages/cleo/src/cli/commands/doctor-db-substrate.ts"() {
44392
+ "use strict";
44393
+ init_define_cli_command();
44394
+ init_renderers();
44395
+ DEFAULT_FLEET_ROOT = "/mnt/projects";
44396
+ doctorDbSubstrateCommand = defineCommand({
44397
+ meta: {
44398
+ name: "db-substrate",
44399
+ description: "Walk every DB in the inventory + report integrity, row counts, orphan dirs. Use --fleet for a multi-project survey under --fleet-root (default /mnt/projects)."
44400
+ },
44401
+ args: {
44402
+ fleet: {
44403
+ type: "boolean",
44404
+ description: "Multi-project survey \u2014 walk every .cleo/-bearing subdir under --fleet-root"
44405
+ },
44406
+ "fleet-root": {
44407
+ type: "string",
44408
+ description: "Fleet root path (default: /mnt/projects). Only used with --fleet."
44409
+ },
44410
+ "integrity-timeout-ms": {
44411
+ type: "string",
44412
+ description: "Wall-clock budget for each PRAGMA integrity_check call (ms; default 60000; 0 disables)."
44413
+ },
44414
+ "no-quarantine": {
44415
+ type: "boolean",
44416
+ description: "Disable auto-quarantine of corrupt DBs (leaves them in place; report-only mode)."
44417
+ },
44418
+ json: { type: "boolean", description: "Output as JSON" },
44419
+ human: { type: "boolean", description: "Force human-readable output" },
44420
+ quiet: { type: "boolean", description: "Suppress non-essential output" }
44421
+ },
44422
+ async run({ args }) {
44423
+ const isFleet = args.fleet === true;
44424
+ let parsedTimeoutMs;
44425
+ if (typeof args["integrity-timeout-ms"] === "string" && args["integrity-timeout-ms"].length > 0) {
44426
+ const n = Number.parseInt(args["integrity-timeout-ms"], 10);
44427
+ if (Number.isFinite(n) && n >= 0) {
44428
+ parsedTimeoutMs = n;
44429
+ }
44430
+ }
44431
+ const options = {
44432
+ ...parsedTimeoutMs !== void 0 ? { integrityCheckTimeoutMs: parsedTimeoutMs } : {},
44433
+ autoQuarantine: args["no-quarantine"] !== true
44434
+ };
44435
+ const result = isFleet ? surveyFleetDbSubstrate(
44436
+ typeof args["fleet-root"] === "string" && args["fleet-root"].length > 0 ? args["fleet-root"] : DEFAULT_FLEET_ROOT,
44437
+ options
44438
+ ) : surveyDbSubstrate(getProjectRoot34(), options);
44439
+ pushSubstrateWarnings(result);
44440
+ pushPerDbWarnings(result);
44441
+ cliOutput(result, {
44442
+ command: "doctor",
44443
+ operation: "doctor.db-substrate.run"
44444
+ });
44445
+ if (result.summary.corrupt > 0 && (process.exitCode === void 0 || process.exitCode === 0)) {
44446
+ process.exitCode = 2;
44447
+ }
44448
+ }
44449
+ });
44450
+ }
44451
+ });
44452
+
44453
+ // packages/cleo/src/cli/commands/doctor-legacy-backups.ts
44454
+ var doctor_legacy_backups_exports = {};
44455
+ __export(doctor_legacy_backups_exports, {
44456
+ doctorLegacyBackupsCommand: () => doctorLegacyBackupsCommand
44457
+ });
44458
+ import { getProjectRoot as getProjectRoot35 } from "@cleocode/core";
44459
+ import { pruneLegacyBackups, scanLegacyBackups } from "@cleocode/core/doctor/legacy-backups.js";
44460
+ function parsePositiveInt(raw, fallback) {
44461
+ if (raw === void 0 || raw === null) return fallback;
44462
+ const parsed = Number.parseInt(String(raw), 10);
44463
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
44464
+ return parsed;
44465
+ }
44466
+ var doctorLegacyBackupsCommand;
44467
+ var init_doctor_legacy_backups = __esm({
44468
+ "packages/cleo/src/cli/commands/doctor-legacy-backups.ts"() {
44469
+ "use strict";
44470
+ init_define_cli_command();
44471
+ init_renderers();
44472
+ doctorLegacyBackupsCommand = defineCommand({
44473
+ meta: {
44474
+ name: "legacy-backups",
44475
+ description: "Enumerate legacy *-pre-cleo.db.bak / brain.db.PRE-DUP-FIX-* / pre-untrack / rotation-overflow artefacts and report origin + retention recommendation. Use --prune to delete 'delete'-recommended files (always dry-run unless --no-dry-run is passed)."
44476
+ },
44477
+ args: {
44478
+ prune: {
44479
+ type: "boolean",
44480
+ description: "Remove every artefact whose recommendation is 'delete'. Defaults to --dry-run; pass --no-dry-run to physically remove."
44481
+ },
44482
+ "dry-run": {
44483
+ type: "boolean",
44484
+ description: "Combine with --prune to preview deletions without touching the filesystem.",
44485
+ default: true
44486
+ },
44487
+ "soft-retention-days": {
44488
+ type: "string",
44489
+ description: "Days under which artefacts are always kept (default 30)."
44490
+ },
44491
+ "hard-retention-days": {
44492
+ type: "string",
44493
+ description: "Days over which artefacts are eligible for prune (default 90)."
44494
+ },
44495
+ json: { type: "boolean", description: "Output as JSON" },
44496
+ human: { type: "boolean", description: "Force human-readable output" },
44497
+ quiet: { type: "boolean", description: "Suppress non-essential output" }
44498
+ },
44499
+ async run({ args }) {
44500
+ const softRetentionDays = parsePositiveInt(args["soft-retention-days"], 30);
44501
+ const hardRetentionDays = parsePositiveInt(args["hard-retention-days"], 90);
44502
+ const projectRoot = getProjectRoot35();
44503
+ let result;
44504
+ if (args.prune === true) {
44505
+ const dryRun = args["dry-run"] !== false;
44506
+ result = pruneLegacyBackups(projectRoot, {
44507
+ softRetentionDays,
44508
+ hardRetentionDays,
44509
+ dryRun
44510
+ });
44511
+ } else {
44512
+ result = scanLegacyBackups(projectRoot, {
44513
+ softRetentionDays,
44514
+ hardRetentionDays
44515
+ });
44516
+ }
44517
+ cliOutput(result, {
44518
+ command: "doctor",
44519
+ operation: "doctor.legacy-backups.run"
44520
+ });
44521
+ if (result.errors.length > 0 && (process.exitCode === void 0 || process.exitCode === 0)) {
44522
+ process.exitCode = 1;
44523
+ }
44524
+ }
44525
+ });
44526
+ }
44527
+ });
44528
+
43438
44529
  // packages/cleo/src/cli/commands/doctor-projects.ts
43439
44530
  var doctor_projects_exports = {};
43440
44531
  __export(doctor_projects_exports, {
@@ -43711,7 +44802,7 @@ __export(migrate_agents_v2_exports, {
43711
44802
  import { createHash as createHash2 } from "node:crypto";
43712
44803
  import { appendFileSync as appendFileSync2, existsSync as existsSync14, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync14 } from "node:fs";
43713
44804
  import { join as join22 } from "node:path";
43714
- import { getProjectRoot as getProjectRoot32, installAgentFromCant } from "@cleocode/core/internal";
44805
+ import { getProjectRoot as getProjectRoot36, installAgentFromCant } from "@cleocode/core/internal";
43715
44806
  import { openCleoDb as openCleoDb2 } from "@cleocode/core/store/open-cleo-db";
43716
44807
  function sha256Hex(bytes) {
43717
44808
  return createHash2("sha256").update(bytes).digest("hex");
@@ -43898,7 +44989,7 @@ var init_migrate_agents_v2 = __esm({
43898
44989
  }
43899
44990
  },
43900
44991
  async run({ args }) {
43901
- const projectRoot = getProjectRoot32();
44992
+ const projectRoot = getProjectRoot36();
43902
44993
  const verbose = args.quiet !== true;
43903
44994
  if (verbose) {
43904
44995
  humanInfo("Scanning .cleo/cant/agents/ and .cleo/agents/ for unregistered agents...");
@@ -43942,7 +45033,7 @@ __export(doctor_exports, {
43942
45033
  });
43943
45034
  import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "node:fs";
43944
45035
  import { join as join23 } from "node:path";
43945
- import { getProjectRoot as getProjectRoot33, pushWarning as pushWarning2 } from "@cleocode/core";
45036
+ import { getProjectRoot as getProjectRoot37, pushWarning as pushWarning3 } from "@cleocode/core";
43946
45037
  import {
43947
45038
  quarantineRogueCleoDir,
43948
45039
  scanRogueCleoDirs
@@ -44049,8 +45140,11 @@ var init_doctor = __esm({
44049
45140
  "use strict";
44050
45141
  init_dist();
44051
45142
  init_cli();
45143
+ init_subcommand_guard();
44052
45144
  init_progress();
44053
45145
  init_renderers();
45146
+ init_doctor_db_substrate();
45147
+ init_doctor_legacy_backups();
44054
45148
  init_doctor_projects();
44055
45149
  init_migrate_agents_v2();
44056
45150
  FIXTURE_ID_PATTERNS = [/^E\d+$/, /^T\d+EP$/];
@@ -44062,6 +45156,12 @@ var init_doctor = __esm({
44062
45156
  ];
44063
45157
  doctorCommand2 = defineCommand({
44064
45158
  meta: { name: "doctor", description: "Run system diagnostics and health checks" },
45159
+ subCommands: {
45160
+ // T10307 / Saga T10281 / Epic T10282 — DB-substrate walker
45161
+ "db-substrate": doctorDbSubstrateCommand,
45162
+ // T10309 / Saga T10281 / Epic T10282 — Legacy-backup walker
45163
+ "legacy-backups": doctorLegacyBackupsCommand
45164
+ },
44065
45165
  args: {
44066
45166
  detailed: {
44067
45167
  type: "boolean",
@@ -44220,14 +45320,15 @@ var init_doctor = __esm({
44220
45320
  description: "Suppress non-essential output"
44221
45321
  }
44222
45322
  },
44223
- async run({ args }) {
45323
+ async run({ args, cmd, rawArgs }) {
45324
+ if (isSubCommandDispatch(rawArgs, cmd.subCommands)) return;
44224
45325
  const isHuman = args.human === true || !!process.stdout.isTTY && args.json !== true;
44225
45326
  const progress = createDoctorProgress(isHuman);
44226
45327
  progress.start();
44227
45328
  try {
44228
45329
  if (args.brain) {
44229
45330
  const { computeBrainHealthDashboard } = await import("@cleocode/core/memory/brain-health-dashboard.js");
44230
- const projectRoot = getProjectRoot33();
45331
+ const projectRoot = getProjectRoot37();
44231
45332
  const dashboard = await computeBrainHealthDashboard(projectRoot);
44232
45333
  cliOutput(dashboard, { command: "doctor", operation: "doctor.brain" });
44233
45334
  if (dashboard.hasP0Failure) {
@@ -44236,7 +45337,7 @@ var init_doctor = __esm({
44236
45337
  return;
44237
45338
  }
44238
45339
  if (args["scan-test-fixtures-in-prod"]) {
44239
- const projectRoot = getProjectRoot33();
45340
+ const projectRoot = getProjectRoot37();
44240
45341
  const matches = await scanTestFixturesInProd(projectRoot);
44241
45342
  const dryRun = args["dry-run"] !== false && args.quarantine !== true;
44242
45343
  const quarantined = !dryRun && matches.length > 0 ? await quarantineTestFixtures(projectRoot, matches) : void 0;
@@ -44324,7 +45425,7 @@ var init_doctor = __esm({
44324
45425
  progress.complete("Comprehensive diagnostics complete");
44325
45426
  } else if (args["scan-rogue-cleo-dirs"]) {
44326
45427
  progress.step(0, "Scanning for rogue .cleo/ directories");
44327
- const projectRoot = getProjectRoot33();
45428
+ const projectRoot = getProjectRoot37();
44328
45429
  const reports = scanRogueCleoDirs(projectRoot);
44329
45430
  progress.complete(
44330
45431
  `Found ${reports.length} rogue .cleo/ director${reports.length === 1 ? "y" : "ies"}`
@@ -44333,7 +45434,7 @@ var init_doctor = __esm({
44333
45434
  } else if (args["quarantine-rogue-cleo-dirs"]) {
44334
45435
  const isDryRun = args["dry-run"] === true;
44335
45436
  progress.step(0, `${isDryRun ? "[DRY RUN] " : ""}Scanning for rogue .cleo/ directories`);
44336
- const projectRoot = getProjectRoot33();
45437
+ const projectRoot = getProjectRoot37();
44337
45438
  const reports = scanRogueCleoDirs(projectRoot);
44338
45439
  if (reports.length === 0) {
44339
45440
  progress.complete("No rogue .cleo/ directories found \u2014 nothing to quarantine");
@@ -44387,7 +45488,7 @@ var init_doctor = __esm({
44387
45488
  const { detectAndRemoveLegacyGlobalFiles, detectAndRemoveStrayProjectNexus } = await import("@cleocode/core/store/cleanup-legacy.js");
44388
45489
  const { getCleoHome: getCleoHome6 } = await import("@cleocode/core");
44389
45490
  const cleoHome = getCleoHome6();
44390
- const projectRoot = getProjectRoot33();
45491
+ const projectRoot = getProjectRoot37();
44391
45492
  const legacyResult = detectAndRemoveLegacyGlobalFiles(cleoHome);
44392
45493
  const strayResult = detectAndRemoveStrayProjectNexus(projectRoot);
44393
45494
  const isDryRun = args["dry-run"] === true;
@@ -44420,7 +45521,7 @@ var init_doctor = __esm({
44420
45521
  } else if (args["audit-worktree-orphans"]) {
44421
45522
  progress.step(0, "Comprehensive worktree anomaly audit (T9808 / council D009)");
44422
45523
  const { auditWorktreeOrphansComprehensive, scanWorktreeOrphansBudgeted } = await import("@cleocode/core/doctor/worktree-orphans.js");
44423
- const projectRoot = getProjectRoot33();
45524
+ const projectRoot = getProjectRoot37();
44424
45525
  const timeoutSecs = args["timeout"] !== void 0 ? Number.parseInt(String(args["timeout"]), 10) : 30;
44425
45526
  const timeoutMs = Number.isFinite(timeoutSecs) && timeoutSecs > 0 ? timeoutSecs * 1e3 : 3e4;
44426
45527
  const maxEntriesPerLevel = args["max-entries-per-level"] !== void 0 ? Number.parseInt(String(args["max-entries-per-level"]), 10) : 500;
@@ -44434,7 +45535,7 @@ var init_doctor = __esm({
44434
45535
  const legacyOrphans = legacyScanResult.orphans;
44435
45536
  const totalAnomalies = comprehensive.count;
44436
45537
  if (legacyScanResult.softWarnMessage) {
44437
- pushWarning2({
45538
+ pushWarning3({
44438
45539
  code: "W_DOCTOR_SCAN_SOFT_WARN",
44439
45540
  message: legacyScanResult.softWarnMessage,
44440
45541
  severity: "warn"
@@ -44442,7 +45543,7 @@ var init_doctor = __esm({
44442
45543
  }
44443
45544
  if (legacyScanResult.isPartial) {
44444
45545
  const reason = legacyScanResult.partialReason === "timeout" ? `timed out after ${timeoutSecs}s (use --timeout <seconds> to adjust)` : `per-level entry cap of ${maxEntriesPerLevel} exceeded (use --max-entries-per-level <n> to adjust)`;
44445
- pushWarning2({
45546
+ pushWarning3({
44446
45547
  code: "W_DOCTOR_SCAN_PARTIAL",
44447
45548
  message: `legacy orphan scan is PARTIAL \u2014 ${reason}. Results may be incomplete.`,
44448
45549
  severity: "warn",
@@ -44477,7 +45578,7 @@ var init_doctor = __esm({
44477
45578
  `${isDryRun ? "[DRY RUN] " : ""}Scanning + pruning worktree-orphan .cleo/ directories`
44478
45579
  );
44479
45580
  const { pruneWorktreeOrphans, scanWorktreeOrphansBudgeted } = await import("@cleocode/core/doctor/worktree-orphans.js");
44480
- const projectRoot = getProjectRoot33();
45581
+ const projectRoot = getProjectRoot37();
44481
45582
  const timeoutSecs = args["timeout"] !== void 0 ? Number.parseInt(String(args["timeout"]), 10) : 30;
44482
45583
  const timeoutMs = Number.isFinite(timeoutSecs) && timeoutSecs > 0 ? timeoutSecs * 1e3 : 3e4;
44483
45584
  const maxEntriesPerLevel = args["max-entries-per-level"] !== void 0 ? Number.parseInt(String(args["max-entries-per-level"]), 10) : 500;
@@ -44486,7 +45587,7 @@ var init_doctor = __esm({
44486
45587
  maxEntriesPerLevel: Number.isFinite(maxEntriesPerLevel) ? maxEntriesPerLevel : 500
44487
45588
  });
44488
45589
  if (scanResult.softWarnMessage) {
44489
- pushWarning2({
45590
+ pushWarning3({
44490
45591
  code: "W_DOCTOR_SCAN_SOFT_WARN",
44491
45592
  message: scanResult.softWarnMessage,
44492
45593
  severity: "warn"
@@ -44494,7 +45595,7 @@ var init_doctor = __esm({
44494
45595
  }
44495
45596
  if (scanResult.isPartial) {
44496
45597
  const reason = scanResult.partialReason === "timeout" ? `timed out after ${timeoutSecs}s (use --timeout <seconds> to adjust)` : `per-level entry cap of ${maxEntriesPerLevel} exceeded (use --max-entries-per-level <n> to adjust)`;
44497
- pushWarning2({
45598
+ pushWarning3({
44498
45599
  code: "W_DOCTOR_SCAN_PARTIAL",
44499
45600
  message: `orphan scan is PARTIAL \u2014 ${reason}. Only orphans found before abort will be pruned.`,
44500
45601
  severity: "warn",
@@ -44556,7 +45657,7 @@ var init_doctor = __esm({
44556
45657
  `${isDryRun ? "[DRY RUN] " : ""}Migrating .cleo/worktree-include \u2192 .worktreeinclude`
44557
45658
  );
44558
45659
  const { migrateWorktreeIncludeFile } = await import("@cleocode/core");
44559
- const projectRoot = getProjectRoot33();
45660
+ const projectRoot = getProjectRoot37();
44560
45661
  const result = await migrateWorktreeIncludeFile(projectRoot, { dryRun: isDryRun });
44561
45662
  progress.complete(`Migration ${result.action}`);
44562
45663
  cliOutput(result, { command: "doctor", operation: "doctor.migrate-worktree-include" });
@@ -44572,7 +45673,7 @@ var init_doctor = __esm({
44572
45673
  } else if (args["audit-sagas"]) {
44573
45674
  progress.step(0, "Auditing Saga hierarchy for ADR-073 invariants");
44574
45675
  const { auditSagaHierarchy } = await import("@cleocode/core/doctor/saga-audit.js");
44575
- const projectRoot = getProjectRoot33();
45676
+ const projectRoot = getProjectRoot37();
44576
45677
  const result = await auditSagaHierarchy(projectRoot);
44577
45678
  const summary = `Saga audit complete \u2014 ${result.sagas.length} saga(s) inspected, ${result.count} invariant violation(s), ${result.driftCount} drift warning(s)`;
44578
45679
  progress.complete(summary);
@@ -44590,7 +45691,7 @@ var init_doctor = __esm({
44590
45691
  { command: "doctor", operation: "admin.health" }
44591
45692
  );
44592
45693
  try {
44593
- const projectRoot = getProjectRoot33();
45694
+ const projectRoot = getProjectRoot37();
44594
45695
  const conflicts = readMigrationConflicts(projectRoot);
44595
45696
  if (conflicts.length > 0) {
44596
45697
  progress.complete(
@@ -44621,7 +45722,7 @@ var init_doctor = __esm({
44621
45722
  progress.complete("Health check complete");
44622
45723
  }
44623
45724
  try {
44624
- const projectRoot = getProjectRoot33();
45725
+ const projectRoot = getProjectRoot37();
44625
45726
  const { auditSagaHierarchy } = await import("@cleocode/core/doctor/saga-audit.js");
44626
45727
  const sagaAudit = await auditSagaHierarchy(projectRoot);
44627
45728
  if (sagaAudit.sagas.length === 0) {
@@ -47768,7 +48869,7 @@ var llm_cost_exports = {};
47768
48869
  __export(llm_cost_exports, {
47769
48870
  costCommand: () => costCommand
47770
48871
  });
47771
- import { getProjectRoot as getProjectRoot34 } from "@cleocode/core/internal";
48872
+ import { getProjectRoot as getProjectRoot38 } from "@cleocode/core/internal";
47772
48873
  import { computeCost } from "@cleocode/core/llm/usage-pricing";
47773
48874
  function resolveSessionId(raw) {
47774
48875
  if (raw === "current") {
@@ -47841,7 +48942,7 @@ var init_llm_cost = __esm({
47841
48942
  process.exit(6);
47842
48943
  }
47843
48944
  const sessionId = resolveSessionId(rawSessionId);
47844
- const projectRoot = getProjectRoot34(process.cwd());
48945
+ const projectRoot = getProjectRoot38(process.cwd());
47845
48946
  let breakdown;
47846
48947
  try {
47847
48948
  breakdown = await loadSessionCostBreakdown(projectRoot, sessionId);
@@ -48482,7 +49583,7 @@ var llm_exports = {};
48482
49583
  __export(llm_exports, {
48483
49584
  llmCommand: () => llmCommand
48484
49585
  });
48485
- import { pushWarning as pushWarning3 } from "@cleocode/core";
49586
+ import { pushWarning as pushWarning4 } from "@cleocode/core";
48486
49587
  async function getListProviders() {
48487
49588
  const { listProviders } = await import(
48488
49589
  /* webpackIgnore: true */
@@ -48613,7 +49714,7 @@ var init_llm3 = __esm({
48613
49714
  apiKey = envValue;
48614
49715
  source = "env";
48615
49716
  } else if (typeof a["api-key"] === "string" && a["api-key"]) {
48616
- pushWarning3({
49717
+ pushWarning4({
48617
49718
  code: "W_DEPRECATED_FLAG",
48618
49719
  message: API_KEY_FLAG_DEPRECATION,
48619
49720
  deprecated: "--api-key=<value>",
@@ -49388,7 +50489,7 @@ var memory_exports = {};
49388
50489
  __export(memory_exports, {
49389
50490
  memoryCommand: () => memoryCommand
49390
50491
  });
49391
- import { getProjectRoot as getProjectRoot35 } from "@cleocode/core";
50492
+ import { getProjectRoot as getProjectRoot39 } from "@cleocode/core";
49392
50493
  import {
49393
50494
  getBrainDb as getBrainDb2,
49394
50495
  getDreamStatus,
@@ -50312,7 +51413,7 @@ var init_memory3 = __esm({
50312
51413
  },
50313
51414
  args: {},
50314
51415
  async run() {
50315
- const root = getProjectRoot35();
51416
+ const root = getProjectRoot39();
50316
51417
  try {
50317
51418
  const result = await runConsolidation(root);
50318
51419
  cliOutput(result, { command: "memory-consolidate", operation: "memory.consolidate" });
@@ -50336,7 +51437,7 @@ var init_memory3 = __esm({
50336
51437
  }
50337
51438
  },
50338
51439
  async run({ args }) {
50339
- const root = getProjectRoot35();
51440
+ const root = getProjectRoot39();
50340
51441
  if (args.status) {
50341
51442
  try {
50342
51443
  const status = await getDreamStatus(root);
@@ -50373,7 +51474,7 @@ var init_memory3 = __esm({
50373
51474
  }
50374
51475
  },
50375
51476
  async run({ args }) {
50376
- const root = getProjectRoot35();
51477
+ const root = getProjectRoot39();
50377
51478
  try {
50378
51479
  const { runObserver, runReflector } = await import("@cleocode/core/memory");
50379
51480
  const observerResult = await runObserver(root, args.session, {
@@ -50413,7 +51514,7 @@ var init_memory3 = __esm({
50413
51514
  }
50414
51515
  },
50415
51516
  async run({ args }) {
50416
- const root = getProjectRoot35();
51517
+ const root = getProjectRoot39();
50417
51518
  try {
50418
51519
  await getBrainDb2(root);
50419
51520
  const { totalDuplicateRows, groups } = await scanDuplicateEntries();
@@ -50459,7 +51560,7 @@ var init_memory3 = __esm({
50459
51560
  async run({ args }) {
50460
51561
  const sourceDir = args.from;
50461
51562
  const isDryRun = !!args["dry-run"];
50462
- const projectRoot = getProjectRoot35();
51563
+ const projectRoot = getProjectRoot39();
50463
51564
  try {
50464
51565
  const result = await importMemoryFiles({
50465
51566
  sourceDir,
@@ -50610,7 +51711,7 @@ var init_memory3 = __esm({
50610
51711
  },
50611
51712
  args: {},
50612
51713
  async run() {
50613
- const root = getProjectRoot35();
51714
+ const root = getProjectRoot39();
50614
51715
  try {
50615
51716
  await getBrainDb2(root);
50616
51717
  const result = await getTierStats(root);
@@ -50653,7 +51754,7 @@ var init_memory3 = __esm({
50653
51754
  }
50654
51755
  },
50655
51756
  async run({ args }) {
50656
- const root = getProjectRoot35();
51757
+ const root = getProjectRoot39();
50657
51758
  const targetTier = args.to;
50658
51759
  const reason = args.reason;
50659
51760
  const validTiers = ["medium", "long"];
@@ -50719,7 +51820,7 @@ var init_memory3 = __esm({
50719
51820
  }
50720
51821
  },
50721
51822
  async run({ args }) {
50722
- const root = getProjectRoot35();
51823
+ const root = getProjectRoot39();
50723
51824
  const targetTier = args.to;
50724
51825
  const reason = args.reason;
50725
51826
  const validTiers = ["short", "medium"];
@@ -51179,7 +52280,7 @@ var migrate_claude_mem_exports = {};
51179
52280
  __export(migrate_claude_mem_exports, {
51180
52281
  migrateClaudeMemCommand: () => migrateClaudeMemCommand
51181
52282
  });
51182
- import { getProjectRoot as getProjectRoot36, migrateClaudeMem } from "@cleocode/core/internal";
52283
+ import { getProjectRoot as getProjectRoot40, migrateClaudeMem } from "@cleocode/core/internal";
51183
52284
  import { ingestLooseAgentOutputs, ingestRcasdDirectories } from "@cleocode/core/memory";
51184
52285
  import { getDb as getDb2 } from "@cleocode/core/store/sqlite";
51185
52286
  var storageCommand, claudeMemCommand, manifestIngestCommand, migrateClaudeMemCommand;
@@ -51242,7 +52343,7 @@ var init_migrate_claude_mem = __esm({
51242
52343
  }
51243
52344
  },
51244
52345
  async run({ args }) {
51245
- const root = getProjectRoot36();
52346
+ const root = getProjectRoot40();
51246
52347
  try {
51247
52348
  const result = await migrateClaudeMem(root, {
51248
52349
  sourcePath: args.source,
@@ -51291,7 +52392,7 @@ var init_migrate_claude_mem = __esm({
51291
52392
  }
51292
52393
  },
51293
52394
  async run({ args }) {
51294
- const projectRoot = getProjectRoot36();
52395
+ const projectRoot = getProjectRoot40();
51295
52396
  try {
51296
52397
  const db = await getDb2(projectRoot);
51297
52398
  const rcasdFlag = Boolean(args.rcasd);
@@ -51395,7 +52496,7 @@ __export(nexus_exports, {
51395
52496
  import { appendFile as appendFile2, mkdir as mkdir3 } from "node:fs/promises";
51396
52497
  import { homedir as homedir5 } from "node:os";
51397
52498
  import path4 from "node:path";
51398
- import { getProjectRoot as getProjectRoot37 } from "@cleocode/core";
52499
+ import { getProjectRoot as getProjectRoot41 } from "@cleocode/core";
51399
52500
  import { getSymbolImpact } from "@cleocode/core/nexus";
51400
52501
  import { runNexusAnalysis } from "@cleocode/core/nexus/analyze-orchestrator.js";
51401
52502
  import { exportNexusGraph } from "@cleocode/core/nexus/export.js";
@@ -51510,7 +52611,7 @@ var init_nexus3 = __esm({
51510
52611
  async run({ args }) {
51511
52612
  applyJsonFlag2(args.json);
51512
52613
  const projectIdOverride = args["project-id"];
51513
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
52614
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
51514
52615
  const startTime = Date.now();
51515
52616
  try {
51516
52617
  const [{ getNexusDb, nexusSchema }, { getIndexStats }] = await Promise.all([
@@ -52025,7 +53126,7 @@ var init_nexus3 = __esm({
52025
53126
  applyJsonFlag2(args.json);
52026
53127
  const startTime = Date.now();
52027
53128
  const projectIdOverride = args["project-id"];
52028
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
53129
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52029
53130
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52030
53131
  const response = await dispatchRaw("query", "nexus", "clusters", { projectId, repoPath });
52031
53132
  const durationMs = Date.now() - startTime;
@@ -52069,7 +53170,7 @@ var init_nexus3 = __esm({
52069
53170
  applyJsonFlag2(args.json);
52070
53171
  const startTime = Date.now();
52071
53172
  const projectIdOverride = args["project-id"];
52072
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
53173
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52073
53174
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52074
53175
  const response = await dispatchRaw("query", "nexus", "flows", { projectId, repoPath });
52075
53176
  const durationMs = Date.now() - startTime;
@@ -52112,7 +53213,7 @@ var init_nexus3 = __esm({
52112
53213
  void appendDeprecationTelemetry("nexus.context", "cleo graph context");
52113
53214
  const startTime = Date.now();
52114
53215
  const projectIdOverride = args["project-id"];
52115
- const repoPath = getProjectRoot37();
53216
+ const repoPath = getProjectRoot41();
52116
53217
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52117
53218
  const limit = parseInt(args.limit, 10);
52118
53219
  const symbolName = args.symbol;
@@ -52175,7 +53276,7 @@ var init_nexus3 = __esm({
52175
53276
  const startTime = Date.now();
52176
53277
  const whyFlag = !!args.why;
52177
53278
  const projectIdOverride = args["project-id"];
52178
- const repoPath = getProjectRoot37();
53279
+ const repoPath = getProjectRoot41();
52179
53280
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52180
53281
  const maxDepth = Math.min(parseInt(args.depth, 10), 5);
52181
53282
  const symbolName = args.symbol;
@@ -52247,7 +53348,7 @@ var init_nexus3 = __esm({
52247
53348
  const projectIdOverride = args["project-id"];
52248
53349
  const isIncremental = !!args.incremental;
52249
53350
  const ctx = getFormatContext();
52250
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
53351
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52251
53352
  humanInfo(`[nexus] Analyzing: ${repoPath}${isIncremental ? " (incremental)" : ""}`);
52252
53353
  if (!isIncremental) humanInfo("[nexus] Clearing existing index for project...");
52253
53354
  try {
@@ -52350,7 +53451,7 @@ var init_nexus3 = __esm({
52350
53451
  async run({ args }) {
52351
53452
  applyJsonFlag2(args.json);
52352
53453
  const startTime = Date.now();
52353
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
53454
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52354
53455
  const name = args.name;
52355
53456
  const response = await dispatchRaw("mutate", "nexus", "projects.register", {
52356
53457
  path: repoPath,
@@ -52708,7 +53809,7 @@ var init_nexus3 = __esm({
52708
53809
  applyJsonFlag2(args.json);
52709
53810
  const startTime = Date.now();
52710
53811
  const projectIdOverride = args["project-id"];
52711
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
53812
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52712
53813
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52713
53814
  const response = await dispatchRaw("mutate", "nexus", "refresh-bridge", {
52714
53815
  repoPath,
@@ -52814,7 +53915,7 @@ var init_nexus3 = __esm({
52814
53915
  async run({ args }) {
52815
53916
  applyJsonFlag2(args.json);
52816
53917
  const startTime = Date.now();
52817
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
53918
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52818
53919
  const projectIdOverride = args["project-id"];
52819
53920
  const beforeRef = args.before ?? "HEAD~1";
52820
53921
  const afterRef = args.after ?? "HEAD";
@@ -52932,7 +54033,7 @@ var init_nexus3 = __esm({
52932
54033
  applyJsonFlag2(args.json);
52933
54034
  const startTime = Date.now();
52934
54035
  const projectIdOverride = args["project-id"];
52935
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
54036
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52936
54037
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52937
54038
  const response = await dispatchRaw("query", "nexus", "route-map", { projectId });
52938
54039
  const durationMs = Date.now() - startTime;
@@ -52988,7 +54089,7 @@ var init_nexus3 = __esm({
52988
54089
  const startTime = Date.now();
52989
54090
  const routeSymbol = args.routeSymbol;
52990
54091
  const projectIdOverride = args["project-id"];
52991
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
54092
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
52992
54093
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
52993
54094
  const response = await dispatchRaw("query", "nexus", "shape-check", { routeSymbol, projectId });
52994
54095
  const durationMs = Date.now() - startTime;
@@ -53378,7 +54479,7 @@ var init_nexus3 = __esm({
53378
54479
  async run({ args }) {
53379
54480
  applyJsonFlag2(args.json);
53380
54481
  const startTime = Date.now();
53381
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
54482
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
53382
54483
  const projectIdOverride = args["project-id"];
53383
54484
  const projectId = projectIdOverride ?? Buffer.from(repoPath).toString("base64url").slice(0, 32);
53384
54485
  const response = await dispatchRaw("mutate", "nexus", "contracts-sync", {
@@ -53482,7 +54583,7 @@ var init_nexus3 = __esm({
53482
54583
  async run({ args }) {
53483
54584
  applyJsonFlag2(args.json);
53484
54585
  const startTime = Date.now();
53485
- const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot37();
54586
+ const repoPath = args.path ? path4.resolve(args.path) : getProjectRoot41();
53486
54587
  const projectId = Buffer.from(repoPath).toString("base64url").slice(0, 32);
53487
54588
  const response = await dispatchRaw("mutate", "nexus", "contracts-link-tasks", {
53488
54589
  projectId,
@@ -53563,7 +54664,7 @@ var init_nexus3 = __esm({
53563
54664
  const isIncremental = !!args.incremental;
53564
54665
  try {
53565
54666
  const result = await runNexusWiki({
53566
- projectRoot: getProjectRoot37(),
54667
+ projectRoot: getProjectRoot41(),
53567
54668
  outputDir,
53568
54669
  communityFilter,
53569
54670
  incremental: isIncremental
@@ -55990,7 +57091,7 @@ var refresh_memory_exports = {};
55990
57091
  __export(refresh_memory_exports, {
55991
57092
  refreshMemoryCommand: () => refreshMemoryCommand
55992
57093
  });
55993
- import { getProjectRoot as getProjectRoot38 } from "@cleocode/core";
57094
+ import { getProjectRoot as getProjectRoot42 } from "@cleocode/core";
55994
57095
  var refreshMemoryCommand;
55995
57096
  var init_refresh_memory = __esm({
55996
57097
  "packages/cleo/src/cli/commands/refresh-memory.ts"() {
@@ -56003,7 +57104,7 @@ var init_refresh_memory = __esm({
56003
57104
  description: "Regenerate .cleo/memory-bridge.md from brain.db"
56004
57105
  },
56005
57106
  async run() {
56006
- const projectDir = getProjectRoot38();
57107
+ const projectDir = getProjectRoot42();
56007
57108
  const { writeMemoryBridge } = await import("@cleocode/core/internal");
56008
57109
  const result = await writeMemoryBridge(projectDir);
56009
57110
  if (result.written) {
@@ -56179,14 +57280,6 @@ var init_relates = __esm({
56179
57280
  }
56180
57281
  });
56181
57282
 
56182
- // packages/cleo/src/cli/lib/define-cli-command.ts
56183
- var init_define_cli_command = __esm({
56184
- "packages/cleo/src/cli/lib/define-cli-command.ts"() {
56185
- "use strict";
56186
- init_dist();
56187
- }
56188
- });
56189
-
56190
57283
  // packages/cleo/src/cli/commands/release/ship-e2e-smoke.ts
56191
57284
  import { release as release2 } from "@cleocode/core";
56192
57285
  var shipE2eSmokeCommand;
@@ -57412,7 +58505,7 @@ import fs3 from "node:fs";
57412
58505
  import path5 from "node:path";
57413
58506
  import {
57414
58507
  CleoError as CleoError7,
57415
- getProjectRoot as getProjectRoot39,
58508
+ getProjectRoot as getProjectRoot43,
57416
58509
  getTaskAccessor as getTaskAccessor3,
57417
58510
  parseConflictReport,
57418
58511
  setAtPath
@@ -57433,7 +58526,7 @@ var init_restore = __esm({
57433
58526
  description: "Apply manually-resolved conflicts from .cleo/restore-conflicts.md"
57434
58527
  },
57435
58528
  async run() {
57436
- const projectRoot = getProjectRoot39();
58529
+ const projectRoot = getProjectRoot43();
57437
58530
  const reportPath = path5.join(projectRoot, CLEO_DIR_NAME, RESTORE_CONFLICTS_MD);
57438
58531
  if (!fs3.existsSync(reportPath)) {
57439
58532
  humanLine("No pending restore conflicts. Nothing to finalize.");
@@ -59924,7 +61017,7 @@ var sequence_exports = {};
59924
61017
  __export(sequence_exports, {
59925
61018
  sequenceCommand: () => sequenceCommand
59926
61019
  });
59927
- import { getProjectRoot as getProjectRoot40 } from "@cleocode/core/internal";
61020
+ import { getProjectRoot as getProjectRoot44 } from "@cleocode/core/internal";
59928
61021
  var showCommand12, checkCommand6, repairCommand2, sequenceCommand;
59929
61022
  var init_sequence = __esm({
59930
61023
  "packages/cleo/src/cli/commands/sequence.ts"() {
@@ -59960,7 +61053,7 @@ var init_sequence = __esm({
59960
61053
  meta: { name: "repair", description: "Reset counter to max + 1 if behind" },
59961
61054
  async run() {
59962
61055
  const { repairSequence } = await import("@cleocode/core/internal");
59963
- const projectRoot = getProjectRoot40();
61056
+ const projectRoot = getProjectRoot44();
59964
61057
  const repair = await repairSequence(projectRoot);
59965
61058
  const result = {
59966
61059
  repaired: repair.repaired,
@@ -60415,8 +61508,8 @@ var init_session4 = __esm({
60415
61508
  "audit-scope": { type: "string", description: "Audit log scope (global|local)" }
60416
61509
  },
60417
61510
  async run({ args }) {
60418
- const { detectSessionDrift, getProjectRoot: getProjectRoot44 } = await import("@cleocode/core");
60419
- const projectRoot = await getProjectRoot44();
61511
+ const { detectSessionDrift, getProjectRoot: getProjectRoot48 } = await import("@cleocode/core");
61512
+ const projectRoot = await getProjectRoot48();
60420
61513
  const scope = args["audit-scope"] === "local" ? "local" : "global";
60421
61514
  const report = await detectSessionDrift({ projectRoot, auditScope: scope });
60422
61515
  cliOutput(report, { command: "session drift", operation: "session.drift" });
@@ -63182,7 +64275,7 @@ __export(token_exports, {
63182
64275
  tokenCommand: () => tokenCommand
63183
64276
  });
63184
64277
  import { readFileSync as readFileSync16 } from "node:fs";
63185
- import { getProjectRoot as getProjectRoot41, measureTokenExchange, recordTokenExchange as recordTokenExchange2 } from "@cleocode/core/internal";
64278
+ import { getProjectRoot as getProjectRoot45, measureTokenExchange, recordTokenExchange as recordTokenExchange2 } from "@cleocode/core/internal";
63186
64279
  function readPayload(args, textKey, fileKey) {
63187
64280
  const text = args[textKey];
63188
64281
  const file = args[fileKey];
@@ -63346,7 +64439,7 @@ var init_token = __esm({
63346
64439
  domain: args.domain,
63347
64440
  operation: args.operation
63348
64441
  };
63349
- const result = args.record ? await recordTokenExchange2(getProjectRoot41(), input2) : await measureTokenExchange(input2);
64442
+ const result = args.record ? await recordTokenExchange2(getProjectRoot45(), input2) : await measureTokenExchange(input2);
63350
64443
  cliOutput(result, {
63351
64444
  command: "token",
63352
64445
  operation: args.record ? "admin.token.record" : "token.estimate"
@@ -63382,7 +64475,7 @@ __export(transcript_exports, {
63382
64475
  });
63383
64476
  import { homedir as homedir6 } from "node:os";
63384
64477
  import { join as join30 } from "node:path";
63385
- import { getProjectRoot as getProjectRoot42 } from "@cleocode/core";
64478
+ import { getProjectRoot as getProjectRoot46 } from "@cleocode/core";
63386
64479
  import {
63387
64480
  parseDurationMs,
63388
64481
  pruneTranscripts,
@@ -63412,7 +64505,7 @@ var init_transcript = __esm({
63412
64505
  async run({ args }) {
63413
64506
  if (args.pending) {
63414
64507
  try {
63415
- const projectRoot = getProjectRoot42();
64508
+ const projectRoot = getProjectRoot46();
63416
64509
  const { scanPendingTranscripts } = await import("@cleocode/core/memory/transcript-scanner.js");
63417
64510
  const pending = await scanPendingTranscripts(projectRoot);
63418
64511
  cliOutput(
@@ -63509,7 +64602,7 @@ var init_transcript = __esm({
63509
64602
  async run({ args }) {
63510
64603
  const tier = args.tier ?? "warm";
63511
64604
  const dryRun = args["dry-run"] ?? false;
63512
- const projectRoot = getProjectRoot42();
64605
+ const projectRoot = getProjectRoot46();
63513
64606
  try {
63514
64607
  const { extractTranscript } = await import("@cleocode/core/memory/transcript-extractor.js");
63515
64608
  const { findSessionTranscriptPath, listAllTranscripts } = await import("@cleocode/core/memory/transcript-scanner.js");
@@ -63621,7 +64714,7 @@ var init_transcript = __esm({
63621
64714
  const dryRun = args["dry-run"] ?? false;
63622
64715
  const olderThanHours = args["older-than-hours"] ? Number.parseInt(args["older-than-hours"], 10) : 24;
63623
64716
  const limit = args.limit ? Number.parseInt(args.limit, 10) : void 0;
63624
- const projectRoot = getProjectRoot42();
64717
+ const projectRoot = getProjectRoot46();
63625
64718
  try {
63626
64719
  const { extractTranscript } = await import("@cleocode/core/memory/transcript-extractor.js");
63627
64720
  const { listAllTranscripts } = await import("@cleocode/core/memory/transcript-scanner.js");
@@ -64748,7 +65841,7 @@ __export(worktree_exports, {
64748
65841
  worktreeCommand: () => worktreeCommand
64749
65842
  });
64750
65843
  import readline4 from "node:readline";
64751
- import { getProjectRoot as getProjectRoot43, listWorktrees as listWorktrees2 } from "@cleocode/core/internal";
65844
+ import { getProjectRoot as getProjectRoot47, listWorktrees as listWorktrees2 } from "@cleocode/core/internal";
64752
65845
  async function promptYesNo2(question) {
64753
65846
  return new Promise((resolve7) => {
64754
65847
  const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
@@ -64853,7 +65946,7 @@ var init_worktree3 = __esm({
64853
65946
  const staleDays = staleDaysRaw !== void 0 ? Number.parseInt(staleDaysRaw, 10) : void 0;
64854
65947
  const idleDaysRaw = typeof args["idle-days"] === "string" ? args["idle-days"] : void 0;
64855
65948
  const idleDays = idleDaysRaw !== void 0 ? Number.parseInt(idleDaysRaw, 10) : void 0;
64856
- const projectRoot = getProjectRoot43();
65949
+ const projectRoot = getProjectRoot47();
64857
65950
  const listResult = await listWorktrees2({
64858
65951
  projectRoot,
64859
65952
  ...staleDays !== void 0 && !Number.isNaN(staleDays) ? { staleDays } : {}
@@ -65178,6 +66271,12 @@ var COMMAND_MANIFEST = [
65178
66271
  description: "Show bundle manifest without extracting or modifying anything",
65179
66272
  load: async () => (await Promise.resolve().then(() => (init_backup_inspect(), backup_inspect_exports))).backupInspectSubCommand
65180
66273
  },
66274
+ {
66275
+ exportName: "backupRecoverSubCommand",
66276
+ name: "recover",
66277
+ description: "Recover a malformed CLEO database from snapshot \u2014 accepts any role from DB_INVENTORY (T10318)",
66278
+ load: async () => (await Promise.resolve().then(() => (init_backup_recover(), backup_recover_exports))).backupRecoverSubCommand
66279
+ },
65181
66280
  {
65182
66281
  exportName: "backupCommand",
65183
66282
  name: "backup",
@@ -65382,6 +66481,18 @@ var COMMAND_MANIFEST = [
65382
66481
  description: "Documentation attachment management (add/list/fetch/remove), ",
65383
66482
  load: async () => (await Promise.resolve().then(() => (init_docs3(), docs_exports))).docsCommand
65384
66483
  },
66484
+ {
66485
+ exportName: "doctorDbSubstrateCommand",
66486
+ name: "db-substrate",
66487
+ description: "Walk every DB in the inventory + report integrity, row counts, orphan dirs. ",
66488
+ load: async () => (await Promise.resolve().then(() => (init_doctor_db_substrate(), doctor_db_substrate_exports))).doctorDbSubstrateCommand
66489
+ },
66490
+ {
66491
+ exportName: "doctorLegacyBackupsCommand",
66492
+ name: "legacy-backups",
66493
+ description: "Enumerate legacy *-pre-cleo.db.bak / brain.db.PRE-DUP-FIX-* / pre-untrack / rotation-overflow ",
66494
+ load: async () => (await Promise.resolve().then(() => (init_doctor_legacy_backups(), doctor_legacy_backups_exports))).doctorLegacyBackupsCommand
66495
+ },
65385
66496
  {
65386
66497
  exportName: "doctorProjectsCommand",
65387
66498
  name: "doctor-projects",
@@ -66075,41 +67186,8 @@ function lazyCommand(meta, loader2) {
66075
67186
  };
66076
67187
  }
66077
67188
 
66078
- // packages/cleo/src/cli/lib/did-you-mean.ts
66079
- function levenshteinDistance(input2, candidate) {
66080
- const inputLen = input2.length;
66081
- const candidateLen = candidate.length;
66082
- const matrix = Array.from({ length: inputLen + 1 }, (_, i) => [i]);
66083
- for (let j = 1; j <= candidateLen; j++) {
66084
- matrix[0][j] = j;
66085
- }
66086
- for (let i = 1; i <= inputLen; i++) {
66087
- for (let j = 1; j <= candidateLen; j++) {
66088
- const cost = input2[i - 1] === candidate[j - 1] ? 0 : 1;
66089
- matrix[i][j] = Math.min(
66090
- matrix[i - 1][j] + 1,
66091
- // deletion
66092
- matrix[i][j - 1] + 1,
66093
- // insertion
66094
- matrix[i - 1][j - 1] + cost
66095
- // substitution
66096
- );
66097
- }
66098
- }
66099
- return matrix[inputLen][candidateLen];
66100
- }
66101
- function didYouMean(input2, candidates, maxDistance = 2) {
66102
- const suggestions = candidates.map((candidate) => ({
66103
- command: candidate,
66104
- distance: levenshteinDistance(input2, candidate)
66105
- })).filter((item) => item.distance <= maxDistance).sort((a, b) => {
66106
- if (a.distance !== b.distance) {
66107
- return a.distance - b.distance;
66108
- }
66109
- return a.command.localeCompare(b.command);
66110
- }).map((item) => item.command);
66111
- return suggestions;
66112
- }
67189
+ // packages/cleo/src/cli/index.ts
67190
+ init_did_you_mean();
66113
67191
 
66114
67192
  // packages/cleo/src/cli/lib/first-run-detection.ts
66115
67193
  import { existsSync as existsSync16 } from "node:fs";
@@ -66385,8 +67463,8 @@ async function runStartupMaintenance() {
66385
67463
  detectAndRemoveLegacyGlobalFiles,
66386
67464
  detectAndRemoveStrayProjectNexus,
66387
67465
  getGlobalSalt,
66388
- getLogger: getLogger20,
66389
- getProjectRoot: getProjectRoot44,
67466
+ getLogger: getLogger21,
67467
+ getProjectRoot: getProjectRoot48,
66390
67468
  isCleanupMarkerSet,
66391
67469
  migrateSignaldockToConduit,
66392
67470
  needsSignaldockToConduitMigration,
@@ -66395,7 +67473,7 @@ async function runStartupMaintenance() {
66395
67473
  } = await import("@cleocode/core/internal");
66396
67474
  let projectRootForCleanup = "";
66397
67475
  try {
66398
- projectRootForCleanup = getProjectRoot44();
67476
+ projectRootForCleanup = getProjectRoot48();
66399
67477
  } catch {
66400
67478
  }
66401
67479
  if (!isCleanupMarkerSet(CLI_VERSION, projectRootForCleanup)) {
@@ -66411,11 +67489,11 @@ async function runStartupMaintenance() {
66411
67489
  }
66412
67490
  setCleanupMarker(CLI_VERSION, projectRootForCleanup);
66413
67491
  }
66414
- const _startupLog = getLogger20("cli-startup");
67492
+ const _startupLog = getLogger21("cli-startup");
66415
67493
  const isInitInvocation = process.argv.slice(2).some((a) => a === "init");
66416
67494
  if (!isInitInvocation) {
66417
67495
  try {
66418
- const _projectRootForMigration = getProjectRoot44();
67496
+ const _projectRootForMigration = getProjectRoot48();
66419
67497
  if (needsSignaldockToConduitMigration(_projectRootForMigration)) {
66420
67498
  const migrationResult = migrateSignaldockToConduit(_projectRootForMigration);
66421
67499
  if (migrationResult.status === "failed") {