@cleocode/cleo 2026.3.44 → 2026.3.45
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 +614 -162
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +627 -175
- package/dist/mcp/index.js.map +4 -4
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -9123,7 +9123,7 @@ var init_tasks_schema = __esm({
|
|
|
9123
9123
|
"supersedes"
|
|
9124
9124
|
];
|
|
9125
9125
|
LIFECYCLE_TRANSITION_TYPES = ["automatic", "manual", "forced"];
|
|
9126
|
-
EXTERNAL_LINK_TYPES = ["created", "matched", "manual"];
|
|
9126
|
+
EXTERNAL_LINK_TYPES = ["created", "matched", "manual", "transferred"];
|
|
9127
9127
|
SYNC_DIRECTIONS = ["inbound", "outbound", "bidirectional"];
|
|
9128
9128
|
tasks = sqliteTable(
|
|
9129
9129
|
"tasks",
|
|
@@ -10583,7 +10583,9 @@ function getBrainDbPath(cwd) {
|
|
|
10583
10583
|
function resolveBrainMigrationsFolder() {
|
|
10584
10584
|
const __filename = fileURLToPath(import.meta.url);
|
|
10585
10585
|
const __dirname = dirname3(__filename);
|
|
10586
|
-
|
|
10586
|
+
const isBundled = __dirname.endsWith("/dist") || __dirname.endsWith("\\dist");
|
|
10587
|
+
const pkgRoot = isBundled ? join7(__dirname, "..") : join7(__dirname, "..", "..");
|
|
10588
|
+
return join7(pkgRoot, "migrations", "drizzle-brain");
|
|
10587
10589
|
}
|
|
10588
10590
|
function tableExists(nativeDb, tableName) {
|
|
10589
10591
|
const result = nativeDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(tableName);
|
|
@@ -10827,7 +10829,9 @@ function getNexusDbPath() {
|
|
|
10827
10829
|
function resolveNexusMigrationsFolder() {
|
|
10828
10830
|
const __filename = fileURLToPath2(import.meta.url);
|
|
10829
10831
|
const __dirname = dirname4(__filename);
|
|
10830
|
-
|
|
10832
|
+
const isBundled = __dirname.endsWith("/dist") || __dirname.endsWith("\\dist");
|
|
10833
|
+
const pkgRoot = isBundled ? join8(__dirname, "..") : join8(__dirname, "..", "..");
|
|
10834
|
+
return join8(pkgRoot, "migrations", "drizzle-nexus");
|
|
10831
10835
|
}
|
|
10832
10836
|
function tableExists2(nativeDb, tableName) {
|
|
10833
10837
|
const result = nativeDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(tableName);
|
|
@@ -11018,7 +11022,7 @@ function getDbPath(cwd) {
|
|
|
11018
11022
|
return join9(getCleoDirAbsolute(cwd), DB_FILENAME3);
|
|
11019
11023
|
}
|
|
11020
11024
|
async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
11021
|
-
const
|
|
11025
|
+
const log10 = getLogger("sqlite");
|
|
11022
11026
|
try {
|
|
11023
11027
|
const countResult = nativeDb.prepare("SELECT COUNT(*) as cnt FROM tasks").get();
|
|
11024
11028
|
const taskCount = countResult?.cnt ?? 0;
|
|
@@ -11039,7 +11043,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
11039
11043
|
if (backupTaskCount < MIN_BACKUP_TASK_COUNT) {
|
|
11040
11044
|
return;
|
|
11041
11045
|
}
|
|
11042
|
-
|
|
11046
|
+
log10.warn(
|
|
11043
11047
|
{ dbPath, backupPath: newestBackup.path, backupTasks: backupTaskCount },
|
|
11044
11048
|
`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).`
|
|
11045
11049
|
);
|
|
@@ -11057,7 +11061,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
11057
11061
|
const tempPath = dbPath + ".recovery-tmp";
|
|
11058
11062
|
copyFileSync3(newestBackup.path, tempPath);
|
|
11059
11063
|
renameSync(tempPath, dbPath);
|
|
11060
|
-
|
|
11064
|
+
log10.info(
|
|
11061
11065
|
{ dbPath, backupPath: newestBackup.path, restoredTasks: backupTaskCount },
|
|
11062
11066
|
"Database auto-recovered from backup successfully."
|
|
11063
11067
|
);
|
|
@@ -11067,7 +11071,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
11067
11071
|
runMigrations(restoredNativeDb, restoredDb);
|
|
11068
11072
|
_db2 = restoredDb;
|
|
11069
11073
|
} catch (err) {
|
|
11070
|
-
|
|
11074
|
+
log10.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
|
|
11071
11075
|
}
|
|
11072
11076
|
}
|
|
11073
11077
|
async function getDb(cwd) {
|
|
@@ -11098,7 +11102,7 @@ async function getDb(cwd) {
|
|
|
11098
11102
|
const { execFileSync: execFileSync17 } = await import("node:child_process");
|
|
11099
11103
|
const gitCwd = resolve3(dbPath, "..", "..");
|
|
11100
11104
|
const filesToCheck = [dbPath, dbPath + "-wal", dbPath + "-shm"];
|
|
11101
|
-
const
|
|
11105
|
+
const log10 = getLogger("sqlite");
|
|
11102
11106
|
for (const fileToCheck of filesToCheck) {
|
|
11103
11107
|
try {
|
|
11104
11108
|
execFileSync17("git", ["ls-files", "--error-unmatch", fileToCheck], {
|
|
@@ -11106,7 +11110,7 @@ async function getDb(cwd) {
|
|
|
11106
11110
|
stdio: "pipe"
|
|
11107
11111
|
});
|
|
11108
11112
|
const basename19 = fileToCheck.split(/[\\/]/).pop();
|
|
11109
|
-
|
|
11113
|
+
log10.warn(
|
|
11110
11114
|
{ path: fileToCheck },
|
|
11111
11115
|
`${basename19} is tracked by project git \u2014 this risks data loss on branch switch. Run: git rm --cached ${fileToCheck.replace(gitCwd + sep, "")} (see ADR-013, T5188)`
|
|
11112
11116
|
);
|
|
@@ -11128,7 +11132,9 @@ async function getDb(cwd) {
|
|
|
11128
11132
|
function resolveMigrationsFolder() {
|
|
11129
11133
|
const __filename = fileURLToPath3(import.meta.url);
|
|
11130
11134
|
const __dirname = dirname5(__filename);
|
|
11131
|
-
|
|
11135
|
+
const isBundled = __dirname.endsWith("/dist") || __dirname.endsWith("\\dist");
|
|
11136
|
+
const pkgRoot = isBundled ? join9(__dirname, "..") : join9(__dirname, "..", "..");
|
|
11137
|
+
return join9(pkgRoot, "migrations", "drizzle-tasks");
|
|
11132
11138
|
}
|
|
11133
11139
|
function tableExists3(nativeDb, tableName) {
|
|
11134
11140
|
const result = nativeDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(tableName);
|
|
@@ -14396,6 +14402,37 @@ function buildExportPackage(tasks2, options) {
|
|
|
14396
14402
|
relationshipGraph
|
|
14397
14403
|
};
|
|
14398
14404
|
}
|
|
14405
|
+
function exportSingle(taskId, allTasks, projectName) {
|
|
14406
|
+
const task = allTasks.find((t) => t.id === taskId);
|
|
14407
|
+
if (!task) return null;
|
|
14408
|
+
return buildExportPackage([task], {
|
|
14409
|
+
mode: "single",
|
|
14410
|
+
rootTaskIds: [taskId],
|
|
14411
|
+
includeChildren: false,
|
|
14412
|
+
projectName
|
|
14413
|
+
});
|
|
14414
|
+
}
|
|
14415
|
+
function exportSubtree(rootId, allTasks, projectName) {
|
|
14416
|
+
const root = allTasks.find((t) => t.id === rootId);
|
|
14417
|
+
if (!root) return null;
|
|
14418
|
+
const collected = /* @__PURE__ */ new Map();
|
|
14419
|
+
const queue = [rootId];
|
|
14420
|
+
while (queue.length > 0) {
|
|
14421
|
+
const id = queue.shift();
|
|
14422
|
+
const task = allTasks.find((t) => t.id === id);
|
|
14423
|
+
if (!task || collected.has(id)) continue;
|
|
14424
|
+
collected.set(id, task);
|
|
14425
|
+
const children = allTasks.filter((t) => t.parentId === id);
|
|
14426
|
+
queue.push(...children.map((c) => c.id));
|
|
14427
|
+
}
|
|
14428
|
+
const tasks2 = [...collected.values()];
|
|
14429
|
+
return buildExportPackage(tasks2, {
|
|
14430
|
+
mode: "subtree",
|
|
14431
|
+
rootTaskIds: [rootId],
|
|
14432
|
+
includeChildren: true,
|
|
14433
|
+
projectName
|
|
14434
|
+
});
|
|
14435
|
+
}
|
|
14399
14436
|
var EXPORT_FORMAT_VERSION;
|
|
14400
14437
|
var init_export2 = __esm({
|
|
14401
14438
|
"packages/core/src/store/export.ts"() {
|
|
@@ -14856,20 +14893,7 @@ function topologicalSort(tasks2) {
|
|
|
14856
14893
|
}
|
|
14857
14894
|
return sorted;
|
|
14858
14895
|
}
|
|
14859
|
-
async function
|
|
14860
|
-
const { file: file2 } = params;
|
|
14861
|
-
try {
|
|
14862
|
-
await access2(file2, fsConstants2.R_OK);
|
|
14863
|
-
} catch {
|
|
14864
|
-
throw new Error(`Export file not found: ${file2}`);
|
|
14865
|
-
}
|
|
14866
|
-
const content = await readFile4(file2, "utf-8");
|
|
14867
|
-
let exportPkg;
|
|
14868
|
-
try {
|
|
14869
|
-
exportPkg = JSON.parse(content);
|
|
14870
|
-
} catch {
|
|
14871
|
-
throw new Error(`Invalid JSON in: ${file2}`);
|
|
14872
|
-
}
|
|
14896
|
+
async function importFromPackage(exportPkg, options = {}) {
|
|
14873
14897
|
if (exportPkg._meta?.format !== "cleo-export") {
|
|
14874
14898
|
throw new Error(
|
|
14875
14899
|
`Invalid export format (expected 'cleo-export', got '${exportPkg._meta?.format}')`
|
|
@@ -14878,16 +14902,16 @@ async function importTasksPackage(params) {
|
|
|
14878
14902
|
if (!exportPkg.tasks?.length) {
|
|
14879
14903
|
throw new Error("Export package contains no tasks");
|
|
14880
14904
|
}
|
|
14881
|
-
const accessor = await getAccessor(
|
|
14905
|
+
const accessor = await getAccessor(options.cwd);
|
|
14882
14906
|
const { tasks: existingTasks } = await accessor.queryTasks({});
|
|
14883
|
-
const onConflict =
|
|
14884
|
-
const onMissingDep =
|
|
14885
|
-
const force =
|
|
14886
|
-
const parentId =
|
|
14887
|
-
const phaseOverride =
|
|
14888
|
-
const addLabel =
|
|
14889
|
-
const resetStatus =
|
|
14890
|
-
const addProvenance =
|
|
14907
|
+
const onConflict = options.onConflict ?? "fail";
|
|
14908
|
+
const onMissingDep = options.onMissingDep === "fail" ? "fail" : "strip";
|
|
14909
|
+
const force = options.force ?? false;
|
|
14910
|
+
const parentId = options.parent;
|
|
14911
|
+
const phaseOverride = options.phase;
|
|
14912
|
+
const addLabel = options.addLabel;
|
|
14913
|
+
const resetStatus = options.resetStatus;
|
|
14914
|
+
const addProvenance = options.provenance !== false;
|
|
14891
14915
|
if (parentId) {
|
|
14892
14916
|
const parentExists = existingTasks.some((t) => t.id === parentId);
|
|
14893
14917
|
if (!parentExists) {
|
|
@@ -14956,7 +14980,7 @@ async function importTasksPackage(params) {
|
|
|
14956
14980
|
existingTitles.add(remapped.title.toLowerCase());
|
|
14957
14981
|
existingIds.add(remapped.id);
|
|
14958
14982
|
}
|
|
14959
|
-
if (
|
|
14983
|
+
if (options.dryRun) {
|
|
14960
14984
|
return {
|
|
14961
14985
|
imported: transformed.length,
|
|
14962
14986
|
skipped: skipped.length,
|
|
@@ -14976,6 +15000,33 @@ async function importTasksPackage(params) {
|
|
|
14976
15000
|
idRemap: idRemapJson
|
|
14977
15001
|
};
|
|
14978
15002
|
}
|
|
15003
|
+
async function importTasksPackage(params) {
|
|
15004
|
+
const { file: file2 } = params;
|
|
15005
|
+
try {
|
|
15006
|
+
await access2(file2, fsConstants2.R_OK);
|
|
15007
|
+
} catch {
|
|
15008
|
+
throw new Error(`Export file not found: ${file2}`);
|
|
15009
|
+
}
|
|
15010
|
+
const content = await readFile4(file2, "utf-8");
|
|
15011
|
+
let exportPkg;
|
|
15012
|
+
try {
|
|
15013
|
+
exportPkg = JSON.parse(content);
|
|
15014
|
+
} catch {
|
|
15015
|
+
throw new Error(`Invalid JSON in: ${file2}`);
|
|
15016
|
+
}
|
|
15017
|
+
return importFromPackage(exportPkg, {
|
|
15018
|
+
cwd: params.cwd,
|
|
15019
|
+
dryRun: params.dryRun,
|
|
15020
|
+
parent: params.parent,
|
|
15021
|
+
phase: params.phase,
|
|
15022
|
+
addLabel: params.addLabel,
|
|
15023
|
+
provenance: params.provenance,
|
|
15024
|
+
resetStatus: params.resetStatus,
|
|
15025
|
+
onConflict: params.onConflict,
|
|
15026
|
+
onMissingDep: params.onMissingDep === "placeholder" ? "strip" : params.onMissingDep,
|
|
15027
|
+
force: params.force
|
|
15028
|
+
});
|
|
15029
|
+
}
|
|
14979
15030
|
var init_import_tasks = __esm({
|
|
14980
15031
|
"packages/core/src/admin/import-tasks.ts"() {
|
|
14981
15032
|
"use strict";
|
|
@@ -43370,6 +43421,338 @@ var init_sharing = __esm({
|
|
|
43370
43421
|
}
|
|
43371
43422
|
});
|
|
43372
43423
|
|
|
43424
|
+
// packages/core/src/reconciliation/link-store.ts
|
|
43425
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
43426
|
+
import { and as and5, eq as eq8 } from "drizzle-orm";
|
|
43427
|
+
async function getLinksByProvider(providerId, cwd) {
|
|
43428
|
+
const db = await getDb(cwd);
|
|
43429
|
+
const rows = await db.select().from(externalTaskLinks).where(eq8(externalTaskLinks.providerId, providerId));
|
|
43430
|
+
return rows.map(rowToLink);
|
|
43431
|
+
}
|
|
43432
|
+
async function getLinkByExternalId(providerId, externalId, cwd) {
|
|
43433
|
+
const db = await getDb(cwd);
|
|
43434
|
+
const rows = await db.select().from(externalTaskLinks).where(
|
|
43435
|
+
and5(
|
|
43436
|
+
eq8(externalTaskLinks.providerId, providerId),
|
|
43437
|
+
eq8(externalTaskLinks.externalId, externalId)
|
|
43438
|
+
)
|
|
43439
|
+
);
|
|
43440
|
+
return rows.length > 0 ? rowToLink(rows[0]) : null;
|
|
43441
|
+
}
|
|
43442
|
+
async function getLinksByTaskId(taskId, cwd) {
|
|
43443
|
+
const db = await getDb(cwd);
|
|
43444
|
+
const rows = await db.select().from(externalTaskLinks).where(eq8(externalTaskLinks.taskId, taskId));
|
|
43445
|
+
return rows.map(rowToLink);
|
|
43446
|
+
}
|
|
43447
|
+
async function createLink(params, cwd) {
|
|
43448
|
+
const db = await getDb(cwd);
|
|
43449
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
43450
|
+
const id = randomUUID4();
|
|
43451
|
+
await db.insert(externalTaskLinks).values({
|
|
43452
|
+
id,
|
|
43453
|
+
taskId: params.taskId,
|
|
43454
|
+
providerId: params.providerId,
|
|
43455
|
+
externalId: params.externalId,
|
|
43456
|
+
externalUrl: params.externalUrl ?? null,
|
|
43457
|
+
externalTitle: params.externalTitle ?? null,
|
|
43458
|
+
linkType: params.linkType,
|
|
43459
|
+
syncDirection: params.syncDirection ?? "inbound",
|
|
43460
|
+
metadataJson: params.metadata ? JSON.stringify(params.metadata) : "{}",
|
|
43461
|
+
linkedAt: now2,
|
|
43462
|
+
lastSyncAt: now2
|
|
43463
|
+
});
|
|
43464
|
+
return {
|
|
43465
|
+
id,
|
|
43466
|
+
taskId: params.taskId,
|
|
43467
|
+
providerId: params.providerId,
|
|
43468
|
+
externalId: params.externalId,
|
|
43469
|
+
externalUrl: params.externalUrl ?? null,
|
|
43470
|
+
externalTitle: params.externalTitle ?? null,
|
|
43471
|
+
linkType: params.linkType,
|
|
43472
|
+
syncDirection: params.syncDirection ?? "inbound",
|
|
43473
|
+
metadata: params.metadata,
|
|
43474
|
+
linkedAt: now2,
|
|
43475
|
+
lastSyncAt: now2
|
|
43476
|
+
};
|
|
43477
|
+
}
|
|
43478
|
+
async function touchLink(linkId, updates, cwd) {
|
|
43479
|
+
const db = await getDb(cwd);
|
|
43480
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
43481
|
+
const values = { lastSyncAt: now2 };
|
|
43482
|
+
if (updates?.externalTitle !== void 0) {
|
|
43483
|
+
values.externalTitle = updates.externalTitle;
|
|
43484
|
+
}
|
|
43485
|
+
if (updates?.metadata !== void 0) {
|
|
43486
|
+
values.metadataJson = JSON.stringify(updates.metadata);
|
|
43487
|
+
}
|
|
43488
|
+
await db.update(externalTaskLinks).set(values).where(eq8(externalTaskLinks.id, linkId));
|
|
43489
|
+
}
|
|
43490
|
+
async function removeLinksByProvider(providerId, cwd) {
|
|
43491
|
+
const db = await getDb(cwd);
|
|
43492
|
+
const result = await db.delete(externalTaskLinks).where(eq8(externalTaskLinks.providerId, providerId));
|
|
43493
|
+
return Number(result.changes);
|
|
43494
|
+
}
|
|
43495
|
+
function rowToLink(row) {
|
|
43496
|
+
return {
|
|
43497
|
+
id: row.id,
|
|
43498
|
+
taskId: row.taskId,
|
|
43499
|
+
providerId: row.providerId,
|
|
43500
|
+
externalId: row.externalId,
|
|
43501
|
+
externalUrl: row.externalUrl,
|
|
43502
|
+
externalTitle: row.externalTitle,
|
|
43503
|
+
linkType: row.linkType,
|
|
43504
|
+
syncDirection: row.syncDirection,
|
|
43505
|
+
metadata: row.metadataJson ? JSON.parse(row.metadataJson) : void 0,
|
|
43506
|
+
linkedAt: row.linkedAt,
|
|
43507
|
+
lastSyncAt: row.lastSyncAt
|
|
43508
|
+
};
|
|
43509
|
+
}
|
|
43510
|
+
var init_link_store = __esm({
|
|
43511
|
+
"packages/core/src/reconciliation/link-store.ts"() {
|
|
43512
|
+
"use strict";
|
|
43513
|
+
init_sqlite2();
|
|
43514
|
+
init_tasks_schema();
|
|
43515
|
+
}
|
|
43516
|
+
});
|
|
43517
|
+
|
|
43518
|
+
// packages/core/src/nexus/transfer.ts
|
|
43519
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
43520
|
+
async function previewTransfer(params) {
|
|
43521
|
+
return executeTransferInternal({ ...params, dryRun: true });
|
|
43522
|
+
}
|
|
43523
|
+
async function executeTransfer(params) {
|
|
43524
|
+
return executeTransferInternal(params);
|
|
43525
|
+
}
|
|
43526
|
+
async function executeTransferInternal(params) {
|
|
43527
|
+
const {
|
|
43528
|
+
taskIds,
|
|
43529
|
+
sourceProject: sourceProjectRef,
|
|
43530
|
+
targetProject: targetProjectRef,
|
|
43531
|
+
mode = "copy",
|
|
43532
|
+
scope = "subtree",
|
|
43533
|
+
onConflict = "rename",
|
|
43534
|
+
onMissingDep = "strip",
|
|
43535
|
+
provenance = true,
|
|
43536
|
+
targetParent,
|
|
43537
|
+
transferBrain = false,
|
|
43538
|
+
dryRun = false
|
|
43539
|
+
} = params;
|
|
43540
|
+
if (!taskIds.length) {
|
|
43541
|
+
throw new Error("No task IDs specified for transfer");
|
|
43542
|
+
}
|
|
43543
|
+
const sourceProject = await nexusGetProject(sourceProjectRef);
|
|
43544
|
+
if (!sourceProject) {
|
|
43545
|
+
throw new Error(`Source project not found: ${sourceProjectRef}`);
|
|
43546
|
+
}
|
|
43547
|
+
const targetProject = await nexusGetProject(targetProjectRef);
|
|
43548
|
+
if (!targetProject) {
|
|
43549
|
+
throw new Error(`Target project not found: ${targetProjectRef}`);
|
|
43550
|
+
}
|
|
43551
|
+
if (sourceProject.hash === targetProject.hash) {
|
|
43552
|
+
throw new Error("Source and target projects must be different");
|
|
43553
|
+
}
|
|
43554
|
+
await requirePermission(sourceProject.hash, "read", "nexus.transfer");
|
|
43555
|
+
await requirePermission(targetProject.hash, "write", "nexus.transfer");
|
|
43556
|
+
const sourceAccessor = await getAccessor(sourceProject.path);
|
|
43557
|
+
const { tasks: allSourceTasks } = await sourceAccessor.queryTasks({});
|
|
43558
|
+
const exportPackages = [];
|
|
43559
|
+
for (const taskId of taskIds) {
|
|
43560
|
+
const pkg = scope === "subtree" ? exportSubtree(taskId, allSourceTasks, sourceProject.name) : exportSingle(taskId, allSourceTasks, sourceProject.name);
|
|
43561
|
+
if (!pkg) {
|
|
43562
|
+
throw new Error(`Task not found in source project: ${taskId}`);
|
|
43563
|
+
}
|
|
43564
|
+
exportPackages.push(pkg);
|
|
43565
|
+
}
|
|
43566
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
43567
|
+
const mergedTasks = [];
|
|
43568
|
+
for (const pkg of exportPackages) {
|
|
43569
|
+
for (const task of pkg.tasks) {
|
|
43570
|
+
if (!seenIds.has(task.id)) {
|
|
43571
|
+
seenIds.add(task.id);
|
|
43572
|
+
mergedTasks.push(task);
|
|
43573
|
+
}
|
|
43574
|
+
}
|
|
43575
|
+
}
|
|
43576
|
+
const mergedPkg = { ...exportPackages[0] };
|
|
43577
|
+
mergedPkg.tasks = mergedTasks;
|
|
43578
|
+
mergedPkg._meta = { ...mergedPkg._meta, taskCount: mergedTasks.length };
|
|
43579
|
+
const importResult = await importFromPackage(mergedPkg, {
|
|
43580
|
+
cwd: targetProject.path,
|
|
43581
|
+
dryRun,
|
|
43582
|
+
parent: targetParent,
|
|
43583
|
+
provenance,
|
|
43584
|
+
onConflict,
|
|
43585
|
+
onMissingDep
|
|
43586
|
+
});
|
|
43587
|
+
const entries = mergedTasks.map((t) => ({
|
|
43588
|
+
sourceId: t.id,
|
|
43589
|
+
targetId: importResult.idRemap[t.id] ?? t.id,
|
|
43590
|
+
title: t.title,
|
|
43591
|
+
type: t.type ?? "task"
|
|
43592
|
+
}));
|
|
43593
|
+
const manifest = {
|
|
43594
|
+
sourceProject: sourceProject.name,
|
|
43595
|
+
targetProject: targetProject.name,
|
|
43596
|
+
mode,
|
|
43597
|
+
scope,
|
|
43598
|
+
entries,
|
|
43599
|
+
idRemap: importResult.idRemap,
|
|
43600
|
+
brainObservationsTransferred: 0
|
|
43601
|
+
};
|
|
43602
|
+
const result = {
|
|
43603
|
+
dryRun,
|
|
43604
|
+
transferred: importResult.imported,
|
|
43605
|
+
skipped: importResult.skipped,
|
|
43606
|
+
archived: 0,
|
|
43607
|
+
linksCreated: 0,
|
|
43608
|
+
brainObservationsTransferred: 0,
|
|
43609
|
+
manifest
|
|
43610
|
+
};
|
|
43611
|
+
if (dryRun) {
|
|
43612
|
+
return result;
|
|
43613
|
+
}
|
|
43614
|
+
let linksCreated = 0;
|
|
43615
|
+
const targetAccessor = await getAccessor(targetProject.path);
|
|
43616
|
+
const { tasks: targetTasks } = await targetAccessor.queryTasks({});
|
|
43617
|
+
const targetTaskIds = new Set(targetTasks.map((t) => t.id));
|
|
43618
|
+
for (const entry of entries) {
|
|
43619
|
+
if (importResult.idRemap[entry.sourceId] && targetTaskIds.has(entry.targetId)) {
|
|
43620
|
+
await createLink(
|
|
43621
|
+
{
|
|
43622
|
+
taskId: entry.targetId,
|
|
43623
|
+
providerId: `nexus:${sourceProject.name}`,
|
|
43624
|
+
externalId: entry.sourceId,
|
|
43625
|
+
externalTitle: entry.title,
|
|
43626
|
+
linkType: "transferred",
|
|
43627
|
+
syncDirection: "inbound",
|
|
43628
|
+
metadata: {
|
|
43629
|
+
transferMode: mode,
|
|
43630
|
+
transferScope: scope,
|
|
43631
|
+
sourceProject: sourceProject.name,
|
|
43632
|
+
transferredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
43633
|
+
}
|
|
43634
|
+
},
|
|
43635
|
+
targetProject.path
|
|
43636
|
+
);
|
|
43637
|
+
linksCreated++;
|
|
43638
|
+
await createLink(
|
|
43639
|
+
{
|
|
43640
|
+
taskId: entry.sourceId,
|
|
43641
|
+
providerId: `nexus:${targetProject.name}`,
|
|
43642
|
+
externalId: entry.targetId,
|
|
43643
|
+
externalTitle: entry.title,
|
|
43644
|
+
linkType: "transferred",
|
|
43645
|
+
syncDirection: "outbound",
|
|
43646
|
+
metadata: {
|
|
43647
|
+
transferMode: mode,
|
|
43648
|
+
transferScope: scope,
|
|
43649
|
+
targetProject: targetProject.name,
|
|
43650
|
+
transferredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
43651
|
+
}
|
|
43652
|
+
},
|
|
43653
|
+
sourceProject.path
|
|
43654
|
+
);
|
|
43655
|
+
linksCreated++;
|
|
43656
|
+
}
|
|
43657
|
+
}
|
|
43658
|
+
result.linksCreated = linksCreated;
|
|
43659
|
+
try {
|
|
43660
|
+
const { getNexusDb: getNexusDb2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
|
|
43661
|
+
const { nexusAuditLog: nexusAuditLog2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
|
|
43662
|
+
const db = await getNexusDb2();
|
|
43663
|
+
await db.insert(nexusAuditLog2).values({
|
|
43664
|
+
id: randomUUID5(),
|
|
43665
|
+
action: "transfer",
|
|
43666
|
+
projectHash: sourceProject.hash,
|
|
43667
|
+
projectId: sourceProject.projectId,
|
|
43668
|
+
domain: "nexus",
|
|
43669
|
+
operation: "transfer",
|
|
43670
|
+
success: 1,
|
|
43671
|
+
detailsJson: JSON.stringify({
|
|
43672
|
+
sourceProject: sourceProject.name,
|
|
43673
|
+
targetProject: targetProject.name,
|
|
43674
|
+
mode,
|
|
43675
|
+
scope,
|
|
43676
|
+
taskCount: result.transferred,
|
|
43677
|
+
idRemap: importResult.idRemap
|
|
43678
|
+
})
|
|
43679
|
+
});
|
|
43680
|
+
} catch (err) {
|
|
43681
|
+
log6.warn({ err }, "nexus transfer audit write failed");
|
|
43682
|
+
}
|
|
43683
|
+
if (mode === "move") {
|
|
43684
|
+
let archived = 0;
|
|
43685
|
+
for (const entry of entries) {
|
|
43686
|
+
if (importResult.idRemap[entry.sourceId]) {
|
|
43687
|
+
try {
|
|
43688
|
+
await sourceAccessor.archiveSingleTask(entry.sourceId, {
|
|
43689
|
+
archivedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43690
|
+
archiveReason: `Transferred to ${targetProject.name} as ${entry.targetId}`
|
|
43691
|
+
});
|
|
43692
|
+
archived++;
|
|
43693
|
+
} catch (err) {
|
|
43694
|
+
log6.warn({ err, taskId: entry.sourceId }, "failed to archive source task after transfer");
|
|
43695
|
+
}
|
|
43696
|
+
}
|
|
43697
|
+
}
|
|
43698
|
+
result.archived = archived;
|
|
43699
|
+
}
|
|
43700
|
+
if (transferBrain) {
|
|
43701
|
+
let brainTransferred = 0;
|
|
43702
|
+
try {
|
|
43703
|
+
const sourceBrainDb = await getBrainDb(sourceProject.path);
|
|
43704
|
+
const targetBrainDb = await getBrainDb(targetProject.path);
|
|
43705
|
+
const sourceBrain = new BrainDataAccessor(sourceBrainDb);
|
|
43706
|
+
const targetBrain = new BrainDataAccessor(targetBrainDb);
|
|
43707
|
+
for (const entry of entries) {
|
|
43708
|
+
if (!importResult.idRemap[entry.sourceId]) continue;
|
|
43709
|
+
const links = await sourceBrain.getLinksForTask(entry.sourceId);
|
|
43710
|
+
for (const link of links) {
|
|
43711
|
+
if (link.memoryType !== "observation") continue;
|
|
43712
|
+
const observation = await sourceBrain.getObservation(link.memoryId);
|
|
43713
|
+
if (!observation) continue;
|
|
43714
|
+
const newObsId = `O-${randomUUID5().slice(0, 8)}`;
|
|
43715
|
+
await targetBrain.addObservation({
|
|
43716
|
+
...observation,
|
|
43717
|
+
id: newObsId,
|
|
43718
|
+
createdAt: observation.createdAt,
|
|
43719
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
|
|
43720
|
+
});
|
|
43721
|
+
await targetBrain.addLink({
|
|
43722
|
+
memoryType: "observation",
|
|
43723
|
+
memoryId: newObsId,
|
|
43724
|
+
taskId: entry.targetId,
|
|
43725
|
+
linkType: "applies_to",
|
|
43726
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
|
|
43727
|
+
});
|
|
43728
|
+
brainTransferred++;
|
|
43729
|
+
}
|
|
43730
|
+
}
|
|
43731
|
+
} catch (err) {
|
|
43732
|
+
log6.warn({ err }, "brain observation transfer failed");
|
|
43733
|
+
}
|
|
43734
|
+
result.brainObservationsTransferred = brainTransferred;
|
|
43735
|
+
result.manifest.brainObservationsTransferred = brainTransferred;
|
|
43736
|
+
}
|
|
43737
|
+
return result;
|
|
43738
|
+
}
|
|
43739
|
+
var log6;
|
|
43740
|
+
var init_transfer = __esm({
|
|
43741
|
+
"packages/core/src/nexus/transfer.ts"() {
|
|
43742
|
+
"use strict";
|
|
43743
|
+
init_import_tasks();
|
|
43744
|
+
init_logger();
|
|
43745
|
+
init_link_store();
|
|
43746
|
+
init_brain_accessor();
|
|
43747
|
+
init_brain_sqlite();
|
|
43748
|
+
init_data_accessor();
|
|
43749
|
+
init_export2();
|
|
43750
|
+
init_permissions();
|
|
43751
|
+
init_registry3();
|
|
43752
|
+
log6 = getLogger("nexus:transfer");
|
|
43753
|
+
}
|
|
43754
|
+
});
|
|
43755
|
+
|
|
43373
43756
|
// packages/core/src/nexus/index.ts
|
|
43374
43757
|
var nexus_exports = {};
|
|
43375
43758
|
__export(nexus_exports, {
|
|
@@ -43382,6 +43765,7 @@ __export(nexus_exports, {
|
|
|
43382
43765
|
checkPermissionDetail: () => checkPermissionDetail,
|
|
43383
43766
|
criticalPath: () => criticalPath,
|
|
43384
43767
|
discoverRelated: () => discoverRelated,
|
|
43768
|
+
executeTransfer: () => executeTransfer,
|
|
43385
43769
|
extractKeywords: () => extractKeywords2,
|
|
43386
43770
|
generateProjectHash: () => generateProjectHash,
|
|
43387
43771
|
getCurrentProject: () => getCurrentProject,
|
|
@@ -43405,6 +43789,7 @@ __export(nexus_exports, {
|
|
|
43405
43789
|
orphanDetection: () => orphanDetection,
|
|
43406
43790
|
parseQuery: () => parseQuery,
|
|
43407
43791
|
permissionLevel: () => permissionLevel,
|
|
43792
|
+
previewTransfer: () => previewTransfer,
|
|
43408
43793
|
readRegistry: () => readRegistry,
|
|
43409
43794
|
readRegistryRequired: () => readRegistryRequired,
|
|
43410
43795
|
requirePermission: () => requirePermission,
|
|
@@ -43427,6 +43812,7 @@ var init_nexus = __esm({
|
|
|
43427
43812
|
init_query3();
|
|
43428
43813
|
init_registry3();
|
|
43429
43814
|
init_sharing();
|
|
43815
|
+
init_transfer();
|
|
43430
43816
|
}
|
|
43431
43817
|
});
|
|
43432
43818
|
|
|
@@ -44927,100 +45313,6 @@ var init_pipeline = __esm({
|
|
|
44927
45313
|
}
|
|
44928
45314
|
});
|
|
44929
45315
|
|
|
44930
|
-
// packages/core/src/reconciliation/link-store.ts
|
|
44931
|
-
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
44932
|
-
import { and as and5, eq as eq8 } from "drizzle-orm";
|
|
44933
|
-
async function getLinksByProvider(providerId, cwd) {
|
|
44934
|
-
const db = await getDb(cwd);
|
|
44935
|
-
const rows = await db.select().from(externalTaskLinks).where(eq8(externalTaskLinks.providerId, providerId));
|
|
44936
|
-
return rows.map(rowToLink);
|
|
44937
|
-
}
|
|
44938
|
-
async function getLinkByExternalId(providerId, externalId, cwd) {
|
|
44939
|
-
const db = await getDb(cwd);
|
|
44940
|
-
const rows = await db.select().from(externalTaskLinks).where(
|
|
44941
|
-
and5(
|
|
44942
|
-
eq8(externalTaskLinks.providerId, providerId),
|
|
44943
|
-
eq8(externalTaskLinks.externalId, externalId)
|
|
44944
|
-
)
|
|
44945
|
-
);
|
|
44946
|
-
return rows.length > 0 ? rowToLink(rows[0]) : null;
|
|
44947
|
-
}
|
|
44948
|
-
async function getLinksByTaskId(taskId, cwd) {
|
|
44949
|
-
const db = await getDb(cwd);
|
|
44950
|
-
const rows = await db.select().from(externalTaskLinks).where(eq8(externalTaskLinks.taskId, taskId));
|
|
44951
|
-
return rows.map(rowToLink);
|
|
44952
|
-
}
|
|
44953
|
-
async function createLink(params, cwd) {
|
|
44954
|
-
const db = await getDb(cwd);
|
|
44955
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
44956
|
-
const id = randomUUID4();
|
|
44957
|
-
await db.insert(externalTaskLinks).values({
|
|
44958
|
-
id,
|
|
44959
|
-
taskId: params.taskId,
|
|
44960
|
-
providerId: params.providerId,
|
|
44961
|
-
externalId: params.externalId,
|
|
44962
|
-
externalUrl: params.externalUrl ?? null,
|
|
44963
|
-
externalTitle: params.externalTitle ?? null,
|
|
44964
|
-
linkType: params.linkType,
|
|
44965
|
-
syncDirection: params.syncDirection ?? "inbound",
|
|
44966
|
-
metadataJson: params.metadata ? JSON.stringify(params.metadata) : "{}",
|
|
44967
|
-
linkedAt: now2,
|
|
44968
|
-
lastSyncAt: now2
|
|
44969
|
-
});
|
|
44970
|
-
return {
|
|
44971
|
-
id,
|
|
44972
|
-
taskId: params.taskId,
|
|
44973
|
-
providerId: params.providerId,
|
|
44974
|
-
externalId: params.externalId,
|
|
44975
|
-
externalUrl: params.externalUrl ?? null,
|
|
44976
|
-
externalTitle: params.externalTitle ?? null,
|
|
44977
|
-
linkType: params.linkType,
|
|
44978
|
-
syncDirection: params.syncDirection ?? "inbound",
|
|
44979
|
-
metadata: params.metadata,
|
|
44980
|
-
linkedAt: now2,
|
|
44981
|
-
lastSyncAt: now2
|
|
44982
|
-
};
|
|
44983
|
-
}
|
|
44984
|
-
async function touchLink(linkId, updates, cwd) {
|
|
44985
|
-
const db = await getDb(cwd);
|
|
44986
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
44987
|
-
const values = { lastSyncAt: now2 };
|
|
44988
|
-
if (updates?.externalTitle !== void 0) {
|
|
44989
|
-
values.externalTitle = updates.externalTitle;
|
|
44990
|
-
}
|
|
44991
|
-
if (updates?.metadata !== void 0) {
|
|
44992
|
-
values.metadataJson = JSON.stringify(updates.metadata);
|
|
44993
|
-
}
|
|
44994
|
-
await db.update(externalTaskLinks).set(values).where(eq8(externalTaskLinks.id, linkId));
|
|
44995
|
-
}
|
|
44996
|
-
async function removeLinksByProvider(providerId, cwd) {
|
|
44997
|
-
const db = await getDb(cwd);
|
|
44998
|
-
const result = await db.delete(externalTaskLinks).where(eq8(externalTaskLinks.providerId, providerId));
|
|
44999
|
-
return Number(result.changes);
|
|
45000
|
-
}
|
|
45001
|
-
function rowToLink(row) {
|
|
45002
|
-
return {
|
|
45003
|
-
id: row.id,
|
|
45004
|
-
taskId: row.taskId,
|
|
45005
|
-
providerId: row.providerId,
|
|
45006
|
-
externalId: row.externalId,
|
|
45007
|
-
externalUrl: row.externalUrl,
|
|
45008
|
-
externalTitle: row.externalTitle,
|
|
45009
|
-
linkType: row.linkType,
|
|
45010
|
-
syncDirection: row.syncDirection,
|
|
45011
|
-
metadata: row.metadataJson ? JSON.parse(row.metadataJson) : void 0,
|
|
45012
|
-
linkedAt: row.linkedAt,
|
|
45013
|
-
lastSyncAt: row.lastSyncAt
|
|
45014
|
-
};
|
|
45015
|
-
}
|
|
45016
|
-
var init_link_store = __esm({
|
|
45017
|
-
"packages/core/src/reconciliation/link-store.ts"() {
|
|
45018
|
-
"use strict";
|
|
45019
|
-
init_sqlite2();
|
|
45020
|
-
init_tasks_schema();
|
|
45021
|
-
}
|
|
45022
|
-
});
|
|
45023
|
-
|
|
45024
45316
|
// packages/core/src/memory/auto-extract.ts
|
|
45025
45317
|
var auto_extract_exports = {};
|
|
45026
45318
|
__export(auto_extract_exports, {
|
|
@@ -55464,7 +55756,7 @@ import { createGzip } from "node:zlib";
|
|
|
55464
55756
|
async function pruneAuditLog(cleoDir, config2) {
|
|
55465
55757
|
try {
|
|
55466
55758
|
if (!config2.auditRetentionDays || config2.auditRetentionDays <= 0) {
|
|
55467
|
-
|
|
55759
|
+
log7.debug("auditRetentionDays is 0 or unset; skipping audit prune");
|
|
55468
55760
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
55469
55761
|
}
|
|
55470
55762
|
const cutoff = new Date(Date.now() - config2.auditRetentionDays * 864e5).toISOString();
|
|
@@ -55475,7 +55767,7 @@ async function pruneAuditLog(cleoDir, config2) {
|
|
|
55475
55767
|
const db = await getDb4(projectRoot);
|
|
55476
55768
|
const oldRows = await db.select().from(auditLog2).where(lt3(auditLog2.timestamp, cutoff));
|
|
55477
55769
|
if (oldRows.length === 0) {
|
|
55478
|
-
|
|
55770
|
+
log7.debug("No audit_log rows older than cutoff; nothing to prune");
|
|
55479
55771
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
55480
55772
|
}
|
|
55481
55773
|
let archivePath;
|
|
@@ -55493,17 +55785,17 @@ async function pruneAuditLog(cleoDir, config2) {
|
|
|
55493
55785
|
const inStream = Readable.from([jsonlContent]);
|
|
55494
55786
|
await pipeline(inStream, gzip, outStream);
|
|
55495
55787
|
rowsArchived = oldRows.length;
|
|
55496
|
-
|
|
55788
|
+
log7.info(
|
|
55497
55789
|
{ archivePath, rowsArchived },
|
|
55498
55790
|
`Archived ${rowsArchived} audit rows to ${archivePath}`
|
|
55499
55791
|
);
|
|
55500
55792
|
} catch (archiveErr) {
|
|
55501
|
-
|
|
55793
|
+
log7.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
|
|
55502
55794
|
archivePath = void 0;
|
|
55503
55795
|
}
|
|
55504
55796
|
}
|
|
55505
55797
|
await db.delete(auditLog2).where(lt3(auditLog2.timestamp, cutoff)).run();
|
|
55506
|
-
|
|
55798
|
+
log7.info(
|
|
55507
55799
|
{ rowsDeleted: oldRows.length, cutoff },
|
|
55508
55800
|
`Pruned ${oldRows.length} audit_log rows older than ${cutoff}`
|
|
55509
55801
|
);
|
|
@@ -55513,16 +55805,16 @@ async function pruneAuditLog(cleoDir, config2) {
|
|
|
55513
55805
|
archivePath
|
|
55514
55806
|
};
|
|
55515
55807
|
} catch (err) {
|
|
55516
|
-
|
|
55808
|
+
log7.warn({ err }, "audit log pruning failed");
|
|
55517
55809
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
55518
55810
|
}
|
|
55519
55811
|
}
|
|
55520
|
-
var
|
|
55812
|
+
var log7;
|
|
55521
55813
|
var init_audit_prune = __esm({
|
|
55522
55814
|
"packages/core/src/audit-prune.ts"() {
|
|
55523
55815
|
"use strict";
|
|
55524
55816
|
init_logger();
|
|
55525
|
-
|
|
55817
|
+
log7 = getLogger("prune");
|
|
55526
55818
|
}
|
|
55527
55819
|
});
|
|
55528
55820
|
|
|
@@ -63265,7 +63557,7 @@ var init_context_alert = __esm({
|
|
|
63265
63557
|
});
|
|
63266
63558
|
|
|
63267
63559
|
// packages/core/src/output.ts
|
|
63268
|
-
import { randomUUID as
|
|
63560
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
63269
63561
|
function pushWarning(warning) {
|
|
63270
63562
|
pendingWarnings.push(warning);
|
|
63271
63563
|
}
|
|
@@ -63282,7 +63574,7 @@ function createCliMeta(operation, mvi = "standard") {
|
|
|
63282
63574
|
schemaVersion: "2026.2.1",
|
|
63283
63575
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
63284
63576
|
operation,
|
|
63285
|
-
requestId:
|
|
63577
|
+
requestId: randomUUID6(),
|
|
63286
63578
|
transport: "cli",
|
|
63287
63579
|
strict: true,
|
|
63288
63580
|
mvi,
|
|
@@ -63880,6 +64172,7 @@ __export(src_exports, {
|
|
|
63880
64172
|
});
|
|
63881
64173
|
var init_src2 = __esm({
|
|
63882
64174
|
"packages/core/src/index.ts"() {
|
|
64175
|
+
"use strict";
|
|
63883
64176
|
init_src();
|
|
63884
64177
|
init_adapters();
|
|
63885
64178
|
init_admin();
|
|
@@ -65298,7 +65591,7 @@ var init_chain_validation = __esm({
|
|
|
65298
65591
|
});
|
|
65299
65592
|
|
|
65300
65593
|
// packages/core/src/lifecycle/chain-store.ts
|
|
65301
|
-
import { randomUUID as
|
|
65594
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
65302
65595
|
async function addChain(chain, projectRoot) {
|
|
65303
65596
|
const validation = validateChain(chain);
|
|
65304
65597
|
if (validation.errors.length > 0) {
|
|
@@ -65337,7 +65630,7 @@ async function createInstance(params, projectRoot) {
|
|
|
65337
65630
|
if (!chain) {
|
|
65338
65631
|
throw new Error(`Chain "${params.chainId}" not found`);
|
|
65339
65632
|
}
|
|
65340
|
-
const id = `wci-${
|
|
65633
|
+
const id = `wci-${randomUUID7().slice(0, 8)}`;
|
|
65341
65634
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
65342
65635
|
const variables = params.variables ?? {};
|
|
65343
65636
|
const stageToTask = params.stageToTask ?? {};
|
|
@@ -67642,7 +67935,7 @@ var init_model_provider_registry = __esm({
|
|
|
67642
67935
|
});
|
|
67643
67936
|
|
|
67644
67937
|
// packages/core/src/metrics/token-service.ts
|
|
67645
|
-
import { createHash as createHash13, randomUUID as
|
|
67938
|
+
import { createHash as createHash13, randomUUID as randomUUID8 } from "node:crypto";
|
|
67646
67939
|
import { existsSync as existsSync106, readdirSync as readdirSync34, readFileSync as readFileSync78 } from "node:fs";
|
|
67647
67940
|
import { join as join105 } from "node:path";
|
|
67648
67941
|
function normalizeProvider(provider, model, runtimeProvider) {
|
|
@@ -67895,7 +68188,7 @@ async function recordTokenExchange(input) {
|
|
|
67895
68188
|
const measurement = await measureTokenExchange(input);
|
|
67896
68189
|
const db = await getDb4(input.cwd);
|
|
67897
68190
|
const row = {
|
|
67898
|
-
id:
|
|
68191
|
+
id: randomUUID8(),
|
|
67899
68192
|
provider: measurement.provider,
|
|
67900
68193
|
model: measurement.model,
|
|
67901
68194
|
transport: input.transport ?? "unknown",
|
|
@@ -68588,7 +68881,7 @@ async function validateAndRepairSequence(cwd, config2 = {}) {
|
|
|
68588
68881
|
}
|
|
68589
68882
|
const repair = await repairSequence(cwd);
|
|
68590
68883
|
if (repair.repaired) {
|
|
68591
|
-
|
|
68884
|
+
log8.warn(
|
|
68592
68885
|
{ oldCounter: repair.oldCounter, newCounter: repair.newCounter },
|
|
68593
68886
|
"Sequence repaired"
|
|
68594
68887
|
);
|
|
@@ -68617,7 +68910,7 @@ async function triggerCheckpoint(context, cwd, config2 = {}) {
|
|
|
68617
68910
|
try {
|
|
68618
68911
|
await gitCheckpoint("auto", context, cwd);
|
|
68619
68912
|
} catch (err) {
|
|
68620
|
-
|
|
68913
|
+
log8.warn({ err }, "Checkpoint failed (non-fatal)");
|
|
68621
68914
|
}
|
|
68622
68915
|
vacuumIntoBackup({ cwd }).catch(() => {
|
|
68623
68916
|
});
|
|
@@ -68655,16 +68948,16 @@ async function safeDeleteTask(deleteFn, taskId, cwd, config2 = {}) {
|
|
|
68655
68948
|
return result;
|
|
68656
68949
|
}
|
|
68657
68950
|
async function forceCheckpointBeforeOperation(operation, cwd) {
|
|
68658
|
-
|
|
68951
|
+
log8.info({ operation }, "Forcing checkpoint before operation");
|
|
68659
68952
|
try {
|
|
68660
68953
|
await gitCheckpoint("manual", `pre-${operation}`, cwd);
|
|
68661
68954
|
} catch (err) {
|
|
68662
|
-
|
|
68955
|
+
log8.error({ err }, "Failed to create pre-operation checkpoint");
|
|
68663
68956
|
}
|
|
68664
68957
|
vacuumIntoBackup({ cwd, force: true }).catch(() => {
|
|
68665
68958
|
});
|
|
68666
68959
|
}
|
|
68667
|
-
var
|
|
68960
|
+
var log8, DEFAULT_CONFIG2, SafetyError;
|
|
68668
68961
|
var init_data_safety = __esm({
|
|
68669
68962
|
"packages/core/src/store/data-safety.ts"() {
|
|
68670
68963
|
"use strict";
|
|
@@ -68674,7 +68967,7 @@ var init_data_safety = __esm({
|
|
|
68674
68967
|
init_sqlite2();
|
|
68675
68968
|
init_sqlite_backup();
|
|
68676
68969
|
init_tasks_schema();
|
|
68677
|
-
|
|
68970
|
+
log8 = getLogger("data-safety");
|
|
68678
68971
|
DEFAULT_CONFIG2 = {
|
|
68679
68972
|
verifyWrites: true,
|
|
68680
68973
|
detectCollisions: true,
|
|
@@ -74533,6 +74826,7 @@ __export(internal_exports, {
|
|
|
74533
74826
|
ensureProjectContext: () => ensureProjectContext,
|
|
74534
74827
|
ensureSqliteDb: () => ensureSqliteDb,
|
|
74535
74828
|
estimateContext: () => estimateContext,
|
|
74829
|
+
executeTransfer: () => executeTransfer,
|
|
74536
74830
|
exportSnapshot: () => exportSnapshot,
|
|
74537
74831
|
exportTasks: () => exportTasks,
|
|
74538
74832
|
exportTasksPackage: () => exportTasksPackage,
|
|
@@ -74659,6 +74953,7 @@ __export(internal_exports, {
|
|
|
74659
74953
|
gradeSession: () => gradeSession,
|
|
74660
74954
|
heartbeat: () => heartbeat,
|
|
74661
74955
|
hooks: () => hooks,
|
|
74956
|
+
importFromPackage: () => importFromPackage,
|
|
74662
74957
|
importSnapshot: () => importSnapshot,
|
|
74663
74958
|
importTasks: () => importTasks,
|
|
74664
74959
|
importTasksPackage: () => importTasksPackage,
|
|
@@ -74802,6 +75097,7 @@ __export(internal_exports, {
|
|
|
74802
75097
|
predictValidationOutcome: () => predictValidationOutcome,
|
|
74803
75098
|
prepareRelease: () => prepareRelease,
|
|
74804
75099
|
prepareSpawn: () => prepareSpawn,
|
|
75100
|
+
previewTransfer: () => previewTransfer,
|
|
74805
75101
|
protocolEnforcer: () => protocolEnforcer,
|
|
74806
75102
|
pruneAuditLog: () => pruneAuditLog,
|
|
74807
75103
|
pull: () => pull,
|
|
@@ -75092,6 +75388,7 @@ var init_internal = __esm({
|
|
|
75092
75388
|
init_session_memory();
|
|
75093
75389
|
init_discover();
|
|
75094
75390
|
init_registry3();
|
|
75391
|
+
init_transfer();
|
|
75095
75392
|
init_analyze();
|
|
75096
75393
|
init_critical_path();
|
|
75097
75394
|
init_orchestration();
|
|
@@ -76841,10 +77138,10 @@ function camelToKebab(str) {
|
|
|
76841
77138
|
// packages/cleo/src/dispatch/adapters/cli.ts
|
|
76842
77139
|
init_internal();
|
|
76843
77140
|
init_renderers();
|
|
76844
|
-
import { randomUUID as
|
|
77141
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
76845
77142
|
|
|
76846
77143
|
// packages/cleo/src/dispatch/lib/meta.ts
|
|
76847
|
-
import { randomUUID as
|
|
77144
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
76848
77145
|
function createDispatchMeta(gateway, domain2, operation, startTime, source = "mcp", requestId, sessionId) {
|
|
76849
77146
|
return {
|
|
76850
77147
|
gateway,
|
|
@@ -76853,7 +77150,7 @@ function createDispatchMeta(gateway, domain2, operation, startTime, source = "mc
|
|
|
76853
77150
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
76854
77151
|
duration_ms: Date.now() - startTime,
|
|
76855
77152
|
source,
|
|
76856
|
-
requestId: requestId ??
|
|
77153
|
+
requestId: requestId ?? randomUUID9(),
|
|
76857
77154
|
...sessionId != null && { sessionId }
|
|
76858
77155
|
};
|
|
76859
77156
|
}
|
|
@@ -79409,6 +79706,95 @@ var OPERATIONS = [
|
|
|
79409
79706
|
requiredParams: []
|
|
79410
79707
|
},
|
|
79411
79708
|
// ---------------------------------------------------------------------------
|
|
79709
|
+
// nexus.transfer — Cross-project task transfer (T046)
|
|
79710
|
+
// ---------------------------------------------------------------------------
|
|
79711
|
+
{
|
|
79712
|
+
gateway: "query",
|
|
79713
|
+
domain: "nexus",
|
|
79714
|
+
operation: "transfer.preview",
|
|
79715
|
+
description: "nexus.transfer.preview (query) \u2014 preview a cross-project task transfer",
|
|
79716
|
+
tier: 2,
|
|
79717
|
+
idempotent: true,
|
|
79718
|
+
sessionRequired: false,
|
|
79719
|
+
requiredParams: ["taskIds", "sourceProject", "targetProject"],
|
|
79720
|
+
params: [
|
|
79721
|
+
{ name: "taskIds", type: "array", required: true, description: "Task IDs to transfer" },
|
|
79722
|
+
{
|
|
79723
|
+
name: "sourceProject",
|
|
79724
|
+
type: "string",
|
|
79725
|
+
required: true,
|
|
79726
|
+
description: "Source project name or hash"
|
|
79727
|
+
},
|
|
79728
|
+
{
|
|
79729
|
+
name: "targetProject",
|
|
79730
|
+
type: "string",
|
|
79731
|
+
required: true,
|
|
79732
|
+
description: "Target project name or hash"
|
|
79733
|
+
},
|
|
79734
|
+
{
|
|
79735
|
+
name: "mode",
|
|
79736
|
+
type: "string",
|
|
79737
|
+
required: false,
|
|
79738
|
+
description: "Transfer mode: 'copy' (default) or 'move'"
|
|
79739
|
+
},
|
|
79740
|
+
{
|
|
79741
|
+
name: "scope",
|
|
79742
|
+
type: "string",
|
|
79743
|
+
required: false,
|
|
79744
|
+
description: "Transfer scope: 'subtree' (default) or 'single'"
|
|
79745
|
+
}
|
|
79746
|
+
]
|
|
79747
|
+
},
|
|
79748
|
+
{
|
|
79749
|
+
gateway: "mutate",
|
|
79750
|
+
domain: "nexus",
|
|
79751
|
+
operation: "transfer",
|
|
79752
|
+
description: "nexus.transfer (mutate) \u2014 transfer tasks between NEXUS projects",
|
|
79753
|
+
tier: 2,
|
|
79754
|
+
idempotent: false,
|
|
79755
|
+
sessionRequired: false,
|
|
79756
|
+
requiredParams: ["taskIds", "sourceProject", "targetProject"],
|
|
79757
|
+
params: [
|
|
79758
|
+
{ name: "taskIds", type: "array", required: true, description: "Task IDs to transfer" },
|
|
79759
|
+
{
|
|
79760
|
+
name: "sourceProject",
|
|
79761
|
+
type: "string",
|
|
79762
|
+
required: true,
|
|
79763
|
+
description: "Source project name or hash"
|
|
79764
|
+
},
|
|
79765
|
+
{
|
|
79766
|
+
name: "targetProject",
|
|
79767
|
+
type: "string",
|
|
79768
|
+
required: true,
|
|
79769
|
+
description: "Target project name or hash"
|
|
79770
|
+
},
|
|
79771
|
+
{
|
|
79772
|
+
name: "mode",
|
|
79773
|
+
type: "string",
|
|
79774
|
+
required: false,
|
|
79775
|
+
description: "Transfer mode: 'copy' (default) or 'move'"
|
|
79776
|
+
},
|
|
79777
|
+
{
|
|
79778
|
+
name: "scope",
|
|
79779
|
+
type: "string",
|
|
79780
|
+
required: false,
|
|
79781
|
+
description: "Transfer scope: 'subtree' (default) or 'single'"
|
|
79782
|
+
},
|
|
79783
|
+
{
|
|
79784
|
+
name: "onConflict",
|
|
79785
|
+
type: "string",
|
|
79786
|
+
required: false,
|
|
79787
|
+
description: "Conflict strategy: 'rename' (default), 'skip', 'duplicate', 'fail'"
|
|
79788
|
+
},
|
|
79789
|
+
{
|
|
79790
|
+
name: "transferBrain",
|
|
79791
|
+
type: "boolean",
|
|
79792
|
+
required: false,
|
|
79793
|
+
description: "Whether to transfer brain observations (default: false)"
|
|
79794
|
+
}
|
|
79795
|
+
]
|
|
79796
|
+
},
|
|
79797
|
+
// ---------------------------------------------------------------------------
|
|
79412
79798
|
// sticky — Ephemeral notes for quick capture (T5282)
|
|
79413
79799
|
// ---------------------------------------------------------------------------
|
|
79414
79800
|
// Query operations
|
|
@@ -84952,6 +85338,22 @@ async function nexusShareSnapshotImport(projectRoot, inputPath) {
|
|
|
84952
85338
|
return engineError("E_INTERNAL", error40 instanceof Error ? error40.message : String(error40));
|
|
84953
85339
|
}
|
|
84954
85340
|
}
|
|
85341
|
+
async function nexusTransferPreview(params) {
|
|
85342
|
+
try {
|
|
85343
|
+
const result = await previewTransfer(params);
|
|
85344
|
+
return engineSuccess(result);
|
|
85345
|
+
} catch (error40) {
|
|
85346
|
+
return engineError("E_INTERNAL", error40 instanceof Error ? error40.message : String(error40));
|
|
85347
|
+
}
|
|
85348
|
+
}
|
|
85349
|
+
async function nexusTransferExecute(params) {
|
|
85350
|
+
try {
|
|
85351
|
+
const result = await executeTransfer(params);
|
|
85352
|
+
return engineSuccess(result);
|
|
85353
|
+
} catch (error40) {
|
|
85354
|
+
return engineError("E_INTERNAL", error40 instanceof Error ? error40.message : String(error40));
|
|
85355
|
+
}
|
|
85356
|
+
}
|
|
84955
85357
|
|
|
84956
85358
|
// packages/cleo/src/dispatch/domains/nexus.ts
|
|
84957
85359
|
var NexusHandler = class {
|
|
@@ -85113,6 +85515,29 @@ var NexusHandler = class {
|
|
|
85113
85515
|
const result = await nexusShareStatus(this.projectRoot);
|
|
85114
85516
|
return wrapResult(result, "query", "nexus", "share.status", startTime);
|
|
85115
85517
|
}
|
|
85518
|
+
case "transfer.preview": {
|
|
85519
|
+
const taskIds = params?.taskIds;
|
|
85520
|
+
const sourceProject = params?.sourceProject;
|
|
85521
|
+
const targetProject = params?.targetProject;
|
|
85522
|
+
if (!taskIds?.length || !sourceProject || !targetProject) {
|
|
85523
|
+
return errorResult(
|
|
85524
|
+
"query",
|
|
85525
|
+
"nexus",
|
|
85526
|
+
operation,
|
|
85527
|
+
"E_INVALID_INPUT",
|
|
85528
|
+
"taskIds, sourceProject, and targetProject are required",
|
|
85529
|
+
startTime
|
|
85530
|
+
);
|
|
85531
|
+
}
|
|
85532
|
+
const result = await nexusTransferPreview({
|
|
85533
|
+
taskIds,
|
|
85534
|
+
sourceProject,
|
|
85535
|
+
targetProject,
|
|
85536
|
+
mode: params?.mode ?? "copy",
|
|
85537
|
+
scope: params?.scope ?? "subtree"
|
|
85538
|
+
});
|
|
85539
|
+
return wrapResult(result, "query", "nexus", operation, startTime);
|
|
85540
|
+
}
|
|
85116
85541
|
default:
|
|
85117
85542
|
return unsupportedOp("query", "nexus", operation, startTime);
|
|
85118
85543
|
}
|
|
@@ -85235,6 +85660,31 @@ var NexusHandler = class {
|
|
|
85235
85660
|
const result = await nexusShareSnapshotImport(this.projectRoot, inputPath);
|
|
85236
85661
|
return wrapResult(result, "mutate", "nexus", "share.snapshot.import", startTime);
|
|
85237
85662
|
}
|
|
85663
|
+
case "transfer": {
|
|
85664
|
+
const taskIds = params?.taskIds;
|
|
85665
|
+
const sourceProject = params?.sourceProject;
|
|
85666
|
+
const targetProject = params?.targetProject;
|
|
85667
|
+
if (!taskIds?.length || !sourceProject || !targetProject) {
|
|
85668
|
+
return errorResult(
|
|
85669
|
+
"mutate",
|
|
85670
|
+
"nexus",
|
|
85671
|
+
operation,
|
|
85672
|
+
"E_INVALID_INPUT",
|
|
85673
|
+
"taskIds, sourceProject, and targetProject are required",
|
|
85674
|
+
startTime
|
|
85675
|
+
);
|
|
85676
|
+
}
|
|
85677
|
+
const result = await nexusTransferExecute({
|
|
85678
|
+
taskIds,
|
|
85679
|
+
sourceProject,
|
|
85680
|
+
targetProject,
|
|
85681
|
+
mode: params?.mode ?? "copy",
|
|
85682
|
+
scope: params?.scope ?? "subtree",
|
|
85683
|
+
onConflict: params?.onConflict ?? "rename",
|
|
85684
|
+
transferBrain: params?.transferBrain ?? false
|
|
85685
|
+
});
|
|
85686
|
+
return wrapResult(result, "mutate", "nexus", operation, startTime);
|
|
85687
|
+
}
|
|
85238
85688
|
default:
|
|
85239
85689
|
return unsupportedOp("mutate", "nexus", operation, startTime);
|
|
85240
85690
|
}
|
|
@@ -85263,7 +85713,8 @@ var NexusHandler = class {
|
|
|
85263
85713
|
"blockers.show",
|
|
85264
85714
|
"orphans.list",
|
|
85265
85715
|
"discover",
|
|
85266
|
-
"search"
|
|
85716
|
+
"search",
|
|
85717
|
+
"transfer.preview"
|
|
85267
85718
|
],
|
|
85268
85719
|
mutate: [
|
|
85269
85720
|
"share.snapshot.export",
|
|
@@ -85273,7 +85724,8 @@ var NexusHandler = class {
|
|
|
85273
85724
|
"unregister",
|
|
85274
85725
|
"sync",
|
|
85275
85726
|
"permission.set",
|
|
85276
|
-
"reconcile"
|
|
85727
|
+
"reconcile",
|
|
85728
|
+
"transfer"
|
|
85277
85729
|
]
|
|
85278
85730
|
};
|
|
85279
85731
|
}
|
|
@@ -88730,7 +89182,7 @@ function getConfig() {
|
|
|
88730
89182
|
|
|
88731
89183
|
// packages/cleo/src/dispatch/middleware/audit.ts
|
|
88732
89184
|
init_internal();
|
|
88733
|
-
var
|
|
89185
|
+
var log9 = getLogger("audit");
|
|
88734
89186
|
var cachedProjectHash;
|
|
88735
89187
|
function resolveProjectHash() {
|
|
88736
89188
|
if (cachedProjectHash !== void 0) return cachedProjectHash;
|
|
@@ -88761,9 +89213,9 @@ async function writeToSqlite(entry, requestId) {
|
|
|
88761
89213
|
const { getDb: getDb4 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
|
|
88762
89214
|
const { auditLog: auditLog2 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
|
|
88763
89215
|
const { AuditLogInsertSchema: AuditLogInsertSchema2 } = await Promise.resolve().then(() => (init_internal(), internal_exports));
|
|
88764
|
-
const { randomUUID:
|
|
89216
|
+
const { randomUUID: randomUUID11 } = await import("node:crypto");
|
|
88765
89217
|
const payload = {
|
|
88766
|
-
id:
|
|
89218
|
+
id: randomUUID11(),
|
|
88767
89219
|
timestamp: entry.timestamp,
|
|
88768
89220
|
action: entry.operation,
|
|
88769
89221
|
taskId: entry.metadata.taskId ?? "system",
|
|
@@ -88784,7 +89236,7 @@ async function writeToSqlite(entry, requestId) {
|
|
|
88784
89236
|
};
|
|
88785
89237
|
const parsed = AuditLogInsertSchema2.safeParse(payload);
|
|
88786
89238
|
if (!parsed.success) {
|
|
88787
|
-
|
|
89239
|
+
log9.warn(
|
|
88788
89240
|
{ issues: parsed.error.issues },
|
|
88789
89241
|
"Audit payload failed Zod validation; skipping insert"
|
|
88790
89242
|
);
|
|
@@ -88793,7 +89245,7 @@ async function writeToSqlite(entry, requestId) {
|
|
|
88793
89245
|
const db = await getDb4(process.cwd());
|
|
88794
89246
|
await db.insert(auditLog2).values(parsed.data).run();
|
|
88795
89247
|
} catch (err) {
|
|
88796
|
-
|
|
89248
|
+
log9.warn({ err }, "Failed to write audit entry to SQLite");
|
|
88797
89249
|
}
|
|
88798
89250
|
}
|
|
88799
89251
|
function createAudit() {
|
|
@@ -88824,7 +89276,7 @@ function createAudit() {
|
|
|
88824
89276
|
},
|
|
88825
89277
|
error: response.error?.message
|
|
88826
89278
|
};
|
|
88827
|
-
|
|
89279
|
+
log9.info(
|
|
88828
89280
|
{
|
|
88829
89281
|
domain: entry.domain,
|
|
88830
89282
|
operation: entry.operation,
|
|
@@ -88841,7 +89293,7 @@ function createAudit() {
|
|
|
88841
89293
|
await writeToSqlite(entry, req.requestId);
|
|
88842
89294
|
} else {
|
|
88843
89295
|
writeToSqlite(entry, req.requestId).catch((err) => {
|
|
88844
|
-
|
|
89296
|
+
log9.error({ err }, "Failed to persist audit entry to SQLite");
|
|
88845
89297
|
});
|
|
88846
89298
|
}
|
|
88847
89299
|
return response;
|
|
@@ -89025,7 +89477,7 @@ async function dispatchFromCli(gateway, domain2, operation, params, outputOpts)
|
|
|
89025
89477
|
operation,
|
|
89026
89478
|
params,
|
|
89027
89479
|
source: "cli",
|
|
89028
|
-
requestId:
|
|
89480
|
+
requestId: randomUUID10()
|
|
89029
89481
|
});
|
|
89030
89482
|
if (response.success) {
|
|
89031
89483
|
await autoRecordDispatchTokenUsage({
|
|
@@ -89078,7 +89530,7 @@ async function dispatchRaw(gateway, domain2, operation, params) {
|
|
|
89078
89530
|
operation,
|
|
89079
89531
|
params,
|
|
89080
89532
|
source: "cli",
|
|
89081
|
-
requestId:
|
|
89533
|
+
requestId: randomUUID10()
|
|
89082
89534
|
});
|
|
89083
89535
|
}
|
|
89084
89536
|
|