@kb-labs/devlink-entry 2.94.0 → 2.98.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
1
+ import { defineCommand, TimingTracker, useLoader, handleError } from '@kb-labs/sdk';
2
2
  import { restoreBackup, listBackups } from '@kb-labs/devlink-core';
3
3
 
4
4
  // src/cli/commands/backups.ts
@@ -15,7 +15,15 @@ var backups_default = defineCommand({
15
15
  if (restoreId) {
16
16
  const loader = useLoader(`Restoring backup ${restoreId}...`);
17
17
  loader.start();
18
- const { restored, errors } = restoreBackup(rootDir, restoreId);
18
+ let restored;
19
+ let errors;
20
+ try {
21
+ ({ restored, errors } = restoreBackup(rootDir, restoreId));
22
+ } catch (err) {
23
+ loader.fail("Restore failed");
24
+ handleError(ctx, err, outputJson);
25
+ return { exitCode: 1 };
26
+ }
19
27
  loader.succeed(`Restored ${restored} file(s)`);
20
28
  tracker.checkpoint("restore");
21
29
  const backups2 = listBackups(rootDir);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/backups.ts"],"names":["backups","result"],"mappings":"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","file":"backups.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { listBackups, restoreBackup } from '@kb-labs/devlink-core';\nimport type { DevlinkBackup } from '@kb-labs/devlink-contracts';\n\ninterface BackupsFlags {\n restore?: string;\n json?: boolean;\n}\n\ninterface BackupsInput {\n argv?: string[];\n flags?: BackupsFlags;\n restore?: string;\n json?: boolean;\n}\n\ninterface BackupsResult {\n backups: DevlinkBackup[];\n restored?: number;\n}\n\nexport default defineCommand<unknown, BackupsInput, BackupsResult>({\n id: 'devlink:backups',\n description: 'List and restore backups',\n\n handler: {\n async execute(ctx: PluginContextV3, input: BackupsInput): Promise<CommandResult<BackupsResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as BackupsFlags;\n const outputJson = flags.json ?? false;\n const restoreId = flags.restore;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n // ─── Restore mode ────────────────────────────────────────────────────────\n if (restoreId) {\n const loader = useLoader(`Restoring backup ${restoreId}...`);\n loader.start();\n\n const { restored, errors } = restoreBackup(rootDir, restoreId);\n loader.succeed(`Restored ${restored} file(s)`);\n tracker.checkpoint('restore');\n\n const backups = listBackups(rootDir);\n const result: BackupsResult = { backups, restored };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n ctx.ui?.success?.(`Restored ${restored} file(s) from backup ${restoreId}`, {\n title: 'DevLink — Restore Backup',\n sections: [\n ...(errors.length > 0 ? [{ header: 'Errors', items: errors }] : []),\n { header: 'Next step', items: ['Run pnpm install to apply changes'] },\n ],\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n }\n\n // ─── List mode ───────────────────────────────────────────────────────────\n const backups = listBackups(rootDir);\n tracker.checkpoint('list');\n\n const result: BackupsResult = { backups };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n if (backups.length === 0) {\n ctx.ui?.info?.('No backups found. Backups are created automatically before each switch.');\n } else {\n const items = backups.map(b =>\n `[${b.id}] ${b.timestamp.slice(0, 19).replace('T', ' ')} — ${b.description} (${b.files.length} files)`\n );\n ctx.ui?.success?.(`${backups.length} backup(s) available`, {\n title: 'DevLink — Backups',\n sections: [\n { header: 'Backups (newest first)', items },\n { header: 'Restore', items: ['kb devlink backups --restore <id>'] },\n ],\n timing: tracker.total(),\n });\n }\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/backups.ts"],"names":["backups","result"],"mappings":"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","file":"backups.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, handleError, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { listBackups, restoreBackup } from '@kb-labs/devlink-core';\nimport type { DevlinkBackup } from '@kb-labs/devlink-contracts';\n\ninterface BackupsFlags {\n restore?: string;\n json?: boolean;\n}\n\ninterface BackupsInput {\n argv?: string[];\n flags?: BackupsFlags;\n restore?: string;\n json?: boolean;\n}\n\ninterface BackupsResult {\n backups: DevlinkBackup[];\n restored?: number;\n}\n\nexport default defineCommand<unknown, BackupsInput, BackupsResult>({\n id: 'devlink:backups',\n description: 'List and restore backups',\n\n handler: {\n async execute(ctx: PluginContextV3, input: BackupsInput): Promise<CommandResult<BackupsResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as BackupsFlags;\n const outputJson = flags.json ?? false;\n const restoreId = flags.restore;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n // ─── Restore mode ────────────────────────────────────────────────────────\n if (restoreId) {\n const loader = useLoader(`Restoring backup ${restoreId}...`);\n loader.start();\n\n let restored: number;\n let errors: string[];\n try {\n ({ restored, errors } = restoreBackup(rootDir, restoreId));\n } catch (err) {\n loader.fail('Restore failed');\n handleError(ctx, err, outputJson);\n return { exitCode: 1 };\n }\n loader.succeed(`Restored ${restored} file(s)`);\n tracker.checkpoint('restore');\n\n const backups = listBackups(rootDir);\n const result: BackupsResult = { backups, restored };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n ctx.ui?.success?.(`Restored ${restored} file(s) from backup ${restoreId}`, {\n title: 'DevLink — Restore Backup',\n sections: [\n ...(errors.length > 0 ? [{ header: 'Errors', items: errors }] : []),\n { header: 'Next step', items: ['Run pnpm install to apply changes'] },\n ],\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n }\n\n // ─── List mode ───────────────────────────────────────────────────────────\n const backups = listBackups(rootDir);\n tracker.checkpoint('list');\n\n const result: BackupsResult = { backups };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n if (backups.length === 0) {\n ctx.ui?.info?.('No backups found. Backups are created automatically before each switch.');\n } else {\n const items = backups.map(b =>\n `[${b.id}] ${b.timestamp.slice(0, 19).replace('T', ' ')} — ${b.description} (${b.files.length} files)`\n );\n ctx.ui?.success?.(`${backups.length} backup(s) available`, {\n title: 'DevLink — Backups',\n sections: [\n { header: 'Backups (newest first)', items },\n { header: 'Restore', items: ['kb devlink backups --restore <id>'] },\n ],\n timing: tracker.total(),\n });\n }\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
@@ -1,4 +1,4 @@
1
- import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
1
+ import { defineCommand, TimingTracker, useLoader, handleError } from '@kb-labs/sdk';
2
2
  import { loadState, discoverMonorepos, buildPackageMapFiltered, buildPlan, freeze } from '@kb-labs/devlink-core';
3
3
 
4
4
  // src/cli/commands/freeze.ts
@@ -6,6 +6,14 @@ var freeze_default = defineCommand({
6
6
  id: "devlink:freeze",
7
7
  description: "Freeze current dependency state to lock file",
8
8
  handler: {
9
+ async intent(_ctx, _input) {
10
+ return {
11
+ summary: "Freeze current dependency state to lock file",
12
+ operations: [
13
+ { type: "create", resource: "file", details: { path: ".kb/devlink/lock.json" } }
14
+ ]
15
+ };
16
+ },
9
17
  async execute(ctx, input) {
10
18
  const tracker = new TimingTracker();
11
19
  const flags = input.flags ?? input;
@@ -13,12 +21,19 @@ var freeze_default = defineCommand({
13
21
  const rootDir = ctx.cwd ?? process.cwd();
14
22
  const loader = useLoader("Freezing current state...");
15
23
  loader.start();
16
- const state = loadState(rootDir);
17
- const monorepos = discoverMonorepos(rootDir);
18
- const currentMode = state.currentMode ?? "npm";
19
- const packageMap = await buildPackageMapFiltered(monorepos, rootDir, void 0, currentMode);
20
- const plan = buildPlan(currentMode, packageMap, monorepos, rootDir);
21
- const lock = freeze(rootDir, plan);
24
+ let lock;
25
+ try {
26
+ const state = loadState(rootDir);
27
+ const monorepos = discoverMonorepos(rootDir);
28
+ const currentMode = state.currentMode ?? "npm";
29
+ const packageMap = await buildPackageMapFiltered(monorepos, rootDir, void 0, currentMode);
30
+ const plan = buildPlan(currentMode, packageMap, monorepos, rootDir);
31
+ lock = freeze(rootDir, plan);
32
+ } catch (err) {
33
+ loader.fail("Failed to freeze state");
34
+ handleError(ctx, err, outputJson);
35
+ return { exitCode: 1 };
36
+ }
22
37
  loader.succeed("State frozen");
23
38
  tracker.checkpoint("freeze");
24
39
  if (outputJson) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/freeze.ts"],"names":[],"mappings":";;;;AAcA,IAAO,iBAAQ,aAAA,CAA8C;AAAA,EAC3D,EAAA,EAAI,gBAAA;AAAA,EACJ,WAAA,EAAa,8CAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAsD;AACxF,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,EAAc;AAClC,MAAA,MAAM,KAAA,GAAS,MAAM,KAAA,IAAS,KAAA;AAC9B,MAAA,MAAM,UAAA,GAAa,MAAM,IAAA,IAAQ,KAAA;AAEjC,MAAA,MAAM,OAAA,GAAU,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEvC,MAAA,MAAM,MAAA,GAAS,UAAU,2BAA2B,CAAA;AACpD,MAAA,MAAA,CAAO,KAAA,EAAM;AAEb,MAAA,MAAM,KAAA,GAAQ,UAAU,OAAO,CAAA;AAC/B,MAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAG3C,MAAA,MAAM,WAAA,GAAc,MAAM,WAAA,IAAe,KAAA;AACzC,MAAA,MAAM,aAAa,MAAM,uBAAA,CAAwB,SAAA,EAAW,OAAA,EAAS,QAAW,WAAW,CAAA;AAC3F,MAAA,MAAM,IAAA,GAAO,SAAA,CAAU,WAAA,EAAa,UAAA,EAAY,WAAW,OAAO,CAAA;AAElE,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,EAAS,IAAI,CAAA;AACjC,MAAA,MAAA,CAAO,QAAQ,cAAc,CAAA;AAC7B,MAAA,OAAA,CAAQ,WAAW,QAAQ,CAAA;AAE3B,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,IAAI,CAAA;AAAA,MACrB,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,EAAA,EAAI,UAAU,mCAAA,EAAqC;AAAA,UACrD,KAAA,EAAO,uBAAA;AAAA,UACP,QAAA,EAAU;AAAA,YACR;AAAA,cACE,MAAA,EAAQ,WAAA;AAAA,cACR,KAAA,EAAO;AAAA,gBACL,CAAA,MAAA,EAAS,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,gBACvB,CAAA,WAAA,EAAc,KAAK,QAAQ,CAAA,CAAA;AAAA,gBAC3B,CAAA,+BAAA;AAAA;AACF;AACF,WACF;AAAA,UACA,MAAA,EAAQ,QAAQ,KAAA;AAAM,SACvB,CAAA;AAAA,MACH;AAEA,MAAA,OAAO,EAAE,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,EAAE,MAAA,EAAQ,OAAA,CAAQ,KAAA,EAAM,EAAE,EAAE;AAAA,IACxE;AAAA;AAEJ,CAAC","file":"freeze.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, buildPlan, freeze, loadState } from '@kb-labs/devlink-core';\nimport type { LockFile } from '@kb-labs/devlink-core';\n\ninterface FreezeFlags {\n json?: boolean;\n}\n\ninterface FreezeInput {\n argv?: string[];\n flags?: FreezeFlags;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, FreezeInput, LockFile>({\n id: 'devlink:freeze',\n description: 'Freeze current dependency state to lock file',\n\n handler: {\n async execute(ctx: PluginContextV3, input: FreezeInput): Promise<CommandResult<LockFile>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as FreezeFlags;\n const outputJson = flags.json ?? false;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const loader = useLoader('Freezing current state...');\n loader.start();\n\n const state = loadState(rootDir);\n const monorepos = discoverMonorepos(rootDir);\n\n // Build a plan that reflects current state (no-op plan for the current mode)\n const currentMode = state.currentMode ?? 'npm';\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir, undefined, currentMode);\n const plan = buildPlan(currentMode, packageMap, monorepos, rootDir);\n\n const lock = freeze(rootDir, plan);\n loader.succeed('State frozen');\n tracker.checkpoint('freeze');\n\n if (outputJson) {\n ctx.ui?.json?.(lock);\n } else {\n ctx.ui?.success?.('Current state frozen to lock file', {\n title: 'DevLink — Freeze',\n sections: [\n {\n header: 'Lock file',\n items: [\n `Mode: ${lock.plan.mode}`,\n `Frozen at: ${lock.frozenAt}`,\n `Location: .kb/devlink/lock.json`,\n ],\n },\n ],\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result: lock, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/freeze.ts"],"names":[],"mappings":";;;;AAcA,IAAO,iBAAQ,aAAA,CAA8C;AAAA,EAC3D,EAAA,EAAI,gBAAA;AAAA,EACJ,WAAA,EAAa,8CAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,MAAA,CAAO,IAAA,EAAuB,MAAA,EAAqB;AACvD,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,8CAAA;AAAA,QACT,UAAA,EAAY;AAAA,UACV,EAAE,MAAM,QAAA,EAAmB,QAAA,EAAU,QAAQ,OAAA,EAAS,EAAE,IAAA,EAAM,uBAAA,EAAwB;AAAE;AAC1F,OACF;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAsD;AACxF,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,EAAc;AAClC,MAAA,MAAM,KAAA,GAAS,MAAM,KAAA,IAAS,KAAA;AAC9B,MAAA,MAAM,UAAA,GAAa,MAAM,IAAA,IAAQ,KAAA;AAEjC,MAAA,MAAM,OAAA,GAAU,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEvC,MAAA,MAAM,MAAA,GAAS,UAAU,2BAA2B,CAAA;AACpD,MAAA,MAAA,CAAO,KAAA,EAAM;AAEb,MAAA,IAAI,IAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,UAAU,OAAO,CAAA;AAC/B,QAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAC3C,QAAA,MAAM,WAAA,GAAc,MAAM,WAAA,IAAe,KAAA;AACzC,QAAA,MAAM,aAAa,MAAM,uBAAA,CAAwB,SAAA,EAAW,OAAA,EAAS,QAAW,WAAW,CAAA;AAC3F,QAAA,MAAM,IAAA,GAAO,SAAA,CAAU,WAAA,EAAa,UAAA,EAAY,WAAW,OAAO,CAAA;AAClE,QAAA,IAAA,GAAO,MAAA,CAAO,SAAS,IAAI,CAAA;AAAA,MAC7B,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,KAAK,wBAAwB,CAAA;AACpC,QAAA,WAAA,CAAY,GAAA,EAAK,KAAK,UAAU,CAAA;AAChC,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AACA,MAAA,MAAA,CAAO,QAAQ,cAAc,CAAA;AAC7B,MAAA,OAAA,CAAQ,WAAW,QAAQ,CAAA;AAE3B,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,IAAI,CAAA;AAAA,MACrB,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,EAAA,EAAI,UAAU,mCAAA,EAAqC;AAAA,UACrD,KAAA,EAAO,uBAAA;AAAA,UACP,QAAA,EAAU;AAAA,YACR;AAAA,cACE,MAAA,EAAQ,WAAA;AAAA,cACR,KAAA,EAAO;AAAA,gBACL,CAAA,MAAA,EAAS,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,gBACvB,CAAA,WAAA,EAAc,KAAK,QAAQ,CAAA,CAAA;AAAA,gBAC3B,CAAA,+BAAA;AAAA;AACF;AACF,WACF;AAAA,UACA,MAAA,EAAQ,QAAQ,KAAA;AAAM,SACvB,CAAA;AAAA,MACH;AAEA,MAAA,OAAO,EAAE,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,EAAE,MAAA,EAAQ,OAAA,CAAQ,KAAA,EAAM,EAAE,EAAE;AAAA,IACxE;AAAA;AAEJ,CAAC","file":"freeze.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, handleError, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, buildPlan, freeze, loadState } from '@kb-labs/devlink-core';\nimport type { LockFile } from '@kb-labs/devlink-core';\n\ninterface FreezeFlags {\n json?: boolean;\n}\n\ninterface FreezeInput {\n argv?: string[];\n flags?: FreezeFlags;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, FreezeInput, LockFile>({\n id: 'devlink:freeze',\n description: 'Freeze current dependency state to lock file',\n\n handler: {\n async intent(_ctx: PluginContextV3, _input: FreezeInput) {\n return {\n summary: 'Freeze current dependency state to lock file',\n operations: [\n { type: 'create' as const, resource: 'file', details: { path: '.kb/devlink/lock.json' } },\n ],\n };\n },\n\n async execute(ctx: PluginContextV3, input: FreezeInput): Promise<CommandResult<LockFile>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as FreezeFlags;\n const outputJson = flags.json ?? false;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const loader = useLoader('Freezing current state...');\n loader.start();\n\n let lock;\n try {\n const state = loadState(rootDir);\n const monorepos = discoverMonorepos(rootDir);\n const currentMode = state.currentMode ?? 'npm';\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir, undefined, currentMode);\n const plan = buildPlan(currentMode, packageMap, monorepos, rootDir);\n lock = freeze(rootDir, plan);\n } catch (err) {\n loader.fail('Failed to freeze state');\n handleError(ctx, err, outputJson);\n return { exitCode: 1 };\n }\n loader.succeed('State frozen');\n tracker.checkpoint('freeze');\n\n if (outputJson) {\n ctx.ui?.json?.(lock);\n } else {\n ctx.ui?.success?.('Current state frozen to lock file', {\n title: 'DevLink — Freeze',\n sections: [\n {\n header: 'Lock file',\n items: [\n `Mode: ${lock.plan.mode}`,\n `Frozen at: ${lock.frozenAt}`,\n `Location: .kb/devlink/lock.json`,\n ],\n },\n ],\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result: lock, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
@@ -1,4 +1,4 @@
1
- import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
1
+ import { defineCommand, TimingTracker, useLoader, handleError } from '@kb-labs/sdk';
2
2
  import { loadState, discoverMonorepos, buildPackageMapFiltered, buildPlan, groupByMonorepo } from '@kb-labs/devlink-core';
3
3
 
4
4
  // src/cli/commands/plan.ts
@@ -15,11 +15,21 @@ var plan_default = defineCommand({
15
15
  const rootDir = ctx.cwd ?? process.cwd();
16
16
  const loader = useLoader("Building plan...");
17
17
  loader.start();
18
- const state = loadState(rootDir);
19
- const monorepos = discoverMonorepos(rootDir);
20
- const targetMode = flags.mode ?? (state.currentMode === "npm" ? "local" : "npm");
21
- const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, targetMode);
22
- const plan = buildPlan(targetMode, packageMap, monorepos, rootDir, { scopedRepos });
18
+ let plan;
19
+ let targetMode;
20
+ let currentModeBefore;
21
+ try {
22
+ const state = loadState(rootDir);
23
+ currentModeBefore = state.currentMode ?? void 0;
24
+ const monorepos = discoverMonorepos(rootDir);
25
+ targetMode = flags.mode ?? (state.currentMode === "npm" ? "local" : "npm");
26
+ const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, targetMode);
27
+ plan = buildPlan(targetMode, packageMap, monorepos, rootDir, { scopedRepos });
28
+ } catch (err) {
29
+ loader.fail("Failed to build plan");
30
+ handleError(ctx, err, outputJson);
31
+ return { exitCode: 1 };
32
+ }
23
33
  loader.succeed(`Plan ready: ${plan.items.length} change(s)`);
24
34
  tracker.checkpoint("plan");
25
35
  if (outputJson) {
@@ -52,7 +62,7 @@ var plan_default = defineCommand({
52
62
  title: "DevLink \u2014 Plan",
53
63
  status: "info",
54
64
  summary: {
55
- "Mode": `${state.currentMode ?? "?"} \u2192 ${targetMode}`,
65
+ "Mode": `${currentModeBefore ?? "?"} \u2192 ${targetMode}`,
56
66
  "Packages": uniquePkgs,
57
67
  "Files affected": uniqueFiles,
58
68
  "Total changes": plan.items.length
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/plan.ts"],"names":[],"mappings":"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","file":"plan.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, buildPlan, groupByMonorepo, loadState } from '@kb-labs/devlink-core';\nimport type { DevlinkMode, DevlinkPlan } from '@kb-labs/devlink-contracts';\n\ninterface PlanFlags {\n mode?: DevlinkMode;\n repos?: string;\n json?: boolean;\n ttl?: number;\n}\n\ninterface PlanInput {\n argv?: string[];\n flags?: PlanFlags;\n mode?: DevlinkMode;\n repos?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, PlanInput, DevlinkPlan>({\n id: 'devlink:plan',\n description: 'Preview what would change when switching mode',\n\n handler: {\n async execute(ctx: PluginContextV3, input: PlanInput): Promise<CommandResult<DevlinkPlan>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as PlanFlags;\n const outputJson = flags.json ?? false;\n const scopedRepos = flags.repos ? flags.repos.split(',').map(s => s.trim()) : undefined;\n const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1000;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const loader = useLoader('Building plan...');\n loader.start();\n\n const state = loadState(rootDir);\n const monorepos = discoverMonorepos(rootDir);\n\n // Determine target mode before building package map — local mode skips npm check\n const targetMode: DevlinkMode = flags.mode ?? (state.currentMode === 'npm' ? 'local' : 'npm');\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, targetMode);\n\n const plan = buildPlan(targetMode, packageMap, monorepos, rootDir, { scopedRepos });\n loader.succeed(`Plan ready: ${plan.items.length} change(s)`);\n tracker.checkpoint('plan');\n\n if (outputJson) {\n ctx.ui?.json?.(plan);\n } else {\n if (plan.items.length === 0) {\n ctx.ui?.info?.('No changes needed — already in the target mode.');\n } else {\n const byRepo = groupByMonorepo(plan.items);\n // Unique packages in npm map\n const uniquePkgs = new Set(plan.items.map(i => i.depName)).size;\n const uniqueFiles = new Set(plan.items.map(i => i.packageJsonPath)).size;\n\n const sections = [...byRepo.entries()].map(([repo, items]) => {\n // Group by depName within each repo — show \"×N files\" instead of N lines\n const byDep = new Map<string, { from: string; to: string; count: number }>();\n for (const item of items) {\n const existing = byDep.get(item.depName);\n if (existing) {\n existing.count++;\n } else {\n byDep.set(item.depName, { from: item.from, to: item.to, count: 1 });\n }\n }\n return {\n header: `${repo} (${byDep.size} dep${byDep.size !== 1 ? 's' : ''})`,\n items: [...byDep.entries()].map(([dep, { from, to, count }]) =>\n count > 1\n ? `${dep}: ${from} → ${to} ×${count} files`\n : `${dep}: ${from} → ${to}`\n ),\n };\n });\n\n ctx.ui?.sideBox?.({\n title: 'DevLink — Plan',\n status: 'info',\n summary: {\n 'Mode': `${state.currentMode ?? '?'} → ${targetMode}`,\n 'Packages': uniquePkgs,\n 'Files affected': uniqueFiles,\n 'Total changes': plan.items.length,\n },\n sections: [\n ...sections,\n { header: 'Next step', items: [`kb devlink switch --mode=${targetMode}`] },\n ],\n timing: tracker.total(),\n });\n }\n }\n\n return { exitCode: 0, result: plan, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/plan.ts"],"names":[],"mappings":"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","file":"plan.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, handleError, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, buildPlan, groupByMonorepo, loadState } from '@kb-labs/devlink-core';\nimport type { DevlinkMode, DevlinkPlan } from '@kb-labs/devlink-contracts';\n\ninterface PlanFlags {\n mode?: DevlinkMode;\n repos?: string;\n json?: boolean;\n ttl?: number;\n}\n\ninterface PlanInput {\n argv?: string[];\n flags?: PlanFlags;\n mode?: DevlinkMode;\n repos?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, PlanInput, DevlinkPlan>({\n id: 'devlink:plan',\n description: 'Preview what would change when switching mode',\n\n handler: {\n async execute(ctx: PluginContextV3, input: PlanInput): Promise<CommandResult<DevlinkPlan>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as PlanFlags;\n const outputJson = flags.json ?? false;\n const scopedRepos = flags.repos ? flags.repos.split(',').map(s => s.trim()) : undefined;\n const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1000;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const loader = useLoader('Building plan...');\n loader.start();\n\n let plan;\n let targetMode: DevlinkMode;\n let currentModeBefore: DevlinkMode | undefined;\n try {\n const state = loadState(rootDir);\n currentModeBefore = state.currentMode ?? undefined;\n const monorepos = discoverMonorepos(rootDir);\n targetMode = flags.mode ?? (state.currentMode === 'npm' ? 'local' : 'npm');\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, targetMode);\n plan = buildPlan(targetMode, packageMap, monorepos, rootDir, { scopedRepos });\n } catch (err) {\n loader.fail('Failed to build plan');\n handleError(ctx, err, outputJson);\n return { exitCode: 1 };\n }\n loader.succeed(`Plan ready: ${plan.items.length} change(s)`);\n tracker.checkpoint('plan');\n\n if (outputJson) {\n ctx.ui?.json?.(plan);\n } else {\n if (plan.items.length === 0) {\n ctx.ui?.info?.('No changes needed — already in the target mode.');\n } else {\n const byRepo = groupByMonorepo(plan.items);\n // Unique packages in npm map\n const uniquePkgs = new Set(plan.items.map(i => i.depName)).size;\n const uniqueFiles = new Set(plan.items.map(i => i.packageJsonPath)).size;\n\n const sections = [...byRepo.entries()].map(([repo, items]) => {\n // Group by depName within each repo — show \"×N files\" instead of N lines\n const byDep = new Map<string, { from: string; to: string; count: number }>();\n for (const item of items) {\n const existing = byDep.get(item.depName);\n if (existing) {\n existing.count++;\n } else {\n byDep.set(item.depName, { from: item.from, to: item.to, count: 1 });\n }\n }\n return {\n header: `${repo} (${byDep.size} dep${byDep.size !== 1 ? 's' : ''})`,\n items: [...byDep.entries()].map(([dep, { from, to, count }]) =>\n count > 1\n ? `${dep}: ${from} → ${to} ×${count} files`\n : `${dep}: ${from} → ${to}`\n ),\n };\n });\n\n ctx.ui?.sideBox?.({\n title: 'DevLink — Plan',\n status: 'info',\n summary: {\n 'Mode': `${currentModeBefore ?? '?'} → ${targetMode}`,\n 'Packages': uniquePkgs,\n 'Files affected': uniqueFiles,\n 'Total changes': plan.items.length,\n },\n sections: [\n ...sections,\n { header: 'Next step', items: [`kb devlink switch --mode=${targetMode}`] },\n ],\n timing: tracker.total(),\n });\n }\n }\n\n return { exitCode: 0, result: plan, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
@@ -1,4 +1,4 @@
1
- import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
1
+ import { defineCommand, TimingTracker, useLoader, handleError } from '@kb-labs/sdk';
2
2
  import { loadState, discoverMonorepos, buildPackageMapFiltered, analyzePackageDeps, diagnose } from '@kb-labs/devlink-core';
3
3
 
4
4
  // src/cli/commands/status.ts
@@ -13,21 +13,29 @@ var status_default = defineCommand({
13
13
  const rootDir = ctx.cwd ?? process.cwd();
14
14
  const loader = useLoader("Analyzing dependencies...");
15
15
  loader.start();
16
- const state = loadState(rootDir);
17
- const monorepos = discoverMonorepos(rootDir);
18
- const packageMap = await buildPackageMapFiltered(monorepos, rootDir);
16
+ let state;
19
17
  let totalLink = 0;
20
18
  let totalNpm = 0;
21
19
  let totalWorkspace = 0;
22
- for (const monorepo of monorepos) {
23
- for (const pkgPath of monorepo.packagePaths) {
24
- const counts = analyzePackageDeps(pkgPath, packageMap);
25
- totalLink += counts.linkCount;
26
- totalNpm += counts.npmCount;
27
- totalWorkspace += counts.workspaceCount;
20
+ let diagnostics;
21
+ try {
22
+ state = loadState(rootDir);
23
+ const monorepos = discoverMonorepos(rootDir);
24
+ const packageMap = await buildPackageMapFiltered(monorepos, rootDir);
25
+ for (const monorepo of monorepos) {
26
+ for (const pkgPath of monorepo.packagePaths) {
27
+ const counts = analyzePackageDeps(pkgPath, packageMap);
28
+ totalLink += counts.linkCount;
29
+ totalNpm += counts.npmCount;
30
+ totalWorkspace += counts.workspaceCount;
31
+ }
28
32
  }
33
+ diagnostics = diagnose(monorepos, packageMap, rootDir);
34
+ } catch (err) {
35
+ loader.fail("Analysis failed");
36
+ handleError(ctx, err, outputJson);
37
+ return { exitCode: 1 };
29
38
  }
30
- const diagnostics = diagnose(monorepos, packageMap, rootDir);
31
39
  loader.succeed("Analysis complete");
32
40
  tracker.checkpoint("analysis");
33
41
  const errors = diagnostics.filter((d) => d.severity === "error");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"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","file":"status.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, analyzePackageDeps, loadState, diagnose } from '@kb-labs/devlink-core';\nimport type { DevlinkStatus, DiagnosticIssue } from '@kb-labs/devlink-contracts';\n\ninterface StatusFlags {\n json?: boolean;\n}\n\ninterface StatusInput {\n argv?: string[];\n flags?: StatusFlags;\n json?: boolean;\n}\n\ninterface StatusResult extends DevlinkStatus {\n diagnostics: DiagnosticIssue[];\n}\n\nexport default defineCommand<unknown, StatusInput, StatusResult>({\n id: 'devlink:status',\n description: 'Show current state of cross-repo dependencies with diagnostics',\n\n handler: {\n async execute(ctx: PluginContextV3, input: StatusInput): Promise<CommandResult<StatusResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as StatusFlags;\n const outputJson = flags.json ?? false;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const loader = useLoader('Analyzing dependencies...');\n loader.start();\n\n const state = loadState(rootDir);\n const monorepos = discoverMonorepos(rootDir);\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir);\n\n let totalLink = 0;\n let totalNpm = 0;\n let totalWorkspace = 0;\n\n for (const monorepo of monorepos) {\n for (const pkgPath of monorepo.packagePaths) {\n const counts = analyzePackageDeps(pkgPath, packageMap);\n totalLink += counts.linkCount;\n totalNpm += counts.npmCount;\n totalWorkspace += counts.workspaceCount;\n }\n }\n\n // Run diagnostics\n const diagnostics = diagnose(monorepos, packageMap, rootDir);\n\n loader.succeed('Analysis complete');\n tracker.checkpoint('analysis');\n\n const errors = diagnostics.filter(d => d.severity === 'error');\n const warnings = diagnostics.filter(d => d.severity === 'warning');\n\n const result: StatusResult = {\n currentMode: state.currentMode,\n lastApplied: state.lastApplied,\n linkCount: totalLink,\n npmCount: totalNpm,\n workspaceCount: totalWorkspace,\n discrepancies: [],\n diagnostics,\n };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n const sections = [\n {\n header: 'Current mode',\n items: [\n `Mode: ${state.currentMode ?? 'unknown'}`,\n `Last applied: ${state.lastApplied ?? 'never'}`,\n ],\n },\n {\n header: 'Dependency counts',\n items: [\n `link: (local) : ${totalLink}`,\n `npm (^version) : ${totalNpm}`,\n `workspace:* : ${totalWorkspace}`,\n ],\n },\n ];\n\n if (errors.length > 0) {\n sections.push({\n header: `❌ Errors (${errors.length})`,\n items: errors.slice(0, 10).map(d => `${d.dep ?? d.file}: ${d.message}`),\n });\n }\n\n if (warnings.length > 0) {\n sections.push({\n header: `⚠ Warnings (${warnings.length})`,\n items: warnings.slice(0, 10).map(d => `${d.dep ?? d.file}: ${d.message}`),\n });\n }\n\n if (diagnostics.length === 0) {\n sections.push({ header: '✅ Health', items: ['No issues detected'] });\n } else {\n sections.push({\n header: 'Fix',\n items: ['Run: kb devlink switch --mode=local --install'],\n });\n }\n\n ctx.ui?.success?.('Dependency status', {\n title: 'DevLink — Status',\n sections,\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"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","file":"status.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, handleError, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, analyzePackageDeps, loadState, diagnose } from '@kb-labs/devlink-core';\nimport type { DevlinkStatus, DiagnosticIssue } from '@kb-labs/devlink-contracts';\n\ninterface StatusFlags {\n json?: boolean;\n}\n\ninterface StatusInput {\n argv?: string[];\n flags?: StatusFlags;\n json?: boolean;\n}\n\ninterface StatusResult extends DevlinkStatus {\n diagnostics: DiagnosticIssue[];\n}\n\nexport default defineCommand<unknown, StatusInput, StatusResult>({\n id: 'devlink:status',\n description: 'Show current state of cross-repo dependencies with diagnostics',\n\n handler: {\n async execute(ctx: PluginContextV3, input: StatusInput): Promise<CommandResult<StatusResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as StatusFlags;\n const outputJson = flags.json ?? false;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const loader = useLoader('Analyzing dependencies...');\n loader.start();\n\n let state: ReturnType<typeof loadState>;\n let totalLink = 0;\n let totalNpm = 0;\n let totalWorkspace = 0;\n let diagnostics: ReturnType<typeof diagnose>;\n try {\n state = loadState(rootDir);\n const monorepos = discoverMonorepos(rootDir);\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir);\n\n for (const monorepo of monorepos) {\n for (const pkgPath of monorepo.packagePaths) {\n const counts = analyzePackageDeps(pkgPath, packageMap);\n totalLink += counts.linkCount;\n totalNpm += counts.npmCount;\n totalWorkspace += counts.workspaceCount;\n }\n }\n\n diagnostics = diagnose(monorepos, packageMap, rootDir);\n } catch (err) {\n loader.fail('Analysis failed');\n handleError(ctx, err, outputJson);\n return { exitCode: 1 };\n }\n\n loader.succeed('Analysis complete');\n tracker.checkpoint('analysis');\n\n const errors = diagnostics.filter(d => d.severity === 'error');\n const warnings = diagnostics.filter(d => d.severity === 'warning');\n\n const result: StatusResult = {\n currentMode: state.currentMode,\n lastApplied: state.lastApplied,\n linkCount: totalLink,\n npmCount: totalNpm,\n workspaceCount: totalWorkspace,\n discrepancies: [],\n diagnostics,\n };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n const sections = [\n {\n header: 'Current mode',\n items: [\n `Mode: ${state.currentMode ?? 'unknown'}`,\n `Last applied: ${state.lastApplied ?? 'never'}`,\n ],\n },\n {\n header: 'Dependency counts',\n items: [\n `link: (local) : ${totalLink}`,\n `npm (^version) : ${totalNpm}`,\n `workspace:* : ${totalWorkspace}`,\n ],\n },\n ];\n\n if (errors.length > 0) {\n sections.push({\n header: `❌ Errors (${errors.length})`,\n items: errors.slice(0, 10).map(d => `${d.dep ?? d.file}: ${d.message}`),\n });\n }\n\n if (warnings.length > 0) {\n sections.push({\n header: `⚠ Warnings (${warnings.length})`,\n items: warnings.slice(0, 10).map(d => `${d.dep ?? d.file}: ${d.message}`),\n });\n }\n\n if (diagnostics.length === 0) {\n sections.push({ header: '✅ Health', items: ['No issues detected'] });\n } else {\n sections.push({\n header: 'Fix',\n items: ['Run: kb devlink switch --mode=local --install'],\n });\n }\n\n ctx.ui?.success?.('Dependency status', {\n title: 'DevLink — Status',\n sections,\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
@@ -1,4 +1,5 @@
1
1
  import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
2
+ import { CLIInput } from '@kb-labs/sdk';
2
3
  import { DevlinkMode } from '@kb-labs/devlink-contracts';
3
4
 
4
5
  interface SwitchFlags {
@@ -11,21 +12,11 @@ interface SwitchFlags {
11
12
  install?: boolean;
12
13
  'clean-locks'?: boolean;
13
14
  }
14
- interface SwitchInput {
15
- argv?: string[];
16
- flags?: SwitchFlags;
17
- mode?: DevlinkMode;
18
- 'dry-run'?: boolean;
19
- repos?: string;
20
- yes?: boolean;
21
- json?: boolean;
22
- }
23
15
  interface SwitchResult {
24
16
  mode: DevlinkMode;
25
17
  changed: number;
26
- dryRun: boolean;
27
18
  backupId?: string;
28
19
  }
29
- declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, SwitchInput, SwitchResult>;
20
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<SwitchFlags>, SwitchResult>;
30
21
 
31
22
  export { _default as default };
@@ -1,4 +1,4 @@
1
- import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
1
+ import { defineCommand, TimingTracker, useLoader, handleError } from '@kb-labs/sdk';
2
2
  import { discoverMonorepos, buildPackageMapFiltered, checkGitDirty, buildPlan, loadState, createBackup, applyPlan, updateWorkspaceYamls, saveState } from '@kb-labs/devlink-core';
3
3
  import { existsSync, unlinkSync, rmSync } from 'fs';
4
4
  import { join } from 'path';
@@ -9,19 +9,57 @@ var switch_default = defineCommand({
9
9
  id: "devlink:switch",
10
10
  description: "Switch cross-repo deps between link: and npm mode",
11
11
  handler: {
12
+ async intent(ctx, input) {
13
+ const flags = input.flags;
14
+ const mode = flags.mode;
15
+ const rootDir = ctx.cwd ?? process.cwd();
16
+ const scopedRepos = flags.repos ? flags.repos.split(",").map((s) => s.trim()) : void 0;
17
+ const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1e3;
18
+ let monorepos;
19
+ let packageMap;
20
+ try {
21
+ monorepos = discoverMonorepos(rootDir);
22
+ packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);
23
+ } catch {
24
+ return {
25
+ summary: `Switch dependencies to ${mode ?? "(unknown)"} mode`,
26
+ operations: [{ type: "update", resource: "package-json", details: { mode } }]
27
+ };
28
+ }
29
+ const plan = buildPlan(mode, packageMap, monorepos, rootDir, { scopedRepos });
30
+ const byRepo = /* @__PURE__ */ new Map();
31
+ for (const item of plan.items) {
32
+ byRepo.set(item.monorepo, (byRepo.get(item.monorepo) ?? 0) + 1);
33
+ }
34
+ return {
35
+ summary: `Switch ${plan.items.length} dependencies to ${mode} mode across ${byRepo.size} repo(s)`,
36
+ operations: [...byRepo.entries()].map(([repo, count]) => ({
37
+ type: "update",
38
+ resource: "dependencies",
39
+ details: { repo, count, mode }
40
+ }))
41
+ };
42
+ },
12
43
  async execute(ctx, input) {
13
44
  const tracker = new TimingTracker();
14
- const flags = input.flags ?? input;
45
+ const flags = input.flags;
15
46
  const mode = flags.mode;
16
- const dryRun = flags["dry-run"] ?? false;
17
47
  const outputJson = flags.json ?? false;
18
48
  const scopedRepos = flags.repos ? flags.repos.split(",").map((s) => s.trim()) : void 0;
19
49
  const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1e3;
20
50
  const rootDir = ctx.cwd ?? process.cwd();
21
51
  const discoverLoader = useLoader("Discovering monorepos...");
22
52
  discoverLoader.start();
23
- const monorepos = discoverMonorepos(rootDir);
24
- const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);
53
+ let monorepos;
54
+ let packageMap;
55
+ try {
56
+ monorepos = discoverMonorepos(rootDir);
57
+ packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);
58
+ } catch (err) {
59
+ discoverLoader.fail("Discovery failed");
60
+ handleError(ctx, err, outputJson);
61
+ return { exitCode: 1 };
62
+ }
25
63
  discoverLoader.succeed(`Found ${monorepos.length} monorepos, ${Object.keys(packageMap).length} packages`);
26
64
  tracker.checkpoint("discovery");
27
65
  const dirtyFiles = checkGitDirty(rootDir);
@@ -32,28 +70,7 @@ var switch_default = defineCommand({
32
70
  tracker.checkpoint("plan");
33
71
  if (plan.items.length === 0 && !flags.install) {
34
72
  ctx.ui?.info?.("No changes needed \u2014 dependencies are already in the requested mode.");
35
- return { exitCode: 0, result: { mode, changed: 0, dryRun }, meta: { timing: tracker.total() } };
36
- }
37
- if (dryRun) {
38
- const result2 = { mode, changed: plan.items.length, dryRun: true };
39
- if (outputJson) {
40
- ctx.ui?.json?.({ ...result2, items: plan.items });
41
- } else {
42
- const byRepo = /* @__PURE__ */ new Map();
43
- for (const item of plan.items) {
44
- byRepo.set(item.monorepo, (byRepo.get(item.monorepo) ?? 0) + 1);
45
- }
46
- const repoLines = [...byRepo.entries()].map(([repo, count]) => `${repo}: ${count} change(s)`);
47
- ctx.ui?.success?.(`[dry-run] Would switch ${plan.items.length} dependencies to ${mode} mode`, {
48
- title: "DevLink \u2014 Dry Run",
49
- sections: [
50
- { header: "Changes by repo", items: repoLines },
51
- { header: "Note", items: ["No files were modified. Remove --dry-run to apply."] }
52
- ],
53
- timing: tracker.total()
54
- });
55
- }
56
- return { exitCode: 0, result: result2, meta: { timing: tracker.total() } };
73
+ return { exitCode: 0, result: { mode, changed: 0 }, meta: { timing: tracker.total() } };
57
74
  }
58
75
  const currentState = loadState(rootDir);
59
76
  const modeAtBackup = currentState.currentMode ?? mode;
@@ -154,7 +171,6 @@ var switch_default = defineCommand({
154
171
  const result = {
155
172
  mode,
156
173
  changed: applyResult.applied,
157
- dryRun: false,
158
174
  backupId
159
175
  };
160
176
  if (outputJson) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/switch.ts"],"names":["result"],"mappings":"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","file":"switch.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, buildPlan, applyPlan, createBackup, loadState, saveState, checkGitDirty, updateWorkspaceYamls } from '@kb-labs/devlink-core';\nimport type { DevlinkMode } from '@kb-labs/devlink-contracts';\nimport { existsSync, unlinkSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\n\ninterface SwitchFlags {\n mode: DevlinkMode;\n 'dry-run'?: boolean;\n repos?: string;\n yes?: boolean;\n json?: boolean;\n ttl?: number;\n install?: boolean;\n 'clean-locks'?: boolean;\n}\n\ninterface SwitchInput {\n argv?: string[];\n flags?: SwitchFlags;\n mode?: DevlinkMode;\n 'dry-run'?: boolean;\n repos?: string;\n yes?: boolean;\n json?: boolean;\n}\n\ninterface SwitchResult {\n mode: DevlinkMode;\n changed: number;\n dryRun: boolean;\n backupId?: string;\n}\n\nexport default defineCommand<unknown, SwitchInput, SwitchResult>({\n id: 'devlink:switch',\n description: 'Switch cross-repo deps between link: and npm mode',\n\n handler: {\n async execute(ctx: PluginContextV3, input: SwitchInput): Promise<CommandResult<SwitchResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as SwitchFlags;\n const mode = flags.mode;\n const dryRun = flags['dry-run'] ?? false;\n const outputJson = flags.json ?? false;\n const scopedRepos = flags.repos ? flags.repos.split(',').map(s => s.trim()) : undefined;\n const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1000;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n // 1. Discover\n const discoverLoader = useLoader('Discovering monorepos...');\n discoverLoader.start();\n\n const monorepos = discoverMonorepos(rootDir);\n const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);\n discoverLoader.succeed(`Found ${monorepos.length} monorepos, ${Object.keys(packageMap).length} packages`);\n tracker.checkpoint('discovery');\n\n // 2. Warn if git dirty\n const dirtyFiles = checkGitDirty(rootDir);\n if (dirtyFiles.length > 0) {\n ctx.ui?.warn?.(`Working tree has ${dirtyFiles.length} uncommitted changes`);\n }\n\n // 3. Build plan\n const plan = buildPlan(mode, packageMap, monorepos, rootDir, { scopedRepos });\n tracker.checkpoint('plan');\n\n if (plan.items.length === 0 && !flags.install) {\n ctx.ui?.info?.('No changes needed — dependencies are already in the requested mode.');\n return { exitCode: 0, result: { mode, changed: 0, dryRun }, meta: { timing: tracker.total() } };\n }\n\n // 4. Dry-run: show plan and exit\n if (dryRun) {\n const result: SwitchResult = { mode, changed: plan.items.length, dryRun: true };\n if (outputJson) {\n ctx.ui?.json?.({ ...result, items: plan.items });\n } else {\n const byRepo = new Map<string, number>();\n for (const item of plan.items) {\n byRepo.set(item.monorepo, (byRepo.get(item.monorepo) ?? 0) + 1);\n }\n const repoLines = [...byRepo.entries()].map(([repo, count]) => `${repo}: ${count} change(s)`);\n ctx.ui?.success?.(`[dry-run] Would switch ${plan.items.length} dependencies to ${mode} mode`, {\n title: 'DevLink — Dry Run',\n sections: [\n { header: 'Changes by repo', items: repoLines },\n { header: 'Note', items: ['No files were modified. Remove --dry-run to apply.'] },\n ],\n timing: tracker.total(),\n });\n }\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n }\n\n // 5. Always create backup (even if no deps change — install cleans node_modules)\n const currentState = loadState(rootDir);\n const modeAtBackup = currentState.currentMode ?? mode;\n const allPackageJsons = monorepos.flatMap(m => m.packagePaths);\n const backup = createBackup(rootDir, allPackageJsons, `pre-switch to ${mode}`, modeAtBackup);\n const backupId = backup.id;\n tracker.checkpoint('backup');\n\n // 6. Apply dep changes (if any)\n let applyResult = { applied: 0, skipped: 0, errors: [] as Array<{ file: string; error: string }> };\n if (plan.items.length > 0) {\n const applyLoader = useLoader(`Switching ${plan.items.length} dependencies to ${mode} mode...`);\n applyLoader.start();\n applyResult = await applyPlan(plan, { dryRun: false });\n applyLoader.succeed(`Applied ${applyResult.applied} change(s)`);\n tracker.checkpoint('apply');\n }\n\n // 7. Update sub-repo pnpm-workspace.yaml with correct cross-repo paths\n const wsLoader = useLoader('Updating sub-repo workspace files...');\n wsLoader.start();\n const wsUpdates = updateWorkspaceYamls(monorepos, packageMap, rootDir);\n const wsChanged = wsUpdates.reduce((sum, u) => sum + u.added.length + u.removed.length, 0);\n wsLoader.succeed(wsChanged > 0\n ? `Updated ${wsUpdates.length} workspace file(s) (${wsChanged} path changes)`\n : 'Workspace files up to date'\n );\n tracker.checkpoint('workspace-yaml');\n\n // 8. Save state\n saveState(rootDir, {\n currentMode: mode,\n lastApplied: new Date().toISOString(),\n frozenAt: currentState.frozenAt,\n });\n\n // 9. Clean stale lockfiles + node_modules in all sub-repos (default: true)\n const shouldClean = flags['clean-locks'] !== false;\n let cleanedLocks = 0;\n let cleanedNodeModules = 0;\n if (shouldClean) {\n const cleanLoader = useLoader('Cleaning stale lockfiles and node_modules...');\n cleanLoader.start();\n for (const mono of monorepos) {\n // Clean lockfile\n const lockPath = join(mono.rootPath, 'pnpm-lock.yaml');\n if (existsSync(lockPath)) {\n try { unlinkSync(lockPath); cleanedLocks++; } catch { /* skip */ }\n }\n // Clean node_modules (contains stale shims with hardcoded paths)\n const nmPath = join(mono.rootPath, 'node_modules');\n if (existsSync(nmPath)) {\n try { rmSync(nmPath, { recursive: true, force: true }); cleanedNodeModules++; } catch { /* skip */ }\n }\n }\n cleanLoader.succeed(\n `Cleaned ${cleanedLocks} lockfile(s), ${cleanedNodeModules} node_modules`\n );\n tracker.checkpoint('clean');\n }\n\n // 10. Install: workspace root first, then per-sub-repo\n const shouldInstall = flags.install === true;\n let installedRepos = 0;\n const installErrors: string[] = [];\n if (shouldInstall) {\n // Phase 1: workspace root install\n const rootLoader = useLoader('Installing workspace root...');\n rootLoader.start();\n try {\n execSync('pnpm install --no-frozen-lockfile', {\n cwd: rootDir,\n stdio: 'pipe',\n timeout: 180_000,\n });\n rootLoader.succeed('Workspace root installed');\n } catch (err) {\n rootLoader.succeed('Workspace root install failed');\n installErrors.push(`root: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`);\n }\n tracker.checkpoint('root-install');\n\n // Phase 2: per-sub-repo install (affected + repos missing lockfile)\n const affectedRepos = new Set(plan.items.map(i => i.monorepo));\n const affectedMonorepos = monorepos.filter(m =>\n affectedRepos.has(m.name) || !existsSync(join(m.rootPath, 'pnpm-lock.yaml'))\n );\n const repoLoader = useLoader(`Installing ${affectedMonorepos.length} sub-repo(s)...`);\n repoLoader.start();\n for (const mono of affectedMonorepos) {\n try {\n execSync('pnpm install --no-frozen-lockfile --prefer-offline', {\n cwd: mono.rootPath,\n stdio: 'pipe',\n timeout: 300_000, // 5 min per sub-repo\n });\n installedRepos++;\n } catch (err) {\n installErrors.push(`${mono.name}: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`);\n }\n }\n repoLoader.succeed(`Installed ${installedRepos}/${affectedMonorepos.length} sub-repo(s)${installErrors.length > 0 ? `, ${installErrors.length} failed` : ''}`);\n tracker.checkpoint('sub-repo-install');\n }\n\n // 11. Output\n const result: SwitchResult = {\n mode,\n changed: applyResult.applied,\n dryRun: false,\n backupId,\n };\n\n if (outputJson) {\n ctx.ui?.json?.({ ...result, cleanedLocks, wsUpdates: wsUpdates.length, installedRepos, installErrors });\n } else {\n const summaryItems = [\n `Mode: ${mode}`,\n `Changed: ${applyResult.applied} dependencies`,\n `Backup: ${backupId}`,\n ];\n if (wsChanged > 0) {\n summaryItems.push(`Workspace YAMLs: ${wsUpdates.length} updated`);\n }\n if (cleanedLocks > 0 || cleanedNodeModules > 0) {\n summaryItems.push(`Cleaned: ${cleanedLocks} lockfile(s), ${cleanedNodeModules} node_modules`);\n }\n if (shouldInstall) {\n summaryItems.push(`Installed: root + ${installedRepos} sub-repo(s)`);\n }\n\n const sections = [\n { header: 'Summary', items: summaryItems },\n ...(applyResult.errors.length > 0\n ? [{ header: 'Errors', items: applyResult.errors.map(e => `${e.file}: ${e.error}`) }]\n : []),\n ...(installErrors.length > 0\n ? [{ header: 'Install errors', items: installErrors }]\n : []),\n ...(!shouldInstall && applyResult.applied > 0\n ? [{ header: 'Next step', items: ['Re-run with --install to complete setup'] }]\n : []),\n ];\n ctx.ui?.success?.(`Switched to ${mode} mode`, {\n title: 'DevLink — Switch',\n sections,\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/switch.ts"],"names":[],"mappings":"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","file":"switch.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, handleError, type PluginContextV3, type CommandResult, type CLIInput } from '@kb-labs/sdk';\nimport { discoverMonorepos, buildPackageMapFiltered, buildPlan, applyPlan, createBackup, loadState, saveState, checkGitDirty, updateWorkspaceYamls } from '@kb-labs/devlink-core';\nimport type { DevlinkMode } from '@kb-labs/devlink-contracts';\nimport { existsSync, unlinkSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\n\ninterface SwitchFlags {\n mode: DevlinkMode;\n 'dry-run'?: boolean;\n repos?: string;\n yes?: boolean;\n json?: boolean;\n ttl?: number;\n install?: boolean;\n 'clean-locks'?: boolean;\n}\n\ninterface SwitchResult {\n mode: DevlinkMode;\n changed: number;\n backupId?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<SwitchFlags>, SwitchResult>({\n id: 'devlink:switch',\n description: 'Switch cross-repo deps between link: and npm mode',\n\n handler: {\n async intent(ctx: PluginContextV3, input: CLIInput<SwitchFlags>) {\n const flags = input.flags;\n const mode = flags.mode;\n const rootDir = ctx.cwd ?? process.cwd();\n const scopedRepos = flags.repos ? flags.repos.split(',').map(s => s.trim()) : undefined;\n const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1000;\n\n let monorepos;\n let packageMap;\n try {\n monorepos = discoverMonorepos(rootDir);\n packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);\n } catch {\n return {\n summary: `Switch dependencies to ${mode ?? '(unknown)'} mode`,\n operations: [{ type: 'update' as const, resource: 'package-json', details: { mode } }],\n };\n }\n\n const plan = buildPlan(mode, packageMap, monorepos, rootDir, { scopedRepos });\n const byRepo = new Map<string, number>();\n for (const item of plan.items) {\n byRepo.set(item.monorepo, (byRepo.get(item.monorepo) ?? 0) + 1);\n }\n\n return {\n summary: `Switch ${plan.items.length} dependencies to ${mode} mode across ${byRepo.size} repo(s)`,\n operations: [...byRepo.entries()].map(([repo, count]) => ({\n type: 'update' as const,\n resource: 'dependencies',\n details: { repo, count, mode },\n })),\n };\n },\n\n async execute(ctx: PluginContextV3, input: CLIInput<SwitchFlags>): Promise<CommandResult<SwitchResult>> {\n const tracker = new TimingTracker();\n const flags = input.flags;\n const mode = flags.mode;\n const outputJson = flags.json ?? false;\n const scopedRepos = flags.repos ? flags.repos.split(',').map(s => s.trim()) : undefined;\n const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1000;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n // 1. Discover\n const discoverLoader = useLoader('Discovering monorepos...');\n discoverLoader.start();\n\n let monorepos;\n let packageMap;\n try {\n monorepos = discoverMonorepos(rootDir);\n packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);\n } catch (err) {\n discoverLoader.fail('Discovery failed');\n handleError(ctx, err, outputJson);\n return { exitCode: 1 };\n }\n discoverLoader.succeed(`Found ${monorepos.length} monorepos, ${Object.keys(packageMap).length} packages`);\n tracker.checkpoint('discovery');\n\n // 2. Warn if git dirty\n const dirtyFiles = checkGitDirty(rootDir);\n if (dirtyFiles.length > 0) {\n ctx.ui?.warn?.(`Working tree has ${dirtyFiles.length} uncommitted changes`);\n }\n\n // 3. Build plan\n const plan = buildPlan(mode, packageMap, monorepos, rootDir, { scopedRepos });\n tracker.checkpoint('plan');\n\n if (plan.items.length === 0 && !flags.install) {\n ctx.ui?.info?.('No changes needed — dependencies are already in the requested mode.');\n return { exitCode: 0, result: { mode, changed: 0 }, meta: { timing: tracker.total() } };\n }\n\n // 4. Always create backup (even if no deps change — install cleans node_modules)\n const currentState = loadState(rootDir);\n const modeAtBackup = currentState.currentMode ?? mode;\n const allPackageJsons = monorepos.flatMap(m => m.packagePaths);\n const backup = createBackup(rootDir, allPackageJsons, `pre-switch to ${mode}`, modeAtBackup);\n const backupId = backup.id;\n tracker.checkpoint('backup');\n\n // 6. Apply dep changes (if any)\n let applyResult = { applied: 0, skipped: 0, errors: [] as Array<{ file: string; error: string }> };\n if (plan.items.length > 0) {\n const applyLoader = useLoader(`Switching ${plan.items.length} dependencies to ${mode} mode...`);\n applyLoader.start();\n applyResult = await applyPlan(plan, { dryRun: false });\n applyLoader.succeed(`Applied ${applyResult.applied} change(s)`);\n tracker.checkpoint('apply');\n }\n\n // 7. Update sub-repo pnpm-workspace.yaml with correct cross-repo paths\n const wsLoader = useLoader('Updating sub-repo workspace files...');\n wsLoader.start();\n const wsUpdates = updateWorkspaceYamls(monorepos, packageMap, rootDir);\n const wsChanged = wsUpdates.reduce((sum, u) => sum + u.added.length + u.removed.length, 0);\n wsLoader.succeed(wsChanged > 0\n ? `Updated ${wsUpdates.length} workspace file(s) (${wsChanged} path changes)`\n : 'Workspace files up to date'\n );\n tracker.checkpoint('workspace-yaml');\n\n // 8. Save state\n saveState(rootDir, {\n currentMode: mode,\n lastApplied: new Date().toISOString(),\n frozenAt: currentState.frozenAt,\n });\n\n // 9. Clean stale lockfiles + node_modules in all sub-repos (default: true)\n const shouldClean = flags['clean-locks'] !== false;\n let cleanedLocks = 0;\n let cleanedNodeModules = 0;\n if (shouldClean) {\n const cleanLoader = useLoader('Cleaning stale lockfiles and node_modules...');\n cleanLoader.start();\n for (const mono of monorepos) {\n // Clean lockfile\n const lockPath = join(mono.rootPath, 'pnpm-lock.yaml');\n if (existsSync(lockPath)) {\n try { unlinkSync(lockPath); cleanedLocks++; } catch { /* skip */ }\n }\n // Clean node_modules (contains stale shims with hardcoded paths)\n const nmPath = join(mono.rootPath, 'node_modules');\n if (existsSync(nmPath)) {\n try { rmSync(nmPath, { recursive: true, force: true }); cleanedNodeModules++; } catch { /* skip */ }\n }\n }\n cleanLoader.succeed(\n `Cleaned ${cleanedLocks} lockfile(s), ${cleanedNodeModules} node_modules`\n );\n tracker.checkpoint('clean');\n }\n\n // 10. Install: workspace root first, then per-sub-repo\n const shouldInstall = flags.install === true;\n let installedRepos = 0;\n const installErrors: string[] = [];\n if (shouldInstall) {\n // Phase 1: workspace root install\n const rootLoader = useLoader('Installing workspace root...');\n rootLoader.start();\n try {\n execSync('pnpm install --no-frozen-lockfile', {\n cwd: rootDir,\n stdio: 'pipe',\n timeout: 180_000,\n });\n rootLoader.succeed('Workspace root installed');\n } catch (err) {\n rootLoader.succeed('Workspace root install failed');\n installErrors.push(`root: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`);\n }\n tracker.checkpoint('root-install');\n\n // Phase 2: per-sub-repo install (affected + repos missing lockfile)\n const affectedRepos = new Set(plan.items.map(i => i.monorepo));\n const affectedMonorepos = monorepos.filter(m =>\n affectedRepos.has(m.name) || !existsSync(join(m.rootPath, 'pnpm-lock.yaml'))\n );\n const repoLoader = useLoader(`Installing ${affectedMonorepos.length} sub-repo(s)...`);\n repoLoader.start();\n for (const mono of affectedMonorepos) {\n try {\n execSync('pnpm install --no-frozen-lockfile --prefer-offline', {\n cwd: mono.rootPath,\n stdio: 'pipe',\n timeout: 300_000, // 5 min per sub-repo\n });\n installedRepos++;\n } catch (err) {\n installErrors.push(`${mono.name}: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`);\n }\n }\n repoLoader.succeed(`Installed ${installedRepos}/${affectedMonorepos.length} sub-repo(s)${installErrors.length > 0 ? `, ${installErrors.length} failed` : ''}`);\n tracker.checkpoint('sub-repo-install');\n }\n\n // 11. Output\n const result: SwitchResult = {\n mode,\n changed: applyResult.applied,\n backupId,\n };\n\n if (outputJson) {\n ctx.ui?.json?.({ ...result, cleanedLocks, wsUpdates: wsUpdates.length, installedRepos, installErrors });\n } else {\n const summaryItems = [\n `Mode: ${mode}`,\n `Changed: ${applyResult.applied} dependencies`,\n `Backup: ${backupId}`,\n ];\n if (wsChanged > 0) {\n summaryItems.push(`Workspace YAMLs: ${wsUpdates.length} updated`);\n }\n if (cleanedLocks > 0 || cleanedNodeModules > 0) {\n summaryItems.push(`Cleaned: ${cleanedLocks} lockfile(s), ${cleanedNodeModules} node_modules`);\n }\n if (shouldInstall) {\n summaryItems.push(`Installed: root + ${installedRepos} sub-repo(s)`);\n }\n\n const sections = [\n { header: 'Summary', items: summaryItems },\n ...(applyResult.errors.length > 0\n ? [{ header: 'Errors', items: applyResult.errors.map(e => `${e.file}: ${e.error}`) }]\n : []),\n ...(installErrors.length > 0\n ? [{ header: 'Install errors', items: installErrors }]\n : []),\n ...(!shouldInstall && applyResult.applied > 0\n ? [{ header: 'Next step', items: ['Re-run with --install to complete setup'] }]\n : []),\n ];\n ctx.ui?.success?.(`Switched to ${mode} mode`, {\n title: 'DevLink — Switch',\n sections,\n timing: tracker.total(),\n });\n }\n\n return { exitCode: 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
@@ -1,4 +1,4 @@
1
- import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
1
+ import { defineCommand, TimingTracker, validationError, useLoader, handleError } from '@kb-labs/sdk';
2
2
  import { getLastBackup, restoreBackup, loadState, saveState } from '@kb-labs/devlink-core';
3
3
 
4
4
  // src/cli/commands/undo.ts
@@ -6,6 +6,14 @@ var undo_default = defineCommand({
6
6
  id: "devlink:undo",
7
7
  description: "Restore previous dependency state from last backup",
8
8
  handler: {
9
+ async intent(_ctx, _input) {
10
+ return {
11
+ summary: "Restore previous dependency state from last backup",
12
+ operations: [
13
+ { type: "update", resource: "package-json-files", details: { source: "last-backup" } }
14
+ ]
15
+ };
16
+ },
9
17
  async execute(ctx, input) {
10
18
  const tracker = new TimingTracker();
11
19
  const flags = input.flags ?? input;
@@ -13,12 +21,20 @@ var undo_default = defineCommand({
13
21
  const rootDir = ctx.cwd ?? process.cwd();
14
22
  const backup = getLastBackup(rootDir);
15
23
  if (!backup) {
16
- ctx.ui?.error?.("No backups found. Run switch first to create a backup.");
24
+ validationError(ctx, "No backups found. Run switch first to create a backup.", void 0, outputJson);
17
25
  return { exitCode: 1 };
18
26
  }
19
27
  const loader = useLoader(`Restoring from backup ${backup.id}...`);
20
28
  loader.start();
21
- const { restored, errors } = restoreBackup(rootDir, backup.id);
29
+ let restored;
30
+ let errors;
31
+ try {
32
+ ({ restored, errors } = restoreBackup(rootDir, backup.id));
33
+ } catch (err) {
34
+ loader.fail("Restore failed");
35
+ handleError(ctx, err, outputJson);
36
+ return { exitCode: 1 };
37
+ }
22
38
  loader.succeed(`Restored ${restored} file(s)`);
23
39
  tracker.checkpoint("restore");
24
40
  const currentState = loadState(rootDir);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/undo.ts"],"names":[],"mappings":";;;;AAmBA,IAAO,eAAQ,aAAA,CAA8C;AAAA,EAC3D,EAAA,EAAI,cAAA;AAAA,EACJ,WAAA,EAAa,oDAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAsD;AACxF,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,EAAc;AAClC,MAAA,MAAM,KAAA,GAAS,MAAM,KAAA,IAAS,KAAA;AAC9B,MAAA,MAAM,UAAA,GAAa,MAAM,IAAA,IAAQ,KAAA;AAEjC,MAAA,MAAM,OAAA,GAAU,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEvC,MAAA,MAAM,MAAA,GAAS,cAAc,OAAO,CAAA;AACpC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,GAAA,CAAI,EAAA,EAAI,QAAQ,wDAAwD,CAAA;AACxE,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,CAAA,sBAAA,EAAyB,MAAA,CAAO,EAAE,CAAA,GAAA,CAAK,CAAA;AAChE,MAAA,MAAA,CAAO,KAAA,EAAM;AAEb,MAAA,MAAM,EAAE,QAAA,EAAU,MAAA,KAAW,aAAA,CAAc,OAAA,EAAS,OAAO,EAAE,CAAA;AAC7D,MAAA,MAAA,CAAO,OAAA,CAAQ,CAAA,SAAA,EAAY,QAAQ,CAAA,QAAA,CAAU,CAAA;AAC7C,MAAA,OAAA,CAAQ,WAAW,SAAS,CAAA;AAG5B,MAAA,MAAM,YAAA,GAAe,UAAU,OAAO,CAAA;AACtC,MAAA,SAAA,CAAU,OAAA,EAAS;AAAA,QACjB,GAAG,YAAA;AAAA,QACH,aAAa,MAAA,CAAO,YAAA;AAAA,QACpB,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC,CAAA;AAED,MAAA,MAAM,SAAqB,EAAE,QAAA,EAAU,QAAA,EAAU,MAAA,CAAO,IAAI,MAAA,EAAO;AAEnE,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,MAAM,CAAA;AAAA,MACvB,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,IAAI,OAAA,GAAU,CAAA,4BAAA,EAA+B,MAAA,CAAO,YAAA,IAAgB,SAAS,CAAA,CAAA,CAAA,EAAK;AAAA,UACpF,KAAA,EAAO,qBAAA;AAAA,UACP,QAAA,EAAU;AAAA,YACR;AAAA,cACE,MAAA,EAAQ,SAAA;AAAA,cACR,KAAA,EAAO;AAAA,gBACL,CAAA,WAAA,EAAc,OAAO,EAAE,CAAA,CAAA;AAAA,gBACvB,CAAA,SAAA,EAAY,OAAO,SAAS,CAAA,CAAA;AAAA,gBAC5B,mBAAmB,QAAQ,CAAA;AAAA;AAC7B,aACF;AAAA,YACA,GAAI,MAAA,CAAO,MAAA,GAAS,CAAA,GAAI,CAAC,EAAE,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,MAAA,EAAQ,CAAA,GAAI,EAAC;AAAA,YACjE,EAAE,MAAA,EAAQ,WAAA,EAAa,KAAA,EAAO,CAAC,mCAAmC,CAAA;AAAE,WACtE;AAAA,UACA,MAAA,EAAQ,QAAQ,KAAA;AAAM,SACvB,CAAA;AAAA,MACH;AAEA,MAAA,OAAO,EAAE,QAAA,EAAU,MAAA,CAAO,MAAA,GAAS,IAAI,CAAA,GAAI,CAAA,EAAG,MAAA,EAAQ,IAAA,EAAM,EAAE,MAAA,EAAQ,OAAA,CAAQ,KAAA,IAAQ,EAAE;AAAA,IAC1F;AAAA;AAEJ,CAAC","file":"undo.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { getLastBackup, restoreBackup, saveState, loadState } from '@kb-labs/devlink-core';\n\ninterface UndoFlags {\n json?: boolean;\n}\n\ninterface UndoInput {\n argv?: string[];\n flags?: UndoFlags;\n json?: boolean;\n}\n\ninterface UndoResult {\n restored: number;\n backupId: string;\n errors: string[];\n}\n\nexport default defineCommand<unknown, UndoInput, UndoResult>({\n id: 'devlink:undo',\n description: 'Restore previous dependency state from last backup',\n\n handler: {\n async execute(ctx: PluginContextV3, input: UndoInput): Promise<CommandResult<UndoResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as UndoFlags;\n const outputJson = flags.json ?? false;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const backup = getLastBackup(rootDir);\n if (!backup) {\n ctx.ui?.error?.('No backups found. Run switch first to create a backup.');\n return { exitCode: 1 };\n }\n\n const loader = useLoader(`Restoring from backup ${backup.id}...`);\n loader.start();\n\n const { restored, errors } = restoreBackup(rootDir, backup.id);\n loader.succeed(`Restored ${restored} file(s)`);\n tracker.checkpoint('restore');\n\n // Update state to backup's previous mode\n const currentState = loadState(rootDir);\n saveState(rootDir, {\n ...currentState,\n currentMode: backup.modeAtBackup,\n lastApplied: new Date().toISOString(),\n });\n\n const result: UndoResult = { restored, backupId: backup.id, errors };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n ctx.ui?.success?.(`Restored from backup (mode: ${backup.modeAtBackup ?? 'unknown'})`, {\n title: 'DevLink — Undo',\n sections: [\n {\n header: 'Summary',\n items: [\n `Backup ID: ${backup.id}`,\n `Created: ${backup.timestamp}`,\n `Restored files: ${restored}`,\n ],\n },\n ...(errors.length > 0 ? [{ header: 'Errors', items: errors }] : []),\n { header: 'Next step', items: ['Run pnpm install to apply changes'] },\n ],\n timing: tracker.total(),\n });\n }\n\n return { exitCode: errors.length > 0 ? 1 : 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/undo.ts"],"names":[],"mappings":"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","file":"undo.js","sourcesContent":["import { defineCommand, useLoader, TimingTracker, validationError, handleError, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { getLastBackup, restoreBackup, saveState, loadState } from '@kb-labs/devlink-core';\n\ninterface UndoFlags {\n json?: boolean;\n}\n\ninterface UndoInput {\n argv?: string[];\n flags?: UndoFlags;\n json?: boolean;\n}\n\ninterface UndoResult {\n restored: number;\n backupId: string;\n errors: string[];\n}\n\nexport default defineCommand<unknown, UndoInput, UndoResult>({\n id: 'devlink:undo',\n description: 'Restore previous dependency state from last backup',\n\n handler: {\n async intent(_ctx: PluginContextV3, _input: UndoInput) {\n return {\n summary: 'Restore previous dependency state from last backup',\n operations: [\n { type: 'update' as const, resource: 'package-json-files', details: { source: 'last-backup' } },\n ],\n };\n },\n\n async execute(ctx: PluginContextV3, input: UndoInput): Promise<CommandResult<UndoResult>> {\n const tracker = new TimingTracker();\n const flags = (input.flags ?? input) as UndoFlags;\n const outputJson = flags.json ?? false;\n\n const rootDir = ctx.cwd ?? process.cwd();\n\n const backup = getLastBackup(rootDir);\n if (!backup) {\n validationError(ctx, 'No backups found. Run switch first to create a backup.', undefined, outputJson);\n return { exitCode: 1 };\n }\n\n const loader = useLoader(`Restoring from backup ${backup.id}...`);\n loader.start();\n\n let restored: number;\n let errors: string[];\n try {\n ({ restored, errors } = restoreBackup(rootDir, backup.id));\n } catch (err) {\n loader.fail('Restore failed');\n handleError(ctx, err, outputJson);\n return { exitCode: 1 };\n }\n loader.succeed(`Restored ${restored} file(s)`);\n tracker.checkpoint('restore');\n\n // Update state to backup's previous mode\n const currentState = loadState(rootDir);\n saveState(rootDir, {\n ...currentState,\n currentMode: backup.modeAtBackup,\n lastApplied: new Date().toISOString(),\n });\n\n const result: UndoResult = { restored, backupId: backup.id, errors };\n\n if (outputJson) {\n ctx.ui?.json?.(result);\n } else {\n ctx.ui?.success?.(`Restored from backup (mode: ${backup.modeAtBackup ?? 'unknown'})`, {\n title: 'DevLink — Undo',\n sections: [\n {\n header: 'Summary',\n items: [\n `Backup ID: ${backup.id}`,\n `Created: ${backup.timestamp}`,\n `Restored files: ${restored}`,\n ],\n },\n ...(errors.length > 0 ? [{ header: 'Errors', items: errors }] : []),\n { header: 'Next step', items: ['Run pnpm install to apply changes'] },\n ],\n timing: tracker.total(),\n });\n }\n\n return { exitCode: errors.length > 0 ? 1 : 0, result, meta: { timing: tracker.total() } };\n },\n },\n});\n"]}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export { default, default as manifest } from './manifest.js';
2
- import '@kb-labs/perm-presets';
2
+ import '@kb-labs/plugin-contracts';
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ var manifest = {
18
18
  version: "1.0.0",
19
19
  display: {
20
20
  name: "DevLink",
21
- description: "Manage cross-repo link: \u2194 npm dependencies for KB Labs monorepos.",
21
+ description: "Cross-repo link: dependency management",
22
22
  tags: ["monorepo", "devlink", "dependencies", "publish", "local-dev"]
23
23
  },
24
24
  platform: {
@@ -26,14 +26,17 @@ var manifest = {
26
26
  optional: []
27
27
  },
28
28
  cli: {
29
+ groupMeta: [
30
+ { path: "devlink", describe: "Cross-repo link: dependency management" }
31
+ ],
29
32
  commands: [
30
33
  {
31
- id: "switch",
32
- group: "devlink",
33
- describe: "Switch all cross-repo deps between link: (local) and npm (CI/CD) mode",
34
+ path: "devlink switch",
35
+ category: "Mode",
36
+ describe: "Switch deps between local link: and npm (CI/CD) mode",
37
+ operationType: "mutate",
34
38
  longDescription: "Replaces all cross-repo @kb-labs/* dependencies across monorepos. Creates a backup before applying. Run pnpm install after switching.",
35
39
  handler: "./cli/commands/switch.js#default",
36
- handlerPath: "./cli/commands/switch.js",
37
40
  flags: defineCommandFlags(switchFlags),
38
41
  examples: generateExamples("switch", "devlink", [
39
42
  { description: "Switch to npm mode (CI/CD)", flags: { mode: "npm" } },
@@ -44,12 +47,12 @@ var manifest = {
44
47
  permissions: pluginPermissions
45
48
  },
46
49
  {
47
- id: "status",
48
- group: "devlink",
50
+ path: "devlink status",
51
+ category: "Mode",
49
52
  describe: "Show current state of cross-repo dependencies",
53
+ operationType: "read",
50
54
  longDescription: "Displays the current linking mode, counts of link: vs npm dependencies, and any discrepancies across all monorepos.",
51
55
  handler: "./cli/commands/status.js#default",
52
- handlerPath: "./cli/commands/status.js",
53
56
  flags: defineCommandFlags(statusFlags),
54
57
  examples: generateExamples("status", "devlink", [
55
58
  { description: "Show summary status", flags: {} },
@@ -59,12 +62,12 @@ var manifest = {
59
62
  permissions: pluginPermissions
60
63
  },
61
64
  {
62
- id: "plan",
63
- group: "devlink",
65
+ path: "devlink plan",
66
+ category: "Mode",
64
67
  describe: "Preview what would change when switching mode",
68
+ operationType: "read",
65
69
  longDescription: "Shows all dependency changes that would be made without applying them. Useful for reviewing before running switch.",
66
70
  handler: "./cli/commands/plan.js#default",
67
- handlerPath: "./cli/commands/plan.js",
68
71
  flags: defineCommandFlags(planFlags),
69
72
  examples: generateExamples("plan", "devlink", [
70
73
  { description: "Plan switch to local mode", flags: { mode: "local" } },
@@ -74,12 +77,12 @@ var manifest = {
74
77
  permissions: pluginPermissions
75
78
  },
76
79
  {
77
- id: "freeze",
78
- group: "devlink",
80
+ path: "devlink freeze",
81
+ category: "State",
79
82
  describe: "Freeze current dependency state to lock file",
83
+ operationType: "mutate",
80
84
  longDescription: "Saves a snapshot of current dependency mode to .kb/devlink/lock.json. Use to record a stable known-good state.",
81
85
  handler: "./cli/commands/freeze.js#default",
82
- handlerPath: "./cli/commands/freeze.js",
83
86
  flags: defineCommandFlags(freezeFlags),
84
87
  examples: generateExamples("freeze", "devlink", [
85
88
  { description: "Freeze current state", flags: {} },
@@ -88,12 +91,12 @@ var manifest = {
88
91
  permissions: pluginPermissions
89
92
  },
90
93
  {
91
- id: "undo",
92
- group: "devlink",
94
+ path: "devlink undo",
95
+ category: "State",
93
96
  describe: "Restore previous dependency state from last backup",
97
+ operationType: "mutate",
94
98
  longDescription: "Restores package.json files from the most recent backup created by switch. Run pnpm install after undoing.",
95
99
  handler: "./cli/commands/undo.js#default",
96
- handlerPath: "./cli/commands/undo.js",
97
100
  flags: defineCommandFlags(undoFlags),
98
101
  examples: generateExamples("undo", "devlink", [
99
102
  { description: "Undo last switch", flags: {} },
@@ -102,12 +105,12 @@ var manifest = {
102
105
  permissions: pluginPermissions
103
106
  },
104
107
  {
105
- id: "backups",
106
- group: "devlink",
108
+ path: "devlink backups",
109
+ category: "State",
107
110
  describe: "List and restore backups",
111
+ operationType: "read",
108
112
  longDescription: "Lists all available backups. Use --restore <id> to restore a specific backup.",
109
113
  handler: "./cli/commands/backups.js#default",
110
- handlerPath: "./cli/commands/backups.js",
111
114
  flags: defineCommandFlags(backupsFlags),
112
115
  examples: generateExamples("backups", "devlink", [
113
116
  { description: "List all backups", flags: {} },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { defineCommandFlags, combinePermissions, generateExamples } from '@kb-labs/sdk';\nimport {\n switchFlags,\n statusFlags,\n planFlags,\n freezeFlags,\n undoFlags,\n backupsFlags,\n DEVLINK_CACHE_PREFIX,\n} from '@kb-labs/devlink-contracts';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'readWrite',\n allow: ['**/package.json', '.kb/devlink/**', '**/pnpm-workspace.yaml'],\n })\n .withPlatform({\n cache: [DEVLINK_CACHE_PREFIX],\n })\n .withQuotas({\n timeoutMs: 1800000, // 30 min — switch --install runs pnpm install in 29 sub-repos\n memoryMb: 512,\n })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/devlink',\n version: '1.0.0',\n\n display: {\n name: 'DevLink',\n description: 'Manage cross-repo link: npm dependencies for KB Labs monorepos.',\n tags: ['monorepo', 'devlink', 'dependencies', 'publish', 'local-dev'],\n },\n\n platform: {\n requires: ['storage'],\n optional: [],\n },\n\n cli: {\n commands: [\n {\n id: 'switch',\n group: 'devlink',\n describe: 'Switch all cross-repo deps between link: (local) and npm (CI/CD) mode',\n longDescription:\n 'Replaces all cross-repo @kb-labs/* dependencies across monorepos. ' +\n 'Creates a backup before applying. Run pnpm install after switching.',\n\n handler: './cli/commands/switch.js#default',\n handlerPath: './cli/commands/switch.js',\n\n flags: defineCommandFlags(switchFlags),\n\n examples: generateExamples('switch', 'devlink', [\n { description: 'Switch to npm mode (CI/CD)', flags: { mode: 'npm' } },\n { description: 'Switch to local mode (development)', flags: { mode: 'local' } },\n { description: 'Preview changes without applying', flags: { mode: 'local', 'dry-run': true } },\n { description: 'Switch specific repos only', flags: { mode: 'npm', repos: 'kb-labs-cli,kb-labs-core' } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'status',\n group: 'devlink',\n describe: 'Show current state of cross-repo dependencies',\n longDescription:\n 'Displays the current linking mode, counts of link: vs npm dependencies, ' +\n 'and any discrepancies across all monorepos.',\n\n handler: './cli/commands/status.js#default',\n handlerPath: './cli/commands/status.js',\n\n flags: defineCommandFlags(statusFlags),\n\n examples: generateExamples('status', 'devlink', [\n { description: 'Show summary status', flags: {} },\n { description: 'Verbose output with all deps', flags: { verbose: true } },\n { description: 'JSON output for scripting', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'plan',\n group: 'devlink',\n describe: 'Preview what would change when switching mode',\n longDescription:\n 'Shows all dependency changes that would be made without applying them. ' +\n 'Useful for reviewing before running switch.',\n\n handler: './cli/commands/plan.js#default',\n handlerPath: './cli/commands/plan.js',\n\n flags: defineCommandFlags(planFlags),\n\n examples: generateExamples('plan', 'devlink', [\n { description: 'Plan switch to local mode', flags: { mode: 'local' } },\n { description: 'Plan switch to npm mode', flags: { mode: 'npm' } },\n { description: 'JSON output for scripting', flags: { mode: 'npm', json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'freeze',\n group: 'devlink',\n describe: 'Freeze current dependency state to lock file',\n longDescription:\n 'Saves a snapshot of current dependency mode to .kb/devlink/lock.json. ' +\n 'Use to record a stable known-good state.',\n\n handler: './cli/commands/freeze.js#default',\n handlerPath: './cli/commands/freeze.js',\n\n flags: defineCommandFlags(freezeFlags),\n\n examples: generateExamples('freeze', 'devlink', [\n { description: 'Freeze current state', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'undo',\n group: 'devlink',\n describe: 'Restore previous dependency state from last backup',\n longDescription:\n 'Restores package.json files from the most recent backup created by switch. ' +\n 'Run pnpm install after undoing.',\n\n handler: './cli/commands/undo.js#default',\n handlerPath: './cli/commands/undo.js',\n\n flags: defineCommandFlags(undoFlags),\n\n examples: generateExamples('undo', 'devlink', [\n { description: 'Undo last switch', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'backups',\n group: 'devlink',\n describe: 'List and restore backups',\n longDescription:\n 'Lists all available backups. Use --restore <id> to restore a specific backup.',\n\n handler: './cli/commands/backups.js#default',\n handlerPath: './cli/commands/backups.js',\n\n flags: defineCommandFlags(backupsFlags),\n\n examples: generateExamples('backups', 'devlink', [\n { description: 'List all backups', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n { description: 'Restore specific backup', flags: { restore: '<backup-id>' } },\n ]),\n\n permissions: pluginPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
1
+ {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { defineCommandFlags, combinePermissions, generateExamples } from '@kb-labs/sdk';\nimport {\n switchFlags,\n statusFlags,\n planFlags,\n freezeFlags,\n undoFlags,\n backupsFlags,\n DEVLINK_CACHE_PREFIX,\n} from '@kb-labs/devlink-contracts';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'readWrite',\n allow: ['**/package.json', '.kb/devlink/**', '**/pnpm-workspace.yaml'],\n })\n .withPlatform({\n cache: [DEVLINK_CACHE_PREFIX],\n })\n .withQuotas({\n timeoutMs: 1800000, // 30 min — switch --install runs pnpm install in 29 sub-repos\n memoryMb: 512,\n })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/devlink',\n version: '1.0.0',\n\n display: {\n name: 'DevLink',\n description: 'Cross-repo link: dependency management',\n tags: ['monorepo', 'devlink', 'dependencies', 'publish', 'local-dev'],\n },\n\n platform: {\n requires: ['storage'],\n optional: [],\n },\n\n cli: {\n groupMeta: [\n { path: 'devlink', describe: 'Cross-repo link: dependency management' },\n ],\n commands: [\n {\n path: 'devlink switch',\n category: 'Mode',\n describe: 'Switch deps between local link: and npm (CI/CD) mode',\n operationType: 'mutate' as const,\n longDescription:\n 'Replaces all cross-repo @kb-labs/* dependencies across monorepos. ' +\n 'Creates a backup before applying. Run pnpm install after switching.',\n\n handler: './cli/commands/switch.js#default',\n\n flags: defineCommandFlags(switchFlags),\n\n examples: generateExamples('switch', 'devlink', [\n { description: 'Switch to npm mode (CI/CD)', flags: { mode: 'npm' } },\n { description: 'Switch to local mode (development)', flags: { mode: 'local' } },\n { description: 'Preview changes without applying', flags: { mode: 'local', 'dry-run': true } },\n { description: 'Switch specific repos only', flags: { mode: 'npm', repos: 'kb-labs-cli,kb-labs-core' } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink status',\n category: 'Mode',\n describe: 'Show current state of cross-repo dependencies',\n operationType: 'read' as const,\n longDescription:\n 'Displays the current linking mode, counts of link: vs npm dependencies, ' +\n 'and any discrepancies across all monorepos.',\n\n handler: './cli/commands/status.js#default',\n\n flags: defineCommandFlags(statusFlags),\n\n examples: generateExamples('status', 'devlink', [\n { description: 'Show summary status', flags: {} },\n { description: 'Verbose output with all deps', flags: { verbose: true } },\n { description: 'JSON output for scripting', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink plan',\n category: 'Mode',\n describe: 'Preview what would change when switching mode',\n operationType: 'read' as const,\n longDescription:\n 'Shows all dependency changes that would be made without applying them. ' +\n 'Useful for reviewing before running switch.',\n\n handler: './cli/commands/plan.js#default',\n\n flags: defineCommandFlags(planFlags),\n\n examples: generateExamples('plan', 'devlink', [\n { description: 'Plan switch to local mode', flags: { mode: 'local' } },\n { description: 'Plan switch to npm mode', flags: { mode: 'npm' } },\n { description: 'JSON output for scripting', flags: { mode: 'npm', json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink freeze',\n category: 'State',\n describe: 'Freeze current dependency state to lock file',\n operationType: 'mutate' as const,\n longDescription:\n 'Saves a snapshot of current dependency mode to .kb/devlink/lock.json. ' +\n 'Use to record a stable known-good state.',\n\n handler: './cli/commands/freeze.js#default',\n\n flags: defineCommandFlags(freezeFlags),\n\n examples: generateExamples('freeze', 'devlink', [\n { description: 'Freeze current state', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink undo',\n category: 'State',\n describe: 'Restore previous dependency state from last backup',\n operationType: 'mutate' as const,\n longDescription:\n 'Restores package.json files from the most recent backup created by switch. ' +\n 'Run pnpm install after undoing.',\n\n handler: './cli/commands/undo.js#default',\n\n flags: defineCommandFlags(undoFlags),\n\n examples: generateExamples('undo', 'devlink', [\n { description: 'Undo last switch', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink backups',\n category: 'State',\n describe: 'List and restore backups',\n operationType: 'read' as const,\n longDescription:\n 'Lists all available backups. Use --restore <id> to restore a specific backup.',\n\n handler: './cli/commands/backups.js#default',\n\n flags: defineCommandFlags(backupsFlags),\n\n examples: generateExamples('backups', 'devlink', [\n { description: 'List all backups', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n { description: 'Restore specific backup', flags: { restore: '<backup-id>' } },\n ]),\n\n permissions: pluginPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
@@ -1,4 +1,4 @@
1
- import * as _kb_labs_perm_presets from '@kb-labs/perm-presets';
1
+ import * as _kb_labs_plugin_contracts from '@kb-labs/plugin-contracts';
2
2
 
3
3
  declare const manifest: {
4
4
  schema: string;
@@ -14,13 +14,17 @@ declare const manifest: {
14
14
  optional: never[];
15
15
  };
16
16
  cli: {
17
- commands: {
18
- id: string;
19
- group: string;
17
+ groupMeta: {
18
+ path: string;
20
19
  describe: string;
20
+ }[];
21
+ commands: ({
22
+ path: string;
23
+ category: string;
24
+ describe: string;
25
+ operationType: "mutate";
21
26
  longDescription: string;
22
27
  handler: string;
23
- handlerPath: string;
24
28
  flags: {
25
29
  name: string;
26
30
  type: "string" | "boolean" | "number" | "array";
@@ -31,10 +35,28 @@ declare const manifest: {
31
35
  required?: boolean;
32
36
  }[];
33
37
  examples: string[];
34
- permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
35
- }[];
38
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
39
+ } | {
40
+ path: string;
41
+ category: string;
42
+ describe: string;
43
+ operationType: "read";
44
+ longDescription: string;
45
+ handler: string;
46
+ flags: {
47
+ name: string;
48
+ type: "string" | "boolean" | "number" | "array";
49
+ alias?: string;
50
+ default?: unknown;
51
+ description?: string;
52
+ choices?: string[];
53
+ required?: boolean;
54
+ }[];
55
+ examples: string[];
56
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
57
+ })[];
36
58
  };
37
- permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
59
+ permissions: _kb_labs_plugin_contracts.PermissionSpec;
38
60
  };
39
61
 
40
62
  export { manifest as default, manifest };
package/dist/manifest.js CHANGED
@@ -18,7 +18,7 @@ var manifest = {
18
18
  version: "1.0.0",
19
19
  display: {
20
20
  name: "DevLink",
21
- description: "Manage cross-repo link: \u2194 npm dependencies for KB Labs monorepos.",
21
+ description: "Cross-repo link: dependency management",
22
22
  tags: ["monorepo", "devlink", "dependencies", "publish", "local-dev"]
23
23
  },
24
24
  platform: {
@@ -26,14 +26,17 @@ var manifest = {
26
26
  optional: []
27
27
  },
28
28
  cli: {
29
+ groupMeta: [
30
+ { path: "devlink", describe: "Cross-repo link: dependency management" }
31
+ ],
29
32
  commands: [
30
33
  {
31
- id: "switch",
32
- group: "devlink",
33
- describe: "Switch all cross-repo deps between link: (local) and npm (CI/CD) mode",
34
+ path: "devlink switch",
35
+ category: "Mode",
36
+ describe: "Switch deps between local link: and npm (CI/CD) mode",
37
+ operationType: "mutate",
34
38
  longDescription: "Replaces all cross-repo @kb-labs/* dependencies across monorepos. Creates a backup before applying. Run pnpm install after switching.",
35
39
  handler: "./cli/commands/switch.js#default",
36
- handlerPath: "./cli/commands/switch.js",
37
40
  flags: defineCommandFlags(switchFlags),
38
41
  examples: generateExamples("switch", "devlink", [
39
42
  { description: "Switch to npm mode (CI/CD)", flags: { mode: "npm" } },
@@ -44,12 +47,12 @@ var manifest = {
44
47
  permissions: pluginPermissions
45
48
  },
46
49
  {
47
- id: "status",
48
- group: "devlink",
50
+ path: "devlink status",
51
+ category: "Mode",
49
52
  describe: "Show current state of cross-repo dependencies",
53
+ operationType: "read",
50
54
  longDescription: "Displays the current linking mode, counts of link: vs npm dependencies, and any discrepancies across all monorepos.",
51
55
  handler: "./cli/commands/status.js#default",
52
- handlerPath: "./cli/commands/status.js",
53
56
  flags: defineCommandFlags(statusFlags),
54
57
  examples: generateExamples("status", "devlink", [
55
58
  { description: "Show summary status", flags: {} },
@@ -59,12 +62,12 @@ var manifest = {
59
62
  permissions: pluginPermissions
60
63
  },
61
64
  {
62
- id: "plan",
63
- group: "devlink",
65
+ path: "devlink plan",
66
+ category: "Mode",
64
67
  describe: "Preview what would change when switching mode",
68
+ operationType: "read",
65
69
  longDescription: "Shows all dependency changes that would be made without applying them. Useful for reviewing before running switch.",
66
70
  handler: "./cli/commands/plan.js#default",
67
- handlerPath: "./cli/commands/plan.js",
68
71
  flags: defineCommandFlags(planFlags),
69
72
  examples: generateExamples("plan", "devlink", [
70
73
  { description: "Plan switch to local mode", flags: { mode: "local" } },
@@ -74,12 +77,12 @@ var manifest = {
74
77
  permissions: pluginPermissions
75
78
  },
76
79
  {
77
- id: "freeze",
78
- group: "devlink",
80
+ path: "devlink freeze",
81
+ category: "State",
79
82
  describe: "Freeze current dependency state to lock file",
83
+ operationType: "mutate",
80
84
  longDescription: "Saves a snapshot of current dependency mode to .kb/devlink/lock.json. Use to record a stable known-good state.",
81
85
  handler: "./cli/commands/freeze.js#default",
82
- handlerPath: "./cli/commands/freeze.js",
83
86
  flags: defineCommandFlags(freezeFlags),
84
87
  examples: generateExamples("freeze", "devlink", [
85
88
  { description: "Freeze current state", flags: {} },
@@ -88,12 +91,12 @@ var manifest = {
88
91
  permissions: pluginPermissions
89
92
  },
90
93
  {
91
- id: "undo",
92
- group: "devlink",
94
+ path: "devlink undo",
95
+ category: "State",
93
96
  describe: "Restore previous dependency state from last backup",
97
+ operationType: "mutate",
94
98
  longDescription: "Restores package.json files from the most recent backup created by switch. Run pnpm install after undoing.",
95
99
  handler: "./cli/commands/undo.js#default",
96
- handlerPath: "./cli/commands/undo.js",
97
100
  flags: defineCommandFlags(undoFlags),
98
101
  examples: generateExamples("undo", "devlink", [
99
102
  { description: "Undo last switch", flags: {} },
@@ -102,12 +105,12 @@ var manifest = {
102
105
  permissions: pluginPermissions
103
106
  },
104
107
  {
105
- id: "backups",
106
- group: "devlink",
108
+ path: "devlink backups",
109
+ category: "State",
107
110
  describe: "List and restore backups",
111
+ operationType: "read",
108
112
  longDescription: "Lists all available backups. Use --restore <id> to restore a specific backup.",
109
113
  handler: "./cli/commands/backups.js#default",
110
- handlerPath: "./cli/commands/backups.js",
111
114
  flags: defineCommandFlags(backupsFlags),
112
115
  examples: generateExamples("backups", "devlink", [
113
116
  { description: "List all backups", flags: {} },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":"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","file":"manifest.js","sourcesContent":["import { defineCommandFlags, combinePermissions, generateExamples } from '@kb-labs/sdk';\nimport {\n switchFlags,\n statusFlags,\n planFlags,\n freezeFlags,\n undoFlags,\n backupsFlags,\n DEVLINK_CACHE_PREFIX,\n} from '@kb-labs/devlink-contracts';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'readWrite',\n allow: ['**/package.json', '.kb/devlink/**', '**/pnpm-workspace.yaml'],\n })\n .withPlatform({\n cache: [DEVLINK_CACHE_PREFIX],\n })\n .withQuotas({\n timeoutMs: 1800000, // 30 min — switch --install runs pnpm install in 29 sub-repos\n memoryMb: 512,\n })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/devlink',\n version: '1.0.0',\n\n display: {\n name: 'DevLink',\n description: 'Manage cross-repo link: npm dependencies for KB Labs monorepos.',\n tags: ['monorepo', 'devlink', 'dependencies', 'publish', 'local-dev'],\n },\n\n platform: {\n requires: ['storage'],\n optional: [],\n },\n\n cli: {\n commands: [\n {\n id: 'switch',\n group: 'devlink',\n describe: 'Switch all cross-repo deps between link: (local) and npm (CI/CD) mode',\n longDescription:\n 'Replaces all cross-repo @kb-labs/* dependencies across monorepos. ' +\n 'Creates a backup before applying. Run pnpm install after switching.',\n\n handler: './cli/commands/switch.js#default',\n handlerPath: './cli/commands/switch.js',\n\n flags: defineCommandFlags(switchFlags),\n\n examples: generateExamples('switch', 'devlink', [\n { description: 'Switch to npm mode (CI/CD)', flags: { mode: 'npm' } },\n { description: 'Switch to local mode (development)', flags: { mode: 'local' } },\n { description: 'Preview changes without applying', flags: { mode: 'local', 'dry-run': true } },\n { description: 'Switch specific repos only', flags: { mode: 'npm', repos: 'kb-labs-cli,kb-labs-core' } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'status',\n group: 'devlink',\n describe: 'Show current state of cross-repo dependencies',\n longDescription:\n 'Displays the current linking mode, counts of link: vs npm dependencies, ' +\n 'and any discrepancies across all monorepos.',\n\n handler: './cli/commands/status.js#default',\n handlerPath: './cli/commands/status.js',\n\n flags: defineCommandFlags(statusFlags),\n\n examples: generateExamples('status', 'devlink', [\n { description: 'Show summary status', flags: {} },\n { description: 'Verbose output with all deps', flags: { verbose: true } },\n { description: 'JSON output for scripting', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'plan',\n group: 'devlink',\n describe: 'Preview what would change when switching mode',\n longDescription:\n 'Shows all dependency changes that would be made without applying them. ' +\n 'Useful for reviewing before running switch.',\n\n handler: './cli/commands/plan.js#default',\n handlerPath: './cli/commands/plan.js',\n\n flags: defineCommandFlags(planFlags),\n\n examples: generateExamples('plan', 'devlink', [\n { description: 'Plan switch to local mode', flags: { mode: 'local' } },\n { description: 'Plan switch to npm mode', flags: { mode: 'npm' } },\n { description: 'JSON output for scripting', flags: { mode: 'npm', json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'freeze',\n group: 'devlink',\n describe: 'Freeze current dependency state to lock file',\n longDescription:\n 'Saves a snapshot of current dependency mode to .kb/devlink/lock.json. ' +\n 'Use to record a stable known-good state.',\n\n handler: './cli/commands/freeze.js#default',\n handlerPath: './cli/commands/freeze.js',\n\n flags: defineCommandFlags(freezeFlags),\n\n examples: generateExamples('freeze', 'devlink', [\n { description: 'Freeze current state', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'undo',\n group: 'devlink',\n describe: 'Restore previous dependency state from last backup',\n longDescription:\n 'Restores package.json files from the most recent backup created by switch. ' +\n 'Run pnpm install after undoing.',\n\n handler: './cli/commands/undo.js#default',\n handlerPath: './cli/commands/undo.js',\n\n flags: defineCommandFlags(undoFlags),\n\n examples: generateExamples('undo', 'devlink', [\n { description: 'Undo last switch', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n id: 'backups',\n group: 'devlink',\n describe: 'List and restore backups',\n longDescription:\n 'Lists all available backups. Use --restore <id> to restore a specific backup.',\n\n handler: './cli/commands/backups.js#default',\n handlerPath: './cli/commands/backups.js',\n\n flags: defineCommandFlags(backupsFlags),\n\n examples: generateExamples('backups', 'devlink', [\n { description: 'List all backups', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n { description: 'Restore specific backup', flags: { restore: '<backup-id>' } },\n ]),\n\n permissions: pluginPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
1
+ {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":"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","file":"manifest.js","sourcesContent":["import { defineCommandFlags, combinePermissions, generateExamples } from '@kb-labs/sdk';\nimport {\n switchFlags,\n statusFlags,\n planFlags,\n freezeFlags,\n undoFlags,\n backupsFlags,\n DEVLINK_CACHE_PREFIX,\n} from '@kb-labs/devlink-contracts';\n\nconst pluginPermissions = combinePermissions()\n .withFs({\n mode: 'readWrite',\n allow: ['**/package.json', '.kb/devlink/**', '**/pnpm-workspace.yaml'],\n })\n .withPlatform({\n cache: [DEVLINK_CACHE_PREFIX],\n })\n .withQuotas({\n timeoutMs: 1800000, // 30 min — switch --install runs pnpm install in 29 sub-repos\n memoryMb: 512,\n })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/devlink',\n version: '1.0.0',\n\n display: {\n name: 'DevLink',\n description: 'Cross-repo link: dependency management',\n tags: ['monorepo', 'devlink', 'dependencies', 'publish', 'local-dev'],\n },\n\n platform: {\n requires: ['storage'],\n optional: [],\n },\n\n cli: {\n groupMeta: [\n { path: 'devlink', describe: 'Cross-repo link: dependency management' },\n ],\n commands: [\n {\n path: 'devlink switch',\n category: 'Mode',\n describe: 'Switch deps between local link: and npm (CI/CD) mode',\n operationType: 'mutate' as const,\n longDescription:\n 'Replaces all cross-repo @kb-labs/* dependencies across monorepos. ' +\n 'Creates a backup before applying. Run pnpm install after switching.',\n\n handler: './cli/commands/switch.js#default',\n\n flags: defineCommandFlags(switchFlags),\n\n examples: generateExamples('switch', 'devlink', [\n { description: 'Switch to npm mode (CI/CD)', flags: { mode: 'npm' } },\n { description: 'Switch to local mode (development)', flags: { mode: 'local' } },\n { description: 'Preview changes without applying', flags: { mode: 'local', 'dry-run': true } },\n { description: 'Switch specific repos only', flags: { mode: 'npm', repos: 'kb-labs-cli,kb-labs-core' } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink status',\n category: 'Mode',\n describe: 'Show current state of cross-repo dependencies',\n operationType: 'read' as const,\n longDescription:\n 'Displays the current linking mode, counts of link: vs npm dependencies, ' +\n 'and any discrepancies across all monorepos.',\n\n handler: './cli/commands/status.js#default',\n\n flags: defineCommandFlags(statusFlags),\n\n examples: generateExamples('status', 'devlink', [\n { description: 'Show summary status', flags: {} },\n { description: 'Verbose output with all deps', flags: { verbose: true } },\n { description: 'JSON output for scripting', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink plan',\n category: 'Mode',\n describe: 'Preview what would change when switching mode',\n operationType: 'read' as const,\n longDescription:\n 'Shows all dependency changes that would be made without applying them. ' +\n 'Useful for reviewing before running switch.',\n\n handler: './cli/commands/plan.js#default',\n\n flags: defineCommandFlags(planFlags),\n\n examples: generateExamples('plan', 'devlink', [\n { description: 'Plan switch to local mode', flags: { mode: 'local' } },\n { description: 'Plan switch to npm mode', flags: { mode: 'npm' } },\n { description: 'JSON output for scripting', flags: { mode: 'npm', json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink freeze',\n category: 'State',\n describe: 'Freeze current dependency state to lock file',\n operationType: 'mutate' as const,\n longDescription:\n 'Saves a snapshot of current dependency mode to .kb/devlink/lock.json. ' +\n 'Use to record a stable known-good state.',\n\n handler: './cli/commands/freeze.js#default',\n\n flags: defineCommandFlags(freezeFlags),\n\n examples: generateExamples('freeze', 'devlink', [\n { description: 'Freeze current state', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink undo',\n category: 'State',\n describe: 'Restore previous dependency state from last backup',\n operationType: 'mutate' as const,\n longDescription:\n 'Restores package.json files from the most recent backup created by switch. ' +\n 'Run pnpm install after undoing.',\n\n handler: './cli/commands/undo.js#default',\n\n flags: defineCommandFlags(undoFlags),\n\n examples: generateExamples('undo', 'devlink', [\n { description: 'Undo last switch', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n ]),\n\n permissions: pluginPermissions,\n },\n {\n path: 'devlink backups',\n category: 'State',\n describe: 'List and restore backups',\n operationType: 'read' as const,\n longDescription:\n 'Lists all available backups. Use --restore <id> to restore a specific backup.',\n\n handler: './cli/commands/backups.js#default',\n\n flags: defineCommandFlags(backupsFlags),\n\n examples: generateExamples('backups', 'devlink', [\n { description: 'List all backups', flags: {} },\n { description: 'JSON output', flags: { json: true } },\n { description: 'Restore specific backup', flags: { restore: '<backup-id>' } },\n ]),\n\n permissions: pluginPermissions,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/devlink-entry",
3
3
  "description": "CLI commands and manifest for DevLink plugin.",
4
- "version": "2.94.0",
4
+ "version": "2.98.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -21,9 +21,9 @@
21
21
  "README.md"
22
22
  ],
23
23
  "dependencies": {
24
- "@kb-labs/sdk": "2.21.2",
25
- "@kb-labs/devlink-contracts": "2.94.0",
26
- "@kb-labs/devlink-core": "2.94.0"
24
+ "@kb-labs/sdk": "2.22.0",
25
+ "@kb-labs/devlink-contracts": "2.98.0",
26
+ "@kb-labs/devlink-core": "2.98.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^24.3.3",
@@ -31,8 +31,8 @@
31
31
  "rimraf": "^6.0.1",
32
32
  "tsup": "^8.5.0",
33
33
  "typescript": "^5.6.3",
34
- "vitest": "^3.2.4",
35
- "@kb-labs/devkit": "2.94.0"
34
+ "vitest": "^3.2.6",
35
+ "@kb-labs/devkit": "2.98.0"
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=20.0.0",
@@ -49,6 +49,7 @@
49
49
  "lint": "eslint src --ext .ts",
50
50
  "lint:fix": "eslint . --fix",
51
51
  "test": "vitest run --passWithNoTests",
52
+ "test:cli": "vitest run --config vitest.cli.config.ts --passWithNoTests",
52
53
  "test:watch": "vitest",
53
54
  "type-check": "tsc --noEmit"
54
55
  }