@cleocode/core 2026.4.28 → 2026.4.29

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.
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/adrs/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA8ChD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAgI9E"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/adrs/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA8ChD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqL9E"}
@@ -36,6 +36,7 @@ export interface AdrSyncResult {
36
36
  file: string;
37
37
  error: string;
38
38
  }>;
39
+ warnings: string[];
39
40
  }
40
41
  export interface AdrListResult {
41
42
  adrs: Array<{
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adrs/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,CAAC;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5B,aAAa,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAEhD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,cAAc,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC;QACV,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC;QACV,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adrs/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,CAAC;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5B,aAAa,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAEhD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,cAAc,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC;QACV,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC;QACV,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf"}
package/dist/index.js CHANGED
@@ -1546,10 +1546,10 @@ var init_subquery = __esm({
1546
1546
  init_entity();
1547
1547
  Subquery = class {
1548
1548
  static [entityKind] = "Subquery";
1549
- constructor(sql11, fields, alias, isWith = false, usedTables = []) {
1549
+ constructor(sql12, fields, alias, isWith = false, usedTables = []) {
1550
1550
  this._ = {
1551
1551
  brand: "Subquery",
1552
- sql: sql11,
1552
+ sql: sql12,
1553
1553
  selectedFields: fields,
1554
1554
  alias,
1555
1555
  isWith,
@@ -1929,8 +1929,8 @@ var init_sql = __esm({
1929
1929
  isSelectionField = false;
1930
1930
  /** @internal */
1931
1931
  origin;
1932
- constructor(sql11, fieldAlias) {
1933
- this.sql = sql11;
1932
+ constructor(sql12, fieldAlias) {
1933
+ this.sql = sql12;
1934
1934
  this.fieldAlias = fieldAlias;
1935
1935
  }
1936
1936
  getSQL() {
@@ -2634,17 +2634,17 @@ var init_custom = __esm({
2634
2634
  mapFromJsonValue(value) {
2635
2635
  return typeof this.mapJson === "function" ? this.mapJson(value) : this.mapFromDriverValue(value);
2636
2636
  }
2637
- jsonSelectIdentifier(identifier, sql11) {
2638
- if (typeof this.forJsonSelect === "function") return this.forJsonSelect(identifier, sql11);
2637
+ jsonSelectIdentifier(identifier, sql12) {
2638
+ if (typeof this.forJsonSelect === "function") return this.forJsonSelect(identifier, sql12);
2639
2639
  const rawType = this.getSQLType().toLowerCase();
2640
2640
  const parenPos = rawType.indexOf("(");
2641
2641
  switch (parenPos + 1 ? rawType.slice(0, parenPos) : rawType) {
2642
2642
  case "numeric":
2643
2643
  case "decimal":
2644
2644
  case "bigint":
2645
- return sql11`cast(${identifier} as text)`;
2645
+ return sql12`cast(${identifier} as text)`;
2646
2646
  case "blob":
2647
- return sql11`hex(${identifier})`;
2647
+ return sql12`hex(${identifier})`;
2648
2648
  default:
2649
2649
  return identifier;
2650
2650
  }
@@ -3812,8 +3812,8 @@ var init_custom2 = __esm({
3812
3812
  mapFromJsonValue(value) {
3813
3813
  return typeof this.mapJson === "function" ? this.mapJson(value) : this.mapFromDriverValue(value);
3814
3814
  }
3815
- jsonSelectIdentifier(identifier, sql11, arrayDimensions) {
3816
- if (typeof this.forJsonSelect === "function") return this.forJsonSelect(identifier, sql11, arrayDimensions);
3815
+ jsonSelectIdentifier(identifier, sql12, arrayDimensions) {
3816
+ if (typeof this.forJsonSelect === "function") return this.forJsonSelect(identifier, sql12, arrayDimensions);
3817
3817
  const rawType = this.getSQLType().toLowerCase();
3818
3818
  const parenPos = rawType.indexOf("(");
3819
3819
  switch (parenPos + 1 ? rawType.slice(0, parenPos) : rawType) {
@@ -3823,7 +3823,7 @@ var init_custom2 = __esm({
3823
3823
  case "numeric":
3824
3824
  case "bigint": {
3825
3825
  const arrVal = "[]".repeat(arrayDimensions ?? 0);
3826
- return sql11`${identifier}::text${sql11.raw(arrVal).if(arrayDimensions)}`;
3826
+ return sql12`${identifier}::text${sql12.raw(arrVal).if(arrayDimensions)}`;
3827
3827
  }
3828
3828
  default:
3829
3829
  return identifier;
@@ -7704,8 +7704,8 @@ var init_dialect = __esm({
7704
7704
  const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` : void 0;
7705
7705
  return sql`${withSql}insert into ${table} ${insertOrder} ${valuesSql}${onConflict?.length ? sql.join(onConflict) : void 0}${returningSql}`;
7706
7706
  }
7707
- sqlToQuery(sql11, invokeSource) {
7708
- return sql11.toQuery({
7707
+ sqlToQuery(sql12, invokeSource) {
7708
+ return sql12.toQuery({
7709
7709
  casing: this.casing,
7710
7710
  escapeName: this.escapeName,
7711
7711
  escapeParam: this.escapeParam,
@@ -8802,8 +8802,8 @@ var init_db = __esm({
8802
8802
  });
8803
8803
 
8804
8804
  // node_modules/.pnpm/drizzle-orm@1.0.0-beta.19-d95b7a4_@sinclair+typebox@0.34.49_@types+mssql@9.1.9_@azure+c_7d603f9dc53f6bedf2f8e8db5954b691/node_modules/drizzle-orm/cache/core/cache.js
8805
- async function hashQuery(sql11, params) {
8806
- const dataToHash = `${sql11}-${JSON.stringify(params, (_, v) => typeof v === "bigint" ? `${v}n` : v)}`;
8805
+ async function hashQuery(sql12, params) {
8806
+ const dataToHash = `${sql12}-${JSON.stringify(params, (_, v) => typeof v === "bigint" ? `${v}n` : v)}`;
8807
8807
  const data = new TextEncoder().encode(dataToHash);
8808
8808
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
8809
8809
  return [...new Uint8Array(hashBuffer)].map((b) => b.toString(16).padStart(2, "0")).join("");
@@ -8982,8 +8982,8 @@ var init_session3 = __esm({
8982
8982
  values(query) {
8983
8983
  return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), void 0, "run", false).values();
8984
8984
  }
8985
- async count(sql11) {
8986
- return (await this.values(sql11))[0][0];
8985
+ async count(sql12) {
8986
+ return (await this.values(sql12))[0][0];
8987
8987
  }
8988
8988
  /** @internal */
8989
8989
  extractRawValuesValueFromBatchResult(_result) {
@@ -11074,8 +11074,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
11074
11074
  const dbEntries = nativeDb.prepare('SELECT hash FROM "__drizzle_migrations"').all();
11075
11075
  const hasOrphanedEntries = dbEntries.some((e) => !localHashes.has(e.hash));
11076
11076
  if (hasOrphanedEntries) {
11077
- const log9 = getLogger(logSubsystem);
11078
- log9.warn(
11077
+ const log10 = getLogger(logSubsystem);
11078
+ log10.warn(
11079
11079
  { orphaned: dbEntries.filter((e) => !localHashes.has(e.hash)).length },
11080
11080
  `Detected stale migration journal entries from a previous CLEO version. Reconciling.`
11081
11081
  );
@@ -11107,8 +11107,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
11107
11107
  return cols.some((c) => c.name === column);
11108
11108
  });
11109
11109
  if (allColumnsExist) {
11110
- const log9 = getLogger(logSubsystem);
11111
- log9.warn(
11110
+ const log10 = getLogger(logSubsystem);
11111
+ log10.warn(
11112
11112
  { migration: migration.name, columns: alterMatches },
11113
11113
  `Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
11114
11114
  );
@@ -11153,8 +11153,8 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem) {
11153
11153
  const existingCols = new Set(columns.map((c) => c.name));
11154
11154
  for (const req of requiredColumns) {
11155
11155
  if (!existingCols.has(req.name)) {
11156
- const log9 = getLogger(logSubsystem);
11157
- log9.warn(
11156
+ const log10 = getLogger(logSubsystem);
11157
+ log10.warn(
11158
11158
  { column: req.name },
11159
11159
  `Adding missing column ${tableName}.${req.name} via ALTER TABLE`
11160
11160
  );
@@ -11273,12 +11273,12 @@ function detachAgentFromProject(db, agentId) {
11273
11273
  }
11274
11274
  function listProjectAgentRefs(db, opts) {
11275
11275
  const enabledOnly = opts?.enabledOnly ?? true;
11276
- const sql11 = enabledOnly ? `SELECT agent_id, attached_at, role, capabilities_override, last_used_at, enabled
11276
+ const sql12 = enabledOnly ? `SELECT agent_id, attached_at, role, capabilities_override, last_used_at, enabled
11277
11277
  FROM project_agent_refs WHERE enabled = 1
11278
11278
  ORDER BY attached_at DESC` : `SELECT agent_id, attached_at, role, capabilities_override, last_used_at, enabled
11279
11279
  FROM project_agent_refs
11280
11280
  ORDER BY attached_at DESC`;
11281
- const rows = db.prepare(sql11).all();
11281
+ const rows = db.prepare(sql12).all();
11282
11282
  return rows.map((r) => ({
11283
11283
  agentId: r.agent_id,
11284
11284
  attachedAt: r.attached_at,
@@ -12929,7 +12929,7 @@ function getDbPath(cwd) {
12929
12929
  return join9(getCleoDirAbsolute(cwd), DB_FILENAME2);
12930
12930
  }
12931
12931
  async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
12932
- const log9 = getLogger("sqlite");
12932
+ const log10 = getLogger("sqlite");
12933
12933
  try {
12934
12934
  const countResult = nativeDb.prepare("SELECT COUNT(*) as cnt FROM tasks").get();
12935
12935
  const taskCount = countResult?.cnt ?? 0;
@@ -12950,7 +12950,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
12950
12950
  if (backupTaskCount < MIN_BACKUP_TASK_COUNT) {
12951
12951
  return;
12952
12952
  }
12953
- log9.warn(
12953
+ log10.warn(
12954
12954
  { dbPath, backupPath: newestBackup.path, backupTasks: backupTaskCount },
12955
12955
  `Empty database detected with ${backupTaskCount}-task backup available. Auto-recovering from backup. This likely happened because git-tracked WAL/SHM files were overwritten during a branch switch (T5188).`
12956
12956
  );
@@ -12968,7 +12968,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
12968
12968
  const tempPath = dbPath + ".recovery-tmp";
12969
12969
  copyFileSync4(newestBackup.path, tempPath);
12970
12970
  renameSync(tempPath, dbPath);
12971
- log9.info(
12971
+ log10.info(
12972
12972
  { dbPath, backupPath: newestBackup.path, restoredTasks: backupTaskCount },
12973
12973
  "Database auto-recovered from backup successfully."
12974
12974
  );
@@ -12978,7 +12978,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
12978
12978
  runMigrations(restoredNativeDb, restoredDb);
12979
12979
  _db = restoredDb;
12980
12980
  } catch (err) {
12981
- log9.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
12981
+ log10.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
12982
12982
  }
12983
12983
  }
12984
12984
  async function getDb(cwd) {
@@ -13012,7 +13012,7 @@ async function getDb(cwd) {
13012
13012
  const { execFileSync: execFileSync12 } = await import("node:child_process");
13013
13013
  const gitCwd = resolve3(dbPath, "..", "..");
13014
13014
  const filesToCheck = [dbPath, dbPath + "-wal", dbPath + "-shm"];
13015
- const log9 = getLogger("sqlite");
13015
+ const log10 = getLogger("sqlite");
13016
13016
  for (const fileToCheck of filesToCheck) {
13017
13017
  try {
13018
13018
  execFileSync12("git", ["ls-files", "--error-unmatch", fileToCheck], {
@@ -13021,7 +13021,7 @@ async function getDb(cwd) {
13021
13021
  });
13022
13022
  const basename18 = fileToCheck.split(/[\\/]/).pop();
13023
13023
  const relPath = fileToCheck.replace(gitCwd + sep, "");
13024
- log9.warn(
13024
+ log10.warn(
13025
13025
  { path: fileToCheck },
13026
13026
  `${basename18} is tracked by project git \u2014 this risks data loss on branch switch. Resolution (ADR-013 \xA79): \`git rm --cached ${relPath}\` and rely on \`.cleo/backups/sqlite/\` snapshots + \`cleo backup add\` for recovery.`
13027
13027
  );
@@ -17156,8 +17156,7 @@ function taskListItemNext(taskId) {
17156
17156
  }
17157
17157
  function sessionListItemNext(sessionId) {
17158
17158
  return {
17159
- show: `cleo session show ${sessionId}`,
17160
- serialize: `cleo session serialize ${sessionId}`
17159
+ show: `cleo session show ${sessionId}`
17161
17160
  };
17162
17161
  }
17163
17162
  function sessionStartNext() {
@@ -17330,8 +17329,8 @@ function checkFts5Available(nativeDb) {
17330
17329
  }
17331
17330
  return _fts5Available;
17332
17331
  }
17333
- function execDDL(nativeDb, sql11) {
17334
- nativeDb.prepare(sql11).run();
17332
+ function execDDL(nativeDb, sql12) {
17333
+ nativeDb.prepare(sql12).run();
17335
17334
  }
17336
17335
  function ensureFts5Tables(nativeDb) {
17337
17336
  if (!checkFts5Available(nativeDb)) {
@@ -18446,8 +18445,8 @@ __export(memory_bridge_exports, {
18446
18445
  });
18447
18446
  import { existsSync as existsSync28, mkdirSync as mkdirSync7, readFileSync as readFileSync17, writeFileSync as writeFileSync3 } from "node:fs";
18448
18447
  import { join as join32 } from "node:path";
18449
- function typedAll2(db, sql11, ...params) {
18450
- return db.prepare(sql11).all(...params);
18448
+ function typedAll2(db, sql12, ...params) {
18449
+ return db.prepare(sql12).all(...params);
18451
18450
  }
18452
18451
  async function generateMemoryBridgeContent(projectRoot, config2) {
18453
18452
  const cfg = { ...DEFAULT_CONFIG, ...config2 };
@@ -28857,7 +28856,7 @@ function collectAdrFiles(dir) {
28857
28856
  }
28858
28857
  async function syncAdrsToDb(projectRoot) {
28859
28858
  const adrsDir = join19(projectRoot, ".cleo", "adrs");
28860
- const result = { inserted: 0, updated: 0, skipped: 0, errors: [] };
28859
+ const result = { inserted: 0, updated: 0, skipped: 0, errors: [], warnings: [] };
28861
28860
  if (!existsSync16(adrsDir)) {
28862
28861
  return result;
28863
28862
  }
@@ -28875,9 +28874,36 @@ async function syncAdrsToDb(projectRoot) {
28875
28874
  const fm = record2.frontmatter;
28876
28875
  const dbRelPath = `.cleo/adrs/${relPath}`;
28877
28876
  const content = readFileSync6(filePath, "utf-8");
28878
- const supersedesId = fm.Supersedes ? extractAdrIdFromRef(fm.Supersedes) : null;
28879
- const supersededById = fm["Superseded By"] ? extractAdrIdFromRef(fm["Superseded By"]) : null;
28880
- const amendsId = fm.Amends ? extractAdrIdFromRef(fm.Amends) : null;
28877
+ let supersedesId = fm.Supersedes ? extractAdrIdFromRef(fm.Supersedes) : null;
28878
+ let supersededById = fm["Superseded By"] ? extractAdrIdFromRef(fm["Superseded By"]) : null;
28879
+ let amendsId = fm.Amends ? extractAdrIdFromRef(fm.Amends) : null;
28880
+ if (supersedesId) {
28881
+ const exists2 = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq13(architectureDecisions.id, supersedesId)).all();
28882
+ if (exists2.length === 0) {
28883
+ result.warnings.push(
28884
+ `${record2.id}: supersedes target ${supersedesId} not found in DB, setting to null`
28885
+ );
28886
+ supersedesId = null;
28887
+ }
28888
+ }
28889
+ if (supersededById) {
28890
+ const exists2 = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq13(architectureDecisions.id, supersededById)).all();
28891
+ if (exists2.length === 0) {
28892
+ result.warnings.push(
28893
+ `${record2.id}: supersededBy target ${supersededById} not found in DB, setting to null`
28894
+ );
28895
+ supersededById = null;
28896
+ }
28897
+ }
28898
+ if (amendsId) {
28899
+ const exists2 = await db.select({ id: architectureDecisions.id }).from(architectureDecisions).where(eq13(architectureDecisions.id, amendsId)).all();
28900
+ if (exists2.length === 0) {
28901
+ result.warnings.push(
28902
+ `${record2.id}: amends target ${amendsId} not found in DB, setting to null`
28903
+ );
28904
+ amendsId = null;
28905
+ }
28906
+ }
28881
28907
  const rowBase = {
28882
28908
  id: record2.id,
28883
28909
  title: record2.title,
@@ -28907,6 +28933,13 @@ async function syncAdrsToDb(projectRoot) {
28907
28933
  await db.delete(adrTaskLinks).where(eq13(adrTaskLinks.adrId, record2.id));
28908
28934
  if (fm["Related Tasks"]) {
28909
28935
  for (const taskId of parseTaskIds2(fm["Related Tasks"])) {
28936
+ const taskExists = await db.select({ id: tasks.id }).from(tasks).where(eq13(tasks.id, taskId)).all();
28937
+ if (taskExists.length === 0) {
28938
+ result.warnings.push(
28939
+ `${record2.id}: related task ${taskId} not found in DB, skipping link`
28940
+ );
28941
+ continue;
28942
+ }
28910
28943
  await db.insert(adrTaskLinks).values({ adrId: record2.id, taskId, linkType: "related" });
28911
28944
  }
28912
28945
  }
@@ -40299,10 +40332,12 @@ import { randomUUID as randomUUID6 } from "node:crypto";
40299
40332
  init_logger();
40300
40333
 
40301
40334
  // packages/core/src/reconciliation/link-store.ts
40335
+ init_logger();
40302
40336
  init_sqlite2();
40303
40337
  init_tasks_schema();
40304
40338
  import { randomUUID as randomUUID5 } from "node:crypto";
40305
- import { and as and8, eq as eq11 } from "drizzle-orm";
40339
+ import { and as and8, eq as eq11, sql as sql11 } from "drizzle-orm";
40340
+ var log6 = getLogger("link-store");
40306
40341
  async function getLinksByProvider(providerId, cwd) {
40307
40342
  const db = await getDb(cwd);
40308
40343
  const rows = await db.select().from(externalTaskLinks).where(eq11(externalTaskLinks.providerId, providerId));
@@ -40323,7 +40358,46 @@ async function getLinksByTaskId(taskId, cwd) {
40323
40358
  const rows = await db.select().from(externalTaskLinks).where(eq11(externalTaskLinks.taskId, taskId));
40324
40359
  return rows.map(rowToLink);
40325
40360
  }
40361
+ async function ensureExternalTaskLinksTable(cwd) {
40362
+ const db = await getDb(cwd);
40363
+ try {
40364
+ db.run(
40365
+ sql11.raw(`
40366
+ CREATE TABLE IF NOT EXISTS external_task_links (
40367
+ id text PRIMARY KEY NOT NULL,
40368
+ task_id text NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
40369
+ provider_id text NOT NULL,
40370
+ external_id text NOT NULL,
40371
+ external_url text,
40372
+ external_title text,
40373
+ link_type text NOT NULL,
40374
+ sync_direction text NOT NULL DEFAULT 'inbound',
40375
+ metadata_json text DEFAULT '{}',
40376
+ linked_at text NOT NULL DEFAULT (datetime('now')),
40377
+ last_sync_at text
40378
+ )
40379
+ `)
40380
+ );
40381
+ db.run(
40382
+ sql11.raw(
40383
+ `CREATE UNIQUE INDEX IF NOT EXISTS uq_ext_links_task_provider_external ON external_task_links(task_id, provider_id, external_id)`
40384
+ )
40385
+ );
40386
+ db.run(
40387
+ sql11.raw(`CREATE INDEX IF NOT EXISTS idx_ext_links_task_id ON external_task_links(task_id)`)
40388
+ );
40389
+ db.run(
40390
+ sql11.raw(
40391
+ `CREATE INDEX IF NOT EXISTS idx_ext_links_provider_id ON external_task_links(provider_id)`
40392
+ )
40393
+ );
40394
+ } catch (err) {
40395
+ log6.warn({ err }, "Failed to ensure external_task_links table exists");
40396
+ throw err;
40397
+ }
40398
+ }
40326
40399
  async function createLink(params, cwd) {
40400
+ await ensureExternalTaskLinksTable(cwd);
40327
40401
  const db = await getDb(cwd);
40328
40402
  const now = (/* @__PURE__ */ new Date()).toISOString();
40329
40403
  const id = randomUUID5();
@@ -40392,7 +40466,7 @@ init_brain_accessor();
40392
40466
  init_brain_sqlite();
40393
40467
  init_data_accessor();
40394
40468
  init_registry3();
40395
- var log6 = getLogger("nexus:transfer");
40469
+ var log7 = getLogger("nexus:transfer");
40396
40470
  async function previewTransfer(params) {
40397
40471
  return executeTransferInternal({ ...params, dryRun: true });
40398
40472
  }
@@ -40488,48 +40562,55 @@ async function executeTransferInternal(params) {
40488
40562
  return result;
40489
40563
  }
40490
40564
  let linksCreated = 0;
40491
- const targetAccessor = await getAccessor(targetProject.path);
40492
- const { tasks: targetTasks } = await targetAccessor.queryTasks({});
40493
- const targetTaskIds = new Set(targetTasks.map((t) => t.id));
40494
- for (const entry of entries) {
40495
- if (importResult.idRemap[entry.sourceId] && targetTaskIds.has(entry.targetId)) {
40496
- await createLink(
40497
- {
40498
- taskId: entry.targetId,
40499
- providerId: `nexus:${sourceProject.name}`,
40500
- externalId: entry.sourceId,
40501
- externalTitle: entry.title,
40502
- linkType: "transferred",
40503
- syncDirection: "inbound",
40504
- metadata: {
40505
- transferMode: mode,
40506
- transferScope: scope,
40507
- sourceProject: sourceProject.name,
40508
- transferredAt: (/* @__PURE__ */ new Date()).toISOString()
40509
- }
40510
- },
40511
- targetProject.path
40512
- );
40513
- linksCreated++;
40514
- await createLink(
40515
- {
40516
- taskId: entry.sourceId,
40517
- providerId: `nexus:${targetProject.name}`,
40518
- externalId: entry.targetId,
40519
- externalTitle: entry.title,
40520
- linkType: "transferred",
40521
- syncDirection: "outbound",
40522
- metadata: {
40523
- transferMode: mode,
40524
- transferScope: scope,
40525
- targetProject: targetProject.name,
40526
- transferredAt: (/* @__PURE__ */ new Date()).toISOString()
40527
- }
40528
- },
40529
- sourceProject.path
40530
- );
40531
- linksCreated++;
40565
+ try {
40566
+ const targetAccessor = await getAccessor(targetProject.path);
40567
+ const { tasks: targetTasks } = await targetAccessor.queryTasks({});
40568
+ const targetTaskIds = new Set(targetTasks.map((t) => t.id));
40569
+ for (const entry of entries) {
40570
+ if (importResult.idRemap[entry.sourceId] && targetTaskIds.has(entry.targetId)) {
40571
+ await createLink(
40572
+ {
40573
+ taskId: entry.targetId,
40574
+ providerId: `nexus:${sourceProject.name}`,
40575
+ externalId: entry.sourceId,
40576
+ externalTitle: entry.title,
40577
+ linkType: "transferred",
40578
+ syncDirection: "inbound",
40579
+ metadata: {
40580
+ transferMode: mode,
40581
+ transferScope: scope,
40582
+ sourceProject: sourceProject.name,
40583
+ transferredAt: (/* @__PURE__ */ new Date()).toISOString()
40584
+ }
40585
+ },
40586
+ targetProject.path
40587
+ );
40588
+ linksCreated++;
40589
+ await createLink(
40590
+ {
40591
+ taskId: entry.sourceId,
40592
+ providerId: `nexus:${targetProject.name}`,
40593
+ externalId: entry.targetId,
40594
+ externalTitle: entry.title,
40595
+ linkType: "transferred",
40596
+ syncDirection: "outbound",
40597
+ metadata: {
40598
+ transferMode: mode,
40599
+ transferScope: scope,
40600
+ targetProject: targetProject.name,
40601
+ transferredAt: (/* @__PURE__ */ new Date()).toISOString()
40602
+ }
40603
+ },
40604
+ sourceProject.path
40605
+ );
40606
+ linksCreated++;
40607
+ }
40532
40608
  }
40609
+ } catch (err) {
40610
+ log7.warn(
40611
+ { err, linksCreated },
40612
+ "Failed to create external_task_links during transfer \u2014 tasks were transferred successfully but provenance links could not be written"
40613
+ );
40533
40614
  }
40534
40615
  result.linksCreated = linksCreated;
40535
40616
  try {
@@ -40554,7 +40635,7 @@ async function executeTransferInternal(params) {
40554
40635
  })
40555
40636
  });
40556
40637
  } catch (err) {
40557
- log6.warn({ err }, "nexus transfer audit write failed");
40638
+ log7.warn({ err }, "nexus transfer audit write failed");
40558
40639
  }
40559
40640
  if (mode === "move") {
40560
40641
  let archived = 0;
@@ -40567,7 +40648,7 @@ async function executeTransferInternal(params) {
40567
40648
  });
40568
40649
  archived++;
40569
40650
  } catch (err) {
40570
- log6.warn({ err, taskId: entry.sourceId }, "failed to archive source task after transfer");
40651
+ log7.warn({ err, taskId: entry.sourceId }, "failed to archive source task after transfer");
40571
40652
  }
40572
40653
  }
40573
40654
  }
@@ -40605,7 +40686,7 @@ async function executeTransferInternal(params) {
40605
40686
  }
40606
40687
  }
40607
40688
  } catch (err) {
40608
- log6.warn({ err }, "brain observation transfer failed");
40689
+ log7.warn({ err }, "brain observation transfer failed");
40609
40690
  }
40610
40691
  result.brainObservationsTransferred = brainTransferred;
40611
40692
  result.manifest.brainObservationsTransferred = brainTransferred;
@@ -40653,8 +40734,8 @@ async function loadProjectACL(projectPath) {
40653
40734
  async function logAclFailure(projectPath) {
40654
40735
  try {
40655
40736
  const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
40656
- const log9 = getLogger2("nexus.acl");
40657
- log9.warn({ projectPath }, "Failed to load ACL configuration, defaulting to deny-all");
40737
+ const log10 = getLogger2("nexus.acl");
40738
+ log10.warn({ projectPath }, "Failed to load ACL configuration, defaulting to deny-all");
40658
40739
  } catch {
40659
40740
  }
40660
40741
  }
@@ -40809,9 +40890,9 @@ async function executeOperation(operation, taskId, projectPath, accessor, direct
40809
40890
  async function logRouteAudit(directive, projectName, taskId, operation, success2, error48) {
40810
40891
  try {
40811
40892
  const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
40812
- const log9 = getLogger2("nexus.route");
40893
+ const log10 = getLogger2("nexus.route");
40813
40894
  const level = success2 ? "info" : "warn";
40814
- log9[level](
40895
+ log10[level](
40815
40896
  {
40816
40897
  directive: directive.verb,
40817
40898
  agentId: directive.agentId,
@@ -46906,8 +46987,11 @@ function sanitizeParams(params, projectRoot, context) {
46906
46987
  continue;
46907
46988
  }
46908
46989
  if (typeof value === "string" && (key === "path" || key === "file") && projectRoot) {
46909
- sanitized[key] = sanitizePath(value, projectRoot);
46910
- continue;
46990
+ const allowExternalPath = context?.domain === "nexus" && (context?.operation === "register" || context?.operation === "reconcile");
46991
+ if (!allowExternalPath) {
46992
+ sanitized[key] = sanitizePath(value, projectRoot);
46993
+ continue;
46994
+ }
46911
46995
  }
46912
46996
  if (typeof value === "string" && (key === "title" || key === "description" || key === "content")) {
46913
46997
  const maxLen = key === "title" ? 200 : DEFAULT_MAX_CONTENT_LENGTH;
@@ -49311,7 +49395,7 @@ init_data_accessor();
49311
49395
 
49312
49396
  // packages/core/src/stats/workflow-telemetry.ts
49313
49397
  init_logger();
49314
- var log7 = getLogger("workflow-telemetry");
49398
+ var log8 = getLogger("workflow-telemetry");
49315
49399
  async function queryTasks(cwd, since) {
49316
49400
  try {
49317
49401
  const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
@@ -49333,7 +49417,7 @@ async function queryTasks(cwd, since) {
49333
49417
  }).from(tasks2).where(conditions.length > 0 ? and10(...conditions) : void 0).all();
49334
49418
  return rows;
49335
49419
  } catch (err) {
49336
- log7.warn({ err }, "Failed to query tasks for workflow telemetry");
49420
+ log8.warn({ err }, "Failed to query tasks for workflow telemetry");
49337
49421
  return [];
49338
49422
  }
49339
49423
  }
@@ -49367,7 +49451,7 @@ async function queryCompletionAuditRows(cwd, since) {
49367
49451
  return isComplete;
49368
49452
  });
49369
49453
  } catch (err) {
49370
- log7.warn({ err }, "Failed to query audit log for workflow telemetry");
49454
+ log8.warn({ err }, "Failed to query audit log for workflow telemetry");
49371
49455
  return [];
49372
49456
  }
49373
49457
  }
@@ -50154,13 +50238,22 @@ function rowToStickyNote3(row) {
50154
50238
  }
50155
50239
  async function listStickies(params, projectRoot) {
50156
50240
  const accessor = await getBrainAccessor(projectRoot);
50241
+ const hasTagFilter = params.tags && params.tags.length > 0;
50157
50242
  const rows = await accessor.findStickyNotes({
50158
50243
  status: params.status,
50159
50244
  color: params.color,
50160
50245
  priority: params.priority,
50161
- limit: params.limit
50246
+ limit: hasTagFilter ? void 0 : params.limit
50162
50247
  });
50163
- return rows.map(rowToStickyNote3);
50248
+ let notes = rows.map(rowToStickyNote3);
50249
+ if (hasTagFilter) {
50250
+ const requiredTags = params.tags;
50251
+ notes = notes.filter((note) => requiredTags.every((t) => note.tags.includes(t)));
50252
+ if (params.limit && notes.length > params.limit) {
50253
+ notes = notes.slice(0, params.limit);
50254
+ }
50255
+ }
50256
+ return notes;
50164
50257
  }
50165
50258
 
50166
50259
  // packages/core/src/sticky/purge.ts
@@ -50812,11 +50905,11 @@ import { join as join87 } from "node:path";
50812
50905
  import { Readable } from "node:stream";
50813
50906
  import { pipeline } from "node:stream/promises";
50814
50907
  import { createGzip } from "node:zlib";
50815
- var log8 = getLogger("prune");
50908
+ var log9 = getLogger("prune");
50816
50909
  async function pruneAuditLog(cleoDir, config2) {
50817
50910
  try {
50818
50911
  if (!config2.auditRetentionDays || config2.auditRetentionDays <= 0) {
50819
- log8.debug("auditRetentionDays is 0 or unset; skipping audit prune");
50912
+ log9.debug("auditRetentionDays is 0 or unset; skipping audit prune");
50820
50913
  return { rowsArchived: 0, rowsDeleted: 0 };
50821
50914
  }
50822
50915
  const cutoff = new Date(Date.now() - config2.auditRetentionDays * 864e5).toISOString();
@@ -50827,7 +50920,7 @@ async function pruneAuditLog(cleoDir, config2) {
50827
50920
  const db = await getDb3(projectRoot);
50828
50921
  const oldRows = await db.select().from(auditLog2).where(lt3(auditLog2.timestamp, cutoff));
50829
50922
  if (oldRows.length === 0) {
50830
- log8.debug("No audit_log rows older than cutoff; nothing to prune");
50923
+ log9.debug("No audit_log rows older than cutoff; nothing to prune");
50831
50924
  return { rowsArchived: 0, rowsDeleted: 0 };
50832
50925
  }
50833
50926
  let archivePath;
@@ -50845,17 +50938,17 @@ async function pruneAuditLog(cleoDir, config2) {
50845
50938
  const inStream = Readable.from([jsonlContent]);
50846
50939
  await pipeline(inStream, gzip, outStream);
50847
50940
  rowsArchived = oldRows.length;
50848
- log8.info(
50941
+ log9.info(
50849
50942
  { archivePath, rowsArchived },
50850
50943
  `Archived ${rowsArchived} audit rows to ${archivePath}`
50851
50944
  );
50852
50945
  } catch (archiveErr) {
50853
- log8.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
50946
+ log9.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
50854
50947
  archivePath = void 0;
50855
50948
  }
50856
50949
  }
50857
50950
  await db.delete(auditLog2).where(lt3(auditLog2.timestamp, cutoff)).run();
50858
- log8.info(
50951
+ log9.info(
50859
50952
  { rowsDeleted: oldRows.length, cutoff },
50860
50953
  `Pruned ${oldRows.length} audit_log rows older than ${cutoff}`
50861
50954
  );
@@ -50865,7 +50958,7 @@ async function pruneAuditLog(cleoDir, config2) {
50865
50958
  archivePath
50866
50959
  };
50867
50960
  } catch (err) {
50868
- log8.warn({ err }, "audit log pruning failed");
50961
+ log9.warn({ err }, "audit log pruning failed");
50869
50962
  return { rowsArchived: 0, rowsDeleted: 0 };
50870
50963
  }
50871
50964
  }