@kb-labs/devlink-cli 1.4.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.
- package/dist/cli/commands/backups.d.ts +20 -0
- package/dist/cli/commands/backups.js +66 -0
- package/dist/cli/commands/backups.js.map +1 -0
- package/dist/cli/commands/freeze.d.ts +14 -0
- package/dist/cli/commands/freeze.js +49 -0
- package/dist/cli/commands/freeze.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +32 -0
- package/dist/cli/commands/plan.js +75 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/status.d.ts +17 -0
- package/dist/cli/commands/status.js +97 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/switch.d.ts +31 -0
- package/dist/cli/commands/switch.js +196 -0
- package/dist/cli/commands/switch.js.map +1 -0
- package/dist/cli/commands/undo.d.ts +18 -0
- package/dist/cli/commands/undo.js +58 -0
- package/dist/cli/commands/undo.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +40 -0
- package/dist/manifest.js +127 -0
- package/dist/manifest.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { DevlinkBackup } from '@kb-labs/devlink-contracts';
|
|
3
|
+
|
|
4
|
+
interface BackupsFlags {
|
|
5
|
+
restore?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface BackupsInput {
|
|
9
|
+
argv?: string[];
|
|
10
|
+
flags?: BackupsFlags;
|
|
11
|
+
restore?: string;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface BackupsResult {
|
|
15
|
+
backups: DevlinkBackup[];
|
|
16
|
+
restored?: number;
|
|
17
|
+
}
|
|
18
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, BackupsInput, BackupsResult>;
|
|
19
|
+
|
|
20
|
+
export { _default as default };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
|
|
2
|
+
import { restoreBackup, listBackups } from '@kb-labs/devlink-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/backups.ts
|
|
5
|
+
var backups_default = defineCommand({
|
|
6
|
+
id: "devlink:backups",
|
|
7
|
+
description: "List and restore backups",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const tracker = new TimingTracker();
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const outputJson = flags.json ?? false;
|
|
13
|
+
const restoreId = flags.restore;
|
|
14
|
+
const rootDir = ctx.cwd ?? process.cwd();
|
|
15
|
+
if (restoreId) {
|
|
16
|
+
const loader = useLoader(`Restoring backup ${restoreId}...`);
|
|
17
|
+
loader.start();
|
|
18
|
+
const { restored, errors } = restoreBackup(rootDir, restoreId);
|
|
19
|
+
loader.succeed(`Restored ${restored} file(s)`);
|
|
20
|
+
tracker.checkpoint("restore");
|
|
21
|
+
const backups2 = listBackups(rootDir);
|
|
22
|
+
const result2 = { backups: backups2, restored };
|
|
23
|
+
if (outputJson) {
|
|
24
|
+
ctx.ui?.json?.(result2);
|
|
25
|
+
} else {
|
|
26
|
+
ctx.ui?.success?.(`Restored ${restored} file(s) from backup ${restoreId}`, {
|
|
27
|
+
title: "DevLink \u2014 Restore Backup",
|
|
28
|
+
sections: [
|
|
29
|
+
...errors.length > 0 ? [{ header: "Errors", items: errors }] : [],
|
|
30
|
+
{ header: "Next step", items: ["Run pnpm install to apply changes"] }
|
|
31
|
+
],
|
|
32
|
+
timing: tracker.total()
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return { exitCode: 0, result: result2, meta: { timing: tracker.total() } };
|
|
36
|
+
}
|
|
37
|
+
const backups = listBackups(rootDir);
|
|
38
|
+
tracker.checkpoint("list");
|
|
39
|
+
const result = { backups };
|
|
40
|
+
if (outputJson) {
|
|
41
|
+
ctx.ui?.json?.(result);
|
|
42
|
+
} else {
|
|
43
|
+
if (backups.length === 0) {
|
|
44
|
+
ctx.ui?.info?.("No backups found. Backups are created automatically before each switch.");
|
|
45
|
+
} else {
|
|
46
|
+
const items = backups.map(
|
|
47
|
+
(b) => `[${b.id}] ${b.timestamp.slice(0, 19).replace("T", " ")} \u2014 ${b.description} (${b.files.length} files)`
|
|
48
|
+
);
|
|
49
|
+
ctx.ui?.success?.(`${backups.length} backup(s) available`, {
|
|
50
|
+
title: "DevLink \u2014 Backups",
|
|
51
|
+
sections: [
|
|
52
|
+
{ header: "Backups (newest first)", items },
|
|
53
|
+
{ header: "Restore", items: ["kb devlink backups --restore <id>"] }
|
|
54
|
+
],
|
|
55
|
+
timing: tracker.total()
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { exitCode: 0, result, meta: { timing: tracker.total() } };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export { backups_default as default };
|
|
65
|
+
//# sourceMappingURL=backups.js.map
|
|
66
|
+
//# sourceMappingURL=backups.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { LockFile } from '@kb-labs/devlink-core';
|
|
3
|
+
|
|
4
|
+
interface FreezeFlags {
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface FreezeInput {
|
|
8
|
+
argv?: string[];
|
|
9
|
+
flags?: FreezeFlags;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, FreezeInput, LockFile>;
|
|
13
|
+
|
|
14
|
+
export { _default as default };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
|
|
2
|
+
import { loadState, discoverMonorepos, buildPackageMapFiltered, buildPlan, freeze } from '@kb-labs/devlink-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/freeze.ts
|
|
5
|
+
var freeze_default = defineCommand({
|
|
6
|
+
id: "devlink:freeze",
|
|
7
|
+
description: "Freeze current dependency state to lock file",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const tracker = new TimingTracker();
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const outputJson = flags.json ?? false;
|
|
13
|
+
const rootDir = ctx.cwd ?? process.cwd();
|
|
14
|
+
const loader = useLoader("Freezing current state...");
|
|
15
|
+
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);
|
|
22
|
+
loader.succeed("State frozen");
|
|
23
|
+
tracker.checkpoint("freeze");
|
|
24
|
+
if (outputJson) {
|
|
25
|
+
ctx.ui?.json?.(lock);
|
|
26
|
+
} else {
|
|
27
|
+
ctx.ui?.success?.("Current state frozen to lock file", {
|
|
28
|
+
title: "DevLink \u2014 Freeze",
|
|
29
|
+
sections: [
|
|
30
|
+
{
|
|
31
|
+
header: "Lock file",
|
|
32
|
+
items: [
|
|
33
|
+
`Mode: ${lock.plan.mode}`,
|
|
34
|
+
`Frozen at: ${lock.frozenAt}`,
|
|
35
|
+
`Location: .kb/devlink/lock.json`
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
timing: tracker.total()
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return { exitCode: 0, result: lock, meta: { timing: tracker.total() } };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export { freeze_default as default };
|
|
48
|
+
//# sourceMappingURL=freeze.js.map
|
|
49
|
+
//# sourceMappingURL=freeze.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { DevlinkMode } from '@kb-labs/devlink-contracts';
|
|
3
|
+
|
|
4
|
+
interface PlanFlags {
|
|
5
|
+
mode?: DevlinkMode;
|
|
6
|
+
repos?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
ttl?: number;
|
|
9
|
+
}
|
|
10
|
+
interface PlanInput {
|
|
11
|
+
argv?: string[];
|
|
12
|
+
flags?: PlanFlags;
|
|
13
|
+
mode?: DevlinkMode;
|
|
14
|
+
repos?: string;
|
|
15
|
+
json?: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, PlanInput, {
|
|
18
|
+
mode: "local" | "npm" | "auto";
|
|
19
|
+
items: {
|
|
20
|
+
monorepo: string;
|
|
21
|
+
packageJsonPath: string;
|
|
22
|
+
packageJsonRel: string;
|
|
23
|
+
depName: string;
|
|
24
|
+
from: string;
|
|
25
|
+
to: string;
|
|
26
|
+
section: "dependencies" | "devDependencies" | "peerDependencies";
|
|
27
|
+
}[];
|
|
28
|
+
timestamp: string;
|
|
29
|
+
scopedRepos?: string[] | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
|
|
32
|
+
export { _default as default };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
|
|
2
|
+
import { loadState, discoverMonorepos, buildPackageMapFiltered, buildPlan, groupByMonorepo } from '@kb-labs/devlink-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/plan.ts
|
|
5
|
+
var plan_default = defineCommand({
|
|
6
|
+
id: "devlink:plan",
|
|
7
|
+
description: "Preview what would change when switching mode",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const tracker = new TimingTracker();
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const outputJson = flags.json ?? false;
|
|
13
|
+
const scopedRepos = flags.repos ? flags.repos.split(",").map((s) => s.trim()) : void 0;
|
|
14
|
+
const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1e3;
|
|
15
|
+
const rootDir = ctx.cwd ?? process.cwd();
|
|
16
|
+
const loader = useLoader("Building plan...");
|
|
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 });
|
|
23
|
+
loader.succeed(`Plan ready: ${plan.items.length} change(s)`);
|
|
24
|
+
tracker.checkpoint("plan");
|
|
25
|
+
if (outputJson) {
|
|
26
|
+
ctx.ui?.json?.(plan);
|
|
27
|
+
} else {
|
|
28
|
+
if (plan.items.length === 0) {
|
|
29
|
+
ctx.ui?.info?.("No changes needed \u2014 already in the target mode.");
|
|
30
|
+
} else {
|
|
31
|
+
const byRepo = groupByMonorepo(plan.items);
|
|
32
|
+
const uniquePkgs = new Set(plan.items.map((i) => i.depName)).size;
|
|
33
|
+
const uniqueFiles = new Set(plan.items.map((i) => i.packageJsonPath)).size;
|
|
34
|
+
const sections = [...byRepo.entries()].map(([repo, items]) => {
|
|
35
|
+
const byDep = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const item of items) {
|
|
37
|
+
const existing = byDep.get(item.depName);
|
|
38
|
+
if (existing) {
|
|
39
|
+
existing.count++;
|
|
40
|
+
} else {
|
|
41
|
+
byDep.set(item.depName, { from: item.from, to: item.to, count: 1 });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
header: `${repo} (${byDep.size} dep${byDep.size !== 1 ? "s" : ""})`,
|
|
46
|
+
items: [...byDep.entries()].map(
|
|
47
|
+
([dep, { from, to, count }]) => count > 1 ? `${dep}: ${from} \u2192 ${to} \xD7${count} files` : `${dep}: ${from} \u2192 ${to}`
|
|
48
|
+
)
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
ctx.ui?.sideBox?.({
|
|
52
|
+
title: "DevLink \u2014 Plan",
|
|
53
|
+
status: "info",
|
|
54
|
+
summary: {
|
|
55
|
+
"Mode": `${state.currentMode ?? "?"} \u2192 ${targetMode}`,
|
|
56
|
+
"Packages": uniquePkgs,
|
|
57
|
+
"Files affected": uniqueFiles,
|
|
58
|
+
"Total changes": plan.items.length
|
|
59
|
+
},
|
|
60
|
+
sections: [
|
|
61
|
+
...sections,
|
|
62
|
+
{ header: "Next step", items: [`kb devlink switch --mode=${targetMode}`] }
|
|
63
|
+
],
|
|
64
|
+
timing: tracker.total()
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { exitCode: 0, result: plan, meta: { timing: tracker.total() } };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export { plan_default as default };
|
|
74
|
+
//# sourceMappingURL=plan.js.map
|
|
75
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { DevlinkStatus, DiagnosticIssue } from '@kb-labs/devlink-contracts';
|
|
3
|
+
|
|
4
|
+
interface StatusFlags {
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface StatusInput {
|
|
8
|
+
argv?: string[];
|
|
9
|
+
flags?: StatusFlags;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface StatusResult extends DevlinkStatus {
|
|
13
|
+
diagnostics: DiagnosticIssue[];
|
|
14
|
+
}
|
|
15
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, StatusInput, StatusResult>;
|
|
16
|
+
|
|
17
|
+
export { _default as default };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
|
|
2
|
+
import { loadState, discoverMonorepos, buildPackageMapFiltered, analyzePackageDeps, diagnose } from '@kb-labs/devlink-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/status.ts
|
|
5
|
+
var status_default = defineCommand({
|
|
6
|
+
id: "devlink:status",
|
|
7
|
+
description: "Show current state of cross-repo dependencies with diagnostics",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const tracker = new TimingTracker();
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const outputJson = flags.json ?? false;
|
|
13
|
+
const rootDir = ctx.cwd ?? process.cwd();
|
|
14
|
+
const loader = useLoader("Analyzing dependencies...");
|
|
15
|
+
loader.start();
|
|
16
|
+
const state = loadState(rootDir);
|
|
17
|
+
const monorepos = discoverMonorepos(rootDir);
|
|
18
|
+
const packageMap = await buildPackageMapFiltered(monorepos, rootDir);
|
|
19
|
+
let totalLink = 0;
|
|
20
|
+
let totalNpm = 0;
|
|
21
|
+
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;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const diagnostics = diagnose(monorepos, packageMap, rootDir);
|
|
31
|
+
loader.succeed("Analysis complete");
|
|
32
|
+
tracker.checkpoint("analysis");
|
|
33
|
+
const errors = diagnostics.filter((d) => d.severity === "error");
|
|
34
|
+
const warnings = diagnostics.filter((d) => d.severity === "warning");
|
|
35
|
+
const result = {
|
|
36
|
+
currentMode: state.currentMode,
|
|
37
|
+
lastApplied: state.lastApplied,
|
|
38
|
+
linkCount: totalLink,
|
|
39
|
+
npmCount: totalNpm,
|
|
40
|
+
workspaceCount: totalWorkspace,
|
|
41
|
+
discrepancies: [],
|
|
42
|
+
diagnostics
|
|
43
|
+
};
|
|
44
|
+
if (outputJson) {
|
|
45
|
+
ctx.ui?.json?.(result);
|
|
46
|
+
} else {
|
|
47
|
+
const sections = [
|
|
48
|
+
{
|
|
49
|
+
header: "Current mode",
|
|
50
|
+
items: [
|
|
51
|
+
`Mode: ${state.currentMode ?? "unknown"}`,
|
|
52
|
+
`Last applied: ${state.lastApplied ?? "never"}`
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
header: "Dependency counts",
|
|
57
|
+
items: [
|
|
58
|
+
`link: (local) : ${totalLink}`,
|
|
59
|
+
`npm (^version) : ${totalNpm}`,
|
|
60
|
+
`workspace:* : ${totalWorkspace}`
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
if (errors.length > 0) {
|
|
65
|
+
sections.push({
|
|
66
|
+
header: `\u274C Errors (${errors.length})`,
|
|
67
|
+
items: errors.slice(0, 10).map((d) => `${d.dep ?? d.file}: ${d.message}`)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (warnings.length > 0) {
|
|
71
|
+
sections.push({
|
|
72
|
+
header: `\u26A0 Warnings (${warnings.length})`,
|
|
73
|
+
items: warnings.slice(0, 10).map((d) => `${d.dep ?? d.file}: ${d.message}`)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (diagnostics.length === 0) {
|
|
77
|
+
sections.push({ header: "\u2705 Health", items: ["No issues detected"] });
|
|
78
|
+
} else {
|
|
79
|
+
sections.push({
|
|
80
|
+
header: "Fix",
|
|
81
|
+
items: ["Run: kb devlink switch --mode=local --install"]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
ctx.ui?.success?.("Dependency status", {
|
|
85
|
+
title: "DevLink \u2014 Status",
|
|
86
|
+
sections,
|
|
87
|
+
timing: tracker.total()
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return { exitCode: 0, result, meta: { timing: tracker.total() } };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export { status_default as default };
|
|
96
|
+
//# sourceMappingURL=status.js.map
|
|
97
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { DevlinkMode } from '@kb-labs/devlink-contracts';
|
|
3
|
+
|
|
4
|
+
interface SwitchFlags {
|
|
5
|
+
mode: DevlinkMode;
|
|
6
|
+
'dry-run'?: boolean;
|
|
7
|
+
repos?: string;
|
|
8
|
+
yes?: boolean;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
ttl?: number;
|
|
11
|
+
install?: boolean;
|
|
12
|
+
'clean-locks'?: boolean;
|
|
13
|
+
}
|
|
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
|
+
interface SwitchResult {
|
|
24
|
+
mode: DevlinkMode;
|
|
25
|
+
changed: number;
|
|
26
|
+
dryRun: boolean;
|
|
27
|
+
backupId?: string;
|
|
28
|
+
}
|
|
29
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, SwitchInput, SwitchResult>;
|
|
30
|
+
|
|
31
|
+
export { _default as default };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
|
|
2
|
+
import { discoverMonorepos, buildPackageMapFiltered, checkGitDirty, buildPlan, loadState, createBackup, applyPlan, updateWorkspaceYamls, saveState } from '@kb-labs/devlink-core';
|
|
3
|
+
import { existsSync, unlinkSync, rmSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
|
|
7
|
+
// src/cli/commands/switch.ts
|
|
8
|
+
var switch_default = defineCommand({
|
|
9
|
+
id: "devlink:switch",
|
|
10
|
+
description: "Switch cross-repo deps between link: and npm mode",
|
|
11
|
+
handler: {
|
|
12
|
+
async execute(ctx, input) {
|
|
13
|
+
const tracker = new TimingTracker();
|
|
14
|
+
const flags = input.flags ?? input;
|
|
15
|
+
const mode = flags.mode;
|
|
16
|
+
const dryRun = flags["dry-run"] ?? false;
|
|
17
|
+
const outputJson = flags.json ?? false;
|
|
18
|
+
const scopedRepos = flags.repos ? flags.repos.split(",").map((s) => s.trim()) : void 0;
|
|
19
|
+
const ttlMs = (flags.ttl ?? 24) * 60 * 60 * 1e3;
|
|
20
|
+
const rootDir = ctx.cwd ?? process.cwd();
|
|
21
|
+
const discoverLoader = useLoader("Discovering monorepos...");
|
|
22
|
+
discoverLoader.start();
|
|
23
|
+
const monorepos = discoverMonorepos(rootDir);
|
|
24
|
+
const packageMap = await buildPackageMapFiltered(monorepos, rootDir, ttlMs, mode);
|
|
25
|
+
discoverLoader.succeed(`Found ${monorepos.length} monorepos, ${Object.keys(packageMap).length} packages`);
|
|
26
|
+
tracker.checkpoint("discovery");
|
|
27
|
+
const dirtyFiles = checkGitDirty(rootDir);
|
|
28
|
+
if (dirtyFiles.length > 0) {
|
|
29
|
+
ctx.ui?.warn?.(`Working tree has ${dirtyFiles.length} uncommitted changes`);
|
|
30
|
+
}
|
|
31
|
+
const plan = buildPlan(mode, packageMap, monorepos, rootDir, { scopedRepos });
|
|
32
|
+
tracker.checkpoint("plan");
|
|
33
|
+
if (plan.items.length === 0 && !flags.install) {
|
|
34
|
+
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() } };
|
|
57
|
+
}
|
|
58
|
+
const currentState = loadState(rootDir);
|
|
59
|
+
const modeAtBackup = currentState.currentMode ?? mode;
|
|
60
|
+
const allPackageJsons = monorepos.flatMap((m) => m.packagePaths);
|
|
61
|
+
const backup = createBackup(rootDir, allPackageJsons, `pre-switch to ${mode}`, modeAtBackup);
|
|
62
|
+
const backupId = backup.id;
|
|
63
|
+
tracker.checkpoint("backup");
|
|
64
|
+
let applyResult = { applied: 0, errors: [] };
|
|
65
|
+
if (plan.items.length > 0) {
|
|
66
|
+
const applyLoader = useLoader(`Switching ${plan.items.length} dependencies to ${mode} mode...`);
|
|
67
|
+
applyLoader.start();
|
|
68
|
+
applyResult = await applyPlan(plan, { dryRun: false });
|
|
69
|
+
applyLoader.succeed(`Applied ${applyResult.applied} change(s)`);
|
|
70
|
+
tracker.checkpoint("apply");
|
|
71
|
+
}
|
|
72
|
+
const wsLoader = useLoader("Updating sub-repo workspace files...");
|
|
73
|
+
wsLoader.start();
|
|
74
|
+
const wsUpdates = updateWorkspaceYamls(monorepos, packageMap, rootDir);
|
|
75
|
+
const wsChanged = wsUpdates.reduce((sum, u) => sum + u.added.length + u.removed.length, 0);
|
|
76
|
+
wsLoader.succeed(
|
|
77
|
+
wsChanged > 0 ? `Updated ${wsUpdates.length} workspace file(s) (${wsChanged} path changes)` : "Workspace files up to date"
|
|
78
|
+
);
|
|
79
|
+
tracker.checkpoint("workspace-yaml");
|
|
80
|
+
saveState(rootDir, {
|
|
81
|
+
currentMode: mode,
|
|
82
|
+
lastApplied: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83
|
+
frozenAt: currentState.frozenAt
|
|
84
|
+
});
|
|
85
|
+
const shouldClean = flags["clean-locks"] !== false;
|
|
86
|
+
let cleanedLocks = 0;
|
|
87
|
+
let cleanedNodeModules = 0;
|
|
88
|
+
if (shouldClean) {
|
|
89
|
+
const cleanLoader = useLoader("Cleaning stale lockfiles and node_modules...");
|
|
90
|
+
cleanLoader.start();
|
|
91
|
+
for (const mono of monorepos) {
|
|
92
|
+
const lockPath = join(mono.rootPath, "pnpm-lock.yaml");
|
|
93
|
+
if (existsSync(lockPath)) {
|
|
94
|
+
try {
|
|
95
|
+
unlinkSync(lockPath);
|
|
96
|
+
cleanedLocks++;
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const nmPath = join(mono.rootPath, "node_modules");
|
|
101
|
+
if (existsSync(nmPath)) {
|
|
102
|
+
try {
|
|
103
|
+
rmSync(nmPath, { recursive: true, force: true });
|
|
104
|
+
cleanedNodeModules++;
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
cleanLoader.succeed(
|
|
110
|
+
`Cleaned ${cleanedLocks} lockfile(s), ${cleanedNodeModules} node_modules`
|
|
111
|
+
);
|
|
112
|
+
tracker.checkpoint("clean");
|
|
113
|
+
}
|
|
114
|
+
const shouldInstall = flags.install === true;
|
|
115
|
+
let installedRepos = 0;
|
|
116
|
+
const installErrors = [];
|
|
117
|
+
if (shouldInstall) {
|
|
118
|
+
const rootLoader = useLoader("Installing workspace root...");
|
|
119
|
+
rootLoader.start();
|
|
120
|
+
try {
|
|
121
|
+
execSync("pnpm install --no-frozen-lockfile", {
|
|
122
|
+
cwd: rootDir,
|
|
123
|
+
stdio: "pipe",
|
|
124
|
+
timeout: 18e4
|
|
125
|
+
});
|
|
126
|
+
rootLoader.succeed("Workspace root installed");
|
|
127
|
+
} catch (err) {
|
|
128
|
+
rootLoader.succeed("Workspace root install failed");
|
|
129
|
+
installErrors.push(`root: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
|
|
130
|
+
}
|
|
131
|
+
tracker.checkpoint("root-install");
|
|
132
|
+
const affectedRepos = new Set(plan.items.map((i) => i.monorepo));
|
|
133
|
+
const affectedMonorepos = monorepos.filter(
|
|
134
|
+
(m) => affectedRepos.has(m.name) || !existsSync(join(m.rootPath, "pnpm-lock.yaml"))
|
|
135
|
+
);
|
|
136
|
+
const repoLoader = useLoader(`Installing ${affectedMonorepos.length} sub-repo(s)...`);
|
|
137
|
+
repoLoader.start();
|
|
138
|
+
for (const mono of affectedMonorepos) {
|
|
139
|
+
try {
|
|
140
|
+
execSync("pnpm install --no-frozen-lockfile --prefer-offline", {
|
|
141
|
+
cwd: mono.rootPath,
|
|
142
|
+
stdio: "pipe",
|
|
143
|
+
timeout: 3e5
|
|
144
|
+
// 5 min per sub-repo
|
|
145
|
+
});
|
|
146
|
+
installedRepos++;
|
|
147
|
+
} catch (err) {
|
|
148
|
+
installErrors.push(`${mono.name}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
repoLoader.succeed(`Installed ${installedRepos}/${affectedMonorepos.length} sub-repo(s)${installErrors.length > 0 ? `, ${installErrors.length} failed` : ""}`);
|
|
152
|
+
tracker.checkpoint("sub-repo-install");
|
|
153
|
+
}
|
|
154
|
+
const result = {
|
|
155
|
+
mode,
|
|
156
|
+
changed: applyResult.applied,
|
|
157
|
+
dryRun: false,
|
|
158
|
+
backupId
|
|
159
|
+
};
|
|
160
|
+
if (outputJson) {
|
|
161
|
+
ctx.ui?.json?.({ ...result, cleanedLocks, wsUpdates: wsUpdates.length, installedRepos, installErrors });
|
|
162
|
+
} else {
|
|
163
|
+
const summaryItems = [
|
|
164
|
+
`Mode: ${mode}`,
|
|
165
|
+
`Changed: ${applyResult.applied} dependencies`,
|
|
166
|
+
`Backup: ${backupId}`
|
|
167
|
+
];
|
|
168
|
+
if (wsChanged > 0) {
|
|
169
|
+
summaryItems.push(`Workspace YAMLs: ${wsUpdates.length} updated`);
|
|
170
|
+
}
|
|
171
|
+
if (cleanedLocks > 0 || cleanedNodeModules > 0) {
|
|
172
|
+
summaryItems.push(`Cleaned: ${cleanedLocks} lockfile(s), ${cleanedNodeModules} node_modules`);
|
|
173
|
+
}
|
|
174
|
+
if (shouldInstall) {
|
|
175
|
+
summaryItems.push(`Installed: root + ${installedRepos} sub-repo(s)`);
|
|
176
|
+
}
|
|
177
|
+
const sections = [
|
|
178
|
+
{ header: "Summary", items: summaryItems },
|
|
179
|
+
...applyResult.errors.length > 0 ? [{ header: "Errors", items: applyResult.errors.map((e) => `${e.file}: ${e.error}`) }] : [],
|
|
180
|
+
...installErrors.length > 0 ? [{ header: "Install errors", items: installErrors }] : [],
|
|
181
|
+
...!shouldInstall && applyResult.applied > 0 ? [{ header: "Next step", items: ["Re-run with --install to complete setup"] }] : []
|
|
182
|
+
];
|
|
183
|
+
ctx.ui?.success?.(`Switched to ${mode} mode`, {
|
|
184
|
+
title: "DevLink \u2014 Switch",
|
|
185
|
+
sections,
|
|
186
|
+
timing: tracker.total()
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return { exitCode: 0, result, meta: { timing: tracker.total() } };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
export { switch_default as default };
|
|
195
|
+
//# sourceMappingURL=switch.js.map
|
|
196
|
+
//# sourceMappingURL=switch.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
|
|
3
|
+
interface UndoFlags {
|
|
4
|
+
json?: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface UndoInput {
|
|
7
|
+
argv?: string[];
|
|
8
|
+
flags?: UndoFlags;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface UndoResult {
|
|
12
|
+
restored: number;
|
|
13
|
+
backupId: string;
|
|
14
|
+
errors: string[];
|
|
15
|
+
}
|
|
16
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, UndoInput, UndoResult>;
|
|
17
|
+
|
|
18
|
+
export { _default as default };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineCommand, TimingTracker, useLoader } from '@kb-labs/sdk';
|
|
2
|
+
import { getLastBackup, restoreBackup, loadState, saveState } from '@kb-labs/devlink-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/undo.ts
|
|
5
|
+
var undo_default = defineCommand({
|
|
6
|
+
id: "devlink:undo",
|
|
7
|
+
description: "Restore previous dependency state from last backup",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const tracker = new TimingTracker();
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const outputJson = flags.json ?? false;
|
|
13
|
+
const rootDir = ctx.cwd ?? process.cwd();
|
|
14
|
+
const backup = getLastBackup(rootDir);
|
|
15
|
+
if (!backup) {
|
|
16
|
+
ctx.ui?.error?.("No backups found. Run switch first to create a backup.");
|
|
17
|
+
return { exitCode: 1 };
|
|
18
|
+
}
|
|
19
|
+
const loader = useLoader(`Restoring from backup ${backup.id}...`);
|
|
20
|
+
loader.start();
|
|
21
|
+
const { restored, errors } = restoreBackup(rootDir, backup.id);
|
|
22
|
+
loader.succeed(`Restored ${restored} file(s)`);
|
|
23
|
+
tracker.checkpoint("restore");
|
|
24
|
+
const currentState = loadState(rootDir);
|
|
25
|
+
saveState(rootDir, {
|
|
26
|
+
...currentState,
|
|
27
|
+
currentMode: backup.modeAtBackup,
|
|
28
|
+
lastApplied: (/* @__PURE__ */ new Date()).toISOString()
|
|
29
|
+
});
|
|
30
|
+
const result = { restored, backupId: backup.id, errors };
|
|
31
|
+
if (outputJson) {
|
|
32
|
+
ctx.ui?.json?.(result);
|
|
33
|
+
} else {
|
|
34
|
+
ctx.ui?.success?.(`Restored from backup (mode: ${backup.modeAtBackup ?? "unknown"})`, {
|
|
35
|
+
title: "DevLink \u2014 Undo",
|
|
36
|
+
sections: [
|
|
37
|
+
{
|
|
38
|
+
header: "Summary",
|
|
39
|
+
items: [
|
|
40
|
+
`Backup ID: ${backup.id}`,
|
|
41
|
+
`Created: ${backup.timestamp}`,
|
|
42
|
+
`Restored files: ${restored}`
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
...errors.length > 0 ? [{ header: "Errors", items: errors }] : [],
|
|
46
|
+
{ header: "Next step", items: ["Run pnpm install to apply changes"] }
|
|
47
|
+
],
|
|
48
|
+
timing: tracker.total()
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return { exitCode: errors.length > 0 ? 1 : 0, result, meta: { timing: tracker.total() } };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export { undo_default as default };
|
|
57
|
+
//# sourceMappingURL=undo.js.map
|
|
58
|
+
//# sourceMappingURL=undo.js.map
|
|
@@ -0,0 +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"]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { combinePermissions, generateExamples, defineCommandFlags } from '@kb-labs/sdk';
|
|
2
|
+
import { DEVLINK_CACHE_PREFIX, switchFlags, statusFlags, planFlags, freezeFlags, undoFlags, backupsFlags } from '@kb-labs/devlink-contracts';
|
|
3
|
+
|
|
4
|
+
// src/manifest.ts
|
|
5
|
+
var pluginPermissions = combinePermissions().withFs({
|
|
6
|
+
mode: "readWrite",
|
|
7
|
+
allow: ["**/package.json", ".kb/devlink/**", "**/pnpm-workspace.yaml"]
|
|
8
|
+
}).withPlatform({
|
|
9
|
+
cache: [DEVLINK_CACHE_PREFIX]
|
|
10
|
+
}).withQuotas({
|
|
11
|
+
timeoutMs: 18e5,
|
|
12
|
+
// 30 min — switch --install runs pnpm install in 29 sub-repos
|
|
13
|
+
memoryMb: 512
|
|
14
|
+
}).build();
|
|
15
|
+
var manifest = {
|
|
16
|
+
schema: "kb.plugin/3",
|
|
17
|
+
id: "@kb-labs/devlink",
|
|
18
|
+
version: "1.0.0",
|
|
19
|
+
display: {
|
|
20
|
+
name: "DevLink",
|
|
21
|
+
description: "Manage cross-repo link: \u2194 npm dependencies for KB Labs monorepos.",
|
|
22
|
+
tags: ["monorepo", "devlink", "dependencies", "publish", "local-dev"]
|
|
23
|
+
},
|
|
24
|
+
platform: {
|
|
25
|
+
requires: ["storage"],
|
|
26
|
+
optional: []
|
|
27
|
+
},
|
|
28
|
+
cli: {
|
|
29
|
+
commands: [
|
|
30
|
+
{
|
|
31
|
+
id: "devlink:switch",
|
|
32
|
+
group: "devlink",
|
|
33
|
+
describe: "Switch all cross-repo deps between link: (local) and npm (CI/CD) mode",
|
|
34
|
+
longDescription: "Replaces all cross-repo @kb-labs/* dependencies across monorepos. Creates a backup before applying. Run pnpm install after switching.",
|
|
35
|
+
handler: "./cli/commands/switch.js#default",
|
|
36
|
+
handlerPath: "./cli/commands/switch.js",
|
|
37
|
+
flags: defineCommandFlags(switchFlags),
|
|
38
|
+
examples: generateExamples("switch", "devlink", [
|
|
39
|
+
{ description: "Switch to npm mode (CI/CD)", flags: { mode: "npm" } },
|
|
40
|
+
{ description: "Switch to local mode (development)", flags: { mode: "local" } },
|
|
41
|
+
{ description: "Preview changes without applying", flags: { mode: "local", "dry-run": true } },
|
|
42
|
+
{ description: "Switch specific repos only", flags: { mode: "npm", repos: "kb-labs-cli,kb-labs-core" } }
|
|
43
|
+
]),
|
|
44
|
+
permissions: pluginPermissions
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "devlink:status",
|
|
48
|
+
group: "devlink",
|
|
49
|
+
describe: "Show current state of cross-repo dependencies",
|
|
50
|
+
longDescription: "Displays the current linking mode, counts of link: vs npm dependencies, and any discrepancies across all monorepos.",
|
|
51
|
+
handler: "./cli/commands/status.js#default",
|
|
52
|
+
handlerPath: "./cli/commands/status.js",
|
|
53
|
+
flags: defineCommandFlags(statusFlags),
|
|
54
|
+
examples: generateExamples("status", "devlink", [
|
|
55
|
+
{ description: "Show summary status", flags: {} },
|
|
56
|
+
{ description: "Verbose output with all deps", flags: { verbose: true } },
|
|
57
|
+
{ description: "JSON output for scripting", flags: { json: true } }
|
|
58
|
+
]),
|
|
59
|
+
permissions: pluginPermissions
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "devlink:plan",
|
|
63
|
+
group: "devlink",
|
|
64
|
+
describe: "Preview what would change when switching mode",
|
|
65
|
+
longDescription: "Shows all dependency changes that would be made without applying them. Useful for reviewing before running switch.",
|
|
66
|
+
handler: "./cli/commands/plan.js#default",
|
|
67
|
+
handlerPath: "./cli/commands/plan.js",
|
|
68
|
+
flags: defineCommandFlags(planFlags),
|
|
69
|
+
examples: generateExamples("plan", "devlink", [
|
|
70
|
+
{ description: "Plan switch to local mode", flags: { mode: "local" } },
|
|
71
|
+
{ description: "Plan switch to npm mode", flags: { mode: "npm" } },
|
|
72
|
+
{ description: "JSON output for scripting", flags: { mode: "npm", json: true } }
|
|
73
|
+
]),
|
|
74
|
+
permissions: pluginPermissions
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "devlink:freeze",
|
|
78
|
+
group: "devlink",
|
|
79
|
+
describe: "Freeze current dependency state to lock file",
|
|
80
|
+
longDescription: "Saves a snapshot of current dependency mode to .kb/devlink/lock.json. Use to record a stable known-good state.",
|
|
81
|
+
handler: "./cli/commands/freeze.js#default",
|
|
82
|
+
handlerPath: "./cli/commands/freeze.js",
|
|
83
|
+
flags: defineCommandFlags(freezeFlags),
|
|
84
|
+
examples: generateExamples("freeze", "devlink", [
|
|
85
|
+
{ description: "Freeze current state", flags: {} },
|
|
86
|
+
{ description: "JSON output", flags: { json: true } }
|
|
87
|
+
]),
|
|
88
|
+
permissions: pluginPermissions
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "devlink:undo",
|
|
92
|
+
group: "devlink",
|
|
93
|
+
describe: "Restore previous dependency state from last backup",
|
|
94
|
+
longDescription: "Restores package.json files from the most recent backup created by switch. Run pnpm install after undoing.",
|
|
95
|
+
handler: "./cli/commands/undo.js#default",
|
|
96
|
+
handlerPath: "./cli/commands/undo.js",
|
|
97
|
+
flags: defineCommandFlags(undoFlags),
|
|
98
|
+
examples: generateExamples("undo", "devlink", [
|
|
99
|
+
{ description: "Undo last switch", flags: {} },
|
|
100
|
+
{ description: "JSON output", flags: { json: true } }
|
|
101
|
+
]),
|
|
102
|
+
permissions: pluginPermissions
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "devlink:backups",
|
|
106
|
+
group: "devlink",
|
|
107
|
+
describe: "List and restore backups",
|
|
108
|
+
longDescription: "Lists all available backups. Use --restore <id> to restore a specific backup.",
|
|
109
|
+
handler: "./cli/commands/backups.js#default",
|
|
110
|
+
handlerPath: "./cli/commands/backups.js",
|
|
111
|
+
flags: defineCommandFlags(backupsFlags),
|
|
112
|
+
examples: generateExamples("backups", "devlink", [
|
|
113
|
+
{ description: "List all backups", flags: {} },
|
|
114
|
+
{ description: "JSON output", flags: { json: true } },
|
|
115
|
+
{ description: "Restore specific backup", flags: { restore: "<backup-id>" } }
|
|
116
|
+
]),
|
|
117
|
+
permissions: pluginPermissions
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
permissions: pluginPermissions
|
|
122
|
+
};
|
|
123
|
+
var manifest_default = manifest;
|
|
124
|
+
|
|
125
|
+
export { manifest_default as default, manifest };
|
|
126
|
+
//# sourceMappingURL=index.js.map
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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: 'devlink: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: 'devlink: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: 'devlink: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: 'devlink: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: 'devlink: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: 'devlink: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"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as _kb_labs_perm_presets from '@kb-labs/perm-presets';
|
|
2
|
+
|
|
3
|
+
declare const manifest: {
|
|
4
|
+
schema: string;
|
|
5
|
+
id: string;
|
|
6
|
+
version: string;
|
|
7
|
+
display: {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
tags: string[];
|
|
11
|
+
};
|
|
12
|
+
platform: {
|
|
13
|
+
requires: string[];
|
|
14
|
+
optional: never[];
|
|
15
|
+
};
|
|
16
|
+
cli: {
|
|
17
|
+
commands: {
|
|
18
|
+
id: string;
|
|
19
|
+
group: string;
|
|
20
|
+
describe: string;
|
|
21
|
+
longDescription: string;
|
|
22
|
+
handler: string;
|
|
23
|
+
handlerPath: string;
|
|
24
|
+
flags: {
|
|
25
|
+
name: string;
|
|
26
|
+
type: "string" | "boolean" | "number" | "array";
|
|
27
|
+
alias?: string;
|
|
28
|
+
default?: unknown;
|
|
29
|
+
description?: string;
|
|
30
|
+
choices?: string[];
|
|
31
|
+
required?: boolean;
|
|
32
|
+
}[];
|
|
33
|
+
examples: string[];
|
|
34
|
+
permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
37
|
+
permissions: _kb_labs_perm_presets.RuntimePermissionSpec;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { manifest as default, manifest };
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { combinePermissions, generateExamples, defineCommandFlags } from '@kb-labs/sdk';
|
|
2
|
+
import { DEVLINK_CACHE_PREFIX, switchFlags, statusFlags, planFlags, freezeFlags, undoFlags, backupsFlags } from '@kb-labs/devlink-contracts';
|
|
3
|
+
|
|
4
|
+
// src/manifest.ts
|
|
5
|
+
var pluginPermissions = combinePermissions().withFs({
|
|
6
|
+
mode: "readWrite",
|
|
7
|
+
allow: ["**/package.json", ".kb/devlink/**", "**/pnpm-workspace.yaml"]
|
|
8
|
+
}).withPlatform({
|
|
9
|
+
cache: [DEVLINK_CACHE_PREFIX]
|
|
10
|
+
}).withQuotas({
|
|
11
|
+
timeoutMs: 18e5,
|
|
12
|
+
// 30 min — switch --install runs pnpm install in 29 sub-repos
|
|
13
|
+
memoryMb: 512
|
|
14
|
+
}).build();
|
|
15
|
+
var manifest = {
|
|
16
|
+
schema: "kb.plugin/3",
|
|
17
|
+
id: "@kb-labs/devlink",
|
|
18
|
+
version: "1.0.0",
|
|
19
|
+
display: {
|
|
20
|
+
name: "DevLink",
|
|
21
|
+
description: "Manage cross-repo link: \u2194 npm dependencies for KB Labs monorepos.",
|
|
22
|
+
tags: ["monorepo", "devlink", "dependencies", "publish", "local-dev"]
|
|
23
|
+
},
|
|
24
|
+
platform: {
|
|
25
|
+
requires: ["storage"],
|
|
26
|
+
optional: []
|
|
27
|
+
},
|
|
28
|
+
cli: {
|
|
29
|
+
commands: [
|
|
30
|
+
{
|
|
31
|
+
id: "devlink:switch",
|
|
32
|
+
group: "devlink",
|
|
33
|
+
describe: "Switch all cross-repo deps between link: (local) and npm (CI/CD) mode",
|
|
34
|
+
longDescription: "Replaces all cross-repo @kb-labs/* dependencies across monorepos. Creates a backup before applying. Run pnpm install after switching.",
|
|
35
|
+
handler: "./cli/commands/switch.js#default",
|
|
36
|
+
handlerPath: "./cli/commands/switch.js",
|
|
37
|
+
flags: defineCommandFlags(switchFlags),
|
|
38
|
+
examples: generateExamples("switch", "devlink", [
|
|
39
|
+
{ description: "Switch to npm mode (CI/CD)", flags: { mode: "npm" } },
|
|
40
|
+
{ description: "Switch to local mode (development)", flags: { mode: "local" } },
|
|
41
|
+
{ description: "Preview changes without applying", flags: { mode: "local", "dry-run": true } },
|
|
42
|
+
{ description: "Switch specific repos only", flags: { mode: "npm", repos: "kb-labs-cli,kb-labs-core" } }
|
|
43
|
+
]),
|
|
44
|
+
permissions: pluginPermissions
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "devlink:status",
|
|
48
|
+
group: "devlink",
|
|
49
|
+
describe: "Show current state of cross-repo dependencies",
|
|
50
|
+
longDescription: "Displays the current linking mode, counts of link: vs npm dependencies, and any discrepancies across all monorepos.",
|
|
51
|
+
handler: "./cli/commands/status.js#default",
|
|
52
|
+
handlerPath: "./cli/commands/status.js",
|
|
53
|
+
flags: defineCommandFlags(statusFlags),
|
|
54
|
+
examples: generateExamples("status", "devlink", [
|
|
55
|
+
{ description: "Show summary status", flags: {} },
|
|
56
|
+
{ description: "Verbose output with all deps", flags: { verbose: true } },
|
|
57
|
+
{ description: "JSON output for scripting", flags: { json: true } }
|
|
58
|
+
]),
|
|
59
|
+
permissions: pluginPermissions
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "devlink:plan",
|
|
63
|
+
group: "devlink",
|
|
64
|
+
describe: "Preview what would change when switching mode",
|
|
65
|
+
longDescription: "Shows all dependency changes that would be made without applying them. Useful for reviewing before running switch.",
|
|
66
|
+
handler: "./cli/commands/plan.js#default",
|
|
67
|
+
handlerPath: "./cli/commands/plan.js",
|
|
68
|
+
flags: defineCommandFlags(planFlags),
|
|
69
|
+
examples: generateExamples("plan", "devlink", [
|
|
70
|
+
{ description: "Plan switch to local mode", flags: { mode: "local" } },
|
|
71
|
+
{ description: "Plan switch to npm mode", flags: { mode: "npm" } },
|
|
72
|
+
{ description: "JSON output for scripting", flags: { mode: "npm", json: true } }
|
|
73
|
+
]),
|
|
74
|
+
permissions: pluginPermissions
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "devlink:freeze",
|
|
78
|
+
group: "devlink",
|
|
79
|
+
describe: "Freeze current dependency state to lock file",
|
|
80
|
+
longDescription: "Saves a snapshot of current dependency mode to .kb/devlink/lock.json. Use to record a stable known-good state.",
|
|
81
|
+
handler: "./cli/commands/freeze.js#default",
|
|
82
|
+
handlerPath: "./cli/commands/freeze.js",
|
|
83
|
+
flags: defineCommandFlags(freezeFlags),
|
|
84
|
+
examples: generateExamples("freeze", "devlink", [
|
|
85
|
+
{ description: "Freeze current state", flags: {} },
|
|
86
|
+
{ description: "JSON output", flags: { json: true } }
|
|
87
|
+
]),
|
|
88
|
+
permissions: pluginPermissions
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "devlink:undo",
|
|
92
|
+
group: "devlink",
|
|
93
|
+
describe: "Restore previous dependency state from last backup",
|
|
94
|
+
longDescription: "Restores package.json files from the most recent backup created by switch. Run pnpm install after undoing.",
|
|
95
|
+
handler: "./cli/commands/undo.js#default",
|
|
96
|
+
handlerPath: "./cli/commands/undo.js",
|
|
97
|
+
flags: defineCommandFlags(undoFlags),
|
|
98
|
+
examples: generateExamples("undo", "devlink", [
|
|
99
|
+
{ description: "Undo last switch", flags: {} },
|
|
100
|
+
{ description: "JSON output", flags: { json: true } }
|
|
101
|
+
]),
|
|
102
|
+
permissions: pluginPermissions
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "devlink:backups",
|
|
106
|
+
group: "devlink",
|
|
107
|
+
describe: "List and restore backups",
|
|
108
|
+
longDescription: "Lists all available backups. Use --restore <id> to restore a specific backup.",
|
|
109
|
+
handler: "./cli/commands/backups.js#default",
|
|
110
|
+
handlerPath: "./cli/commands/backups.js",
|
|
111
|
+
flags: defineCommandFlags(backupsFlags),
|
|
112
|
+
examples: generateExamples("backups", "devlink", [
|
|
113
|
+
{ description: "List all backups", flags: {} },
|
|
114
|
+
{ description: "JSON output", flags: { json: true } },
|
|
115
|
+
{ description: "Restore specific backup", flags: { restore: "<backup-id>" } }
|
|
116
|
+
]),
|
|
117
|
+
permissions: pluginPermissions
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
permissions: pluginPermissions
|
|
122
|
+
};
|
|
123
|
+
var manifest_default = manifest;
|
|
124
|
+
|
|
125
|
+
export { manifest_default as default, manifest };
|
|
126
|
+
//# sourceMappingURL=manifest.js.map
|
|
127
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +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: 'devlink: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: 'devlink: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: 'devlink: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: 'devlink: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: 'devlink: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: 'devlink: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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kb-labs/devlink-cli",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "CLI commands and manifest for DevLink plugin.",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"kb": {
|
|
9
|
+
"manifest": "./dist/manifest.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./plugin-manifest": {
|
|
17
|
+
"import": "./dist/manifest.js",
|
|
18
|
+
"types": "./dist/manifest.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./dist/*": "./dist/*"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"scripts": {
|
|
28
|
+
"clean": "rimraf dist",
|
|
29
|
+
"build": "tsup --config tsup.config.ts",
|
|
30
|
+
"dev": "tsup --config tsup.config.ts --watch",
|
|
31
|
+
"lint": "eslint src --ext .ts",
|
|
32
|
+
"lint:fix": "eslint . --fix",
|
|
33
|
+
"type-check": "tsc --noEmit",
|
|
34
|
+
"test": "vitest run --passWithNoTests",
|
|
35
|
+
"test:watch": "vitest"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@kb-labs/devlink-contracts": "^1.0.0",
|
|
39
|
+
"@kb-labs/devlink-core": "^1.0.0",
|
|
40
|
+
"@kb-labs/sdk": "^1.4.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
|
|
44
|
+
"@types/node": "^24.3.3",
|
|
45
|
+
"eslint": "^9",
|
|
46
|
+
"rimraf": "^6.0.1",
|
|
47
|
+
"tsup": "^8.5.0",
|
|
48
|
+
"typescript": "^5.6.3",
|
|
49
|
+
"vitest": "^3.2.4"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=20.0.0",
|
|
53
|
+
"pnpm": ">=9.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|