@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 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
- return join7(__dirname, "..", "..", "migrations", "drizzle-brain");
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
- return join8(__dirname, "..", "..", "migrations", "drizzle-nexus");
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 log9 = getLogger("sqlite");
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
- log9.warn(
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
- log9.info(
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
- log9.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
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 log9 = getLogger("sqlite");
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
- log9.warn(
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
- return join9(__dirname, "..", "..", "migrations", "drizzle-tasks");
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 importTasksPackage(params) {
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(params.cwd);
14905
+ const accessor = await getAccessor(options.cwd);
14882
14906
  const { tasks: existingTasks } = await accessor.queryTasks({});
14883
- const onConflict = params.onConflict ?? "fail";
14884
- const onMissingDep = params.onMissingDep ?? "strip";
14885
- const force = params.force ?? false;
14886
- const parentId = params.parent;
14887
- const phaseOverride = params.phase;
14888
- const addLabel = params.addLabel;
14889
- const resetStatus = params.resetStatus;
14890
- const addProvenance = params.provenance !== false;
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 (params.dryRun) {
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
- log6.debug("auditRetentionDays is 0 or unset; skipping audit prune");
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
- log6.debug("No audit_log rows older than cutoff; nothing to prune");
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
- log6.info(
55788
+ log7.info(
55497
55789
  { archivePath, rowsArchived },
55498
55790
  `Archived ${rowsArchived} audit rows to ${archivePath}`
55499
55791
  );
55500
55792
  } catch (archiveErr) {
55501
- log6.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
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
- log6.info(
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
- log6.warn({ err }, "audit log pruning failed");
55808
+ log7.warn({ err }, "audit log pruning failed");
55517
55809
  return { rowsArchived: 0, rowsDeleted: 0 };
55518
55810
  }
55519
55811
  }
55520
- var log6;
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
- log6 = getLogger("prune");
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 randomUUID5 } from "node:crypto";
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: randomUUID5(),
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 randomUUID6 } from "node:crypto";
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-${randomUUID6().slice(0, 8)}`;
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 randomUUID7 } from "node:crypto";
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: randomUUID7(),
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
- log7.warn(
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
- log7.warn({ err }, "Checkpoint failed (non-fatal)");
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
- log7.info({ operation }, "Forcing checkpoint before operation");
68951
+ log8.info({ operation }, "Forcing checkpoint before operation");
68659
68952
  try {
68660
68953
  await gitCheckpoint("manual", `pre-${operation}`, cwd);
68661
68954
  } catch (err) {
68662
- log7.error({ err }, "Failed to create pre-operation checkpoint");
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 log7, DEFAULT_CONFIG2, SafetyError;
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
- log7 = getLogger("data-safety");
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 randomUUID9 } from "node:crypto";
77141
+ import { randomUUID as randomUUID10 } from "node:crypto";
76845
77142
 
76846
77143
  // packages/cleo/src/dispatch/lib/meta.ts
76847
- import { randomUUID as randomUUID8 } from "node:crypto";
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 ?? randomUUID8(),
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 log8 = getLogger("audit");
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: randomUUID10 } = await import("node:crypto");
89216
+ const { randomUUID: randomUUID11 } = await import("node:crypto");
88765
89217
  const payload = {
88766
- id: randomUUID10(),
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
- log8.warn(
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
- log8.warn({ err }, "Failed to write audit entry to SQLite");
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
- log8.info(
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
- log8.error({ err }, "Failed to persist audit entry to SQLite");
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: randomUUID9()
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: randomUUID9()
89533
+ requestId: randomUUID10()
89082
89534
  });
89083
89535
  }
89084
89536