@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.
- package/dist/adrs/sync.d.ts.map +1 -1
- package/dist/adrs/types.d.ts +1 -0
- package/dist/adrs/types.d.ts.map +1 -1
- package/dist/index.js +198 -105
- package/dist/index.js.map +3 -3
- package/dist/mvi-helpers.d.ts.map +1 -1
- package/dist/reconciliation/link-store.d.ts +4 -0
- package/dist/reconciliation/link-store.d.ts.map +1 -1
- package/dist/security/input-sanitization.d.ts.map +1 -1
- package/dist/sticky/list.d.ts.map +1 -1
- package/dist/sticky/types.d.ts +2 -0
- package/dist/sticky/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/adrs/sync.ts +58 -5
- package/src/adrs/types.ts +1 -0
- package/src/mvi-helpers.ts +0 -1
- package/src/nexus/transfer.ts +54 -44
- package/src/reconciliation/link-store.ts +61 -1
- package/src/security/input-sanitization.ts +8 -2
- package/src/sticky/list.ts +18 -2
- package/src/sticky/types.ts +2 -0
package/dist/adrs/sync.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/adrs/types.d.ts
CHANGED
package/dist/adrs/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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(
|
|
1549
|
+
constructor(sql12, fields, alias, isWith = false, usedTables = []) {
|
|
1550
1550
|
this._ = {
|
|
1551
1551
|
brand: "Subquery",
|
|
1552
|
-
sql:
|
|
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(
|
|
1933
|
-
this.sql =
|
|
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,
|
|
2638
|
-
if (typeof this.forJsonSelect === "function") return this.forJsonSelect(identifier,
|
|
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
|
|
2645
|
+
return sql12`cast(${identifier} as text)`;
|
|
2646
2646
|
case "blob":
|
|
2647
|
-
return
|
|
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,
|
|
3816
|
-
if (typeof this.forJsonSelect === "function") return this.forJsonSelect(identifier,
|
|
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
|
|
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(
|
|
7708
|
-
return
|
|
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(
|
|
8806
|
-
const dataToHash = `${
|
|
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(
|
|
8986
|
-
return (await this.values(
|
|
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
|
|
11078
|
-
|
|
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
|
|
11111
|
-
|
|
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
|
|
11157
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
17334
|
-
nativeDb.prepare(
|
|
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,
|
|
18450
|
-
return db.prepare(
|
|
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
|
-
|
|
28879
|
-
|
|
28880
|
-
|
|
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
|
|
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
|
-
|
|
40492
|
-
|
|
40493
|
-
|
|
40494
|
-
|
|
40495
|
-
|
|
40496
|
-
|
|
40497
|
-
|
|
40498
|
-
|
|
40499
|
-
|
|
40500
|
-
|
|
40501
|
-
|
|
40502
|
-
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
|
|
40507
|
-
|
|
40508
|
-
|
|
40509
|
-
|
|
40510
|
-
|
|
40511
|
-
|
|
40512
|
-
|
|
40513
|
-
|
|
40514
|
-
|
|
40515
|
-
|
|
40516
|
-
|
|
40517
|
-
|
|
40518
|
-
|
|
40519
|
-
|
|
40520
|
-
|
|
40521
|
-
|
|
40522
|
-
|
|
40523
|
-
|
|
40524
|
-
|
|
40525
|
-
|
|
40526
|
-
|
|
40527
|
-
|
|
40528
|
-
|
|
40529
|
-
|
|
40530
|
-
|
|
40531
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
40657
|
-
|
|
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
|
|
40893
|
+
const log10 = getLogger2("nexus.route");
|
|
40813
40894
|
const level = success2 ? "info" : "warn";
|
|
40814
|
-
|
|
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
|
-
|
|
46910
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
50908
|
+
var log9 = getLogger("prune");
|
|
50816
50909
|
async function pruneAuditLog(cleoDir, config2) {
|
|
50817
50910
|
try {
|
|
50818
50911
|
if (!config2.auditRetentionDays || config2.auditRetentionDays <= 0) {
|
|
50819
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50941
|
+
log9.info(
|
|
50849
50942
|
{ archivePath, rowsArchived },
|
|
50850
50943
|
`Archived ${rowsArchived} audit rows to ${archivePath}`
|
|
50851
50944
|
);
|
|
50852
50945
|
} catch (archiveErr) {
|
|
50853
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50961
|
+
log9.warn({ err }, "audit log pruning failed");
|
|
50869
50962
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
50870
50963
|
}
|
|
50871
50964
|
}
|