@shrkcrft/cli 0.1.0-alpha.6 → 0.1.0-alpha.8
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/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +19 -2
- package/dist/commands/command-catalog.d.ts +7 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +112 -33
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +5 -22
- package/dist/commands/diff-check.command.d.ts +30 -0
- package/dist/commands/diff-check.command.d.ts.map +1 -0
- package/dist/commands/diff-check.command.js +210 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +41 -7
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/help.command.d.ts +4 -3
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +74 -16
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +151 -7
- package/dist/commands/packs-new.d.ts +1 -1
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +5 -36
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +2 -10
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/task-context.command.js +0 -16
- package/dist/export/claude-commands-export.d.ts +60 -0
- package/dist/export/claude-commands-export.d.ts.map +1 -0
- package/dist/export/claude-commands-export.js +276 -0
- package/dist/export/export-formats.d.ts +1 -1
- package/dist/export/export-formats.d.ts.map +1 -1
- package/dist/export/export-formats.js +139 -12
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +104 -11
- package/dist/output/watch-loop.d.ts +9 -1
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +13 -3
- package/package.json +20 -20
- package/dist/commands/plugin.command.d.ts +0 -11
- package/dist/commands/plugin.command.d.ts.map +0 -1
- package/dist/commands/plugin.command.js +0 -394
|
@@ -27,11 +27,19 @@ export interface IWatchPlan {
|
|
|
27
27
|
}
|
|
28
28
|
export declare function buildWatchPlan(options: IWatchLoopOptions, steps: readonly string[]): IWatchPlan;
|
|
29
29
|
import type { ParsedArgs } from '../command-registry.js';
|
|
30
|
+
export interface IWatchModeOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Paths to watch when the user does not pass `--paths`. Defaults to
|
|
33
|
+
* `['sharkcraft']` if omitted. Use this for commands that scan code
|
|
34
|
+
* outside `sharkcraft/` (e.g. `check boundaries` scans the whole repo).
|
|
35
|
+
*/
|
|
36
|
+
defaultPaths?: readonly string[];
|
|
37
|
+
}
|
|
30
38
|
/**
|
|
31
39
|
* Run a command's `run` function inside a watch loop when --watch is set.
|
|
32
40
|
*
|
|
33
41
|
* @returns null if --watch is not set (caller proceeds as before), otherwise
|
|
34
42
|
* the exit code of the watch loop.
|
|
35
43
|
*/
|
|
36
|
-
export declare function maybeRunInWatchMode(args: ParsedArgs, runner: (innerArgs: ParsedArgs) => Promise<number
|
|
44
|
+
export declare function maybeRunInWatchMode(args: ParsedArgs, runner: (innerArgs: ParsedArgs) => Promise<number>, options?: IWatchModeOptions): Promise<number | null>;
|
|
37
45
|
//# sourceMappingURL=watch-loop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-loop.d.ts","sourceRoot":"","sources":["../../src/output/watch-loop.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CA6DjB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,0BAA0B,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,UAAU,CAYZ;AAED,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGzD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"watch-loop.d.ts","sourceRoot":"","sources":["../../src/output/watch-loop.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CA6DjB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,0BAA0B,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,UAAU,CAYZ;AAED,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGzD,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,EAClD,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqCxB"}
|
|
@@ -81,31 +81,41 @@ export function buildWatchPlan(options, steps) {
|
|
|
81
81
|
steps,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
-
import { flagBool, flagNumber, resolveCwd } from "../command-registry.js";
|
|
84
|
+
import { flagBool, flagNumber, flagString, resolveCwd } from "../command-registry.js";
|
|
85
85
|
/**
|
|
86
86
|
* Run a command's `run` function inside a watch loop when --watch is set.
|
|
87
87
|
*
|
|
88
88
|
* @returns null if --watch is not set (caller proceeds as before), otherwise
|
|
89
89
|
* the exit code of the watch loop.
|
|
90
90
|
*/
|
|
91
|
-
export async function maybeRunInWatchMode(args, runner) {
|
|
91
|
+
export async function maybeRunInWatchMode(args, runner, options = {}) {
|
|
92
92
|
if (!flagBool(args, 'watch'))
|
|
93
93
|
return null;
|
|
94
94
|
const cwd = resolveCwd(args);
|
|
95
95
|
const debounce = flagNumber(args, 'debounce') ?? 300;
|
|
96
96
|
const once = flagBool(args, 'once');
|
|
97
|
+
const pathsFlag = flagString(args, 'paths');
|
|
98
|
+
const userPaths = pathsFlag
|
|
99
|
+
? pathsFlag.split(',').map((s) => s.trim()).filter((s) => s.length > 0)
|
|
100
|
+
: [];
|
|
101
|
+
const paths = userPaths.length > 0
|
|
102
|
+
? userPaths
|
|
103
|
+
: options.defaultPaths && options.defaultPaths.length > 0
|
|
104
|
+
? options.defaultPaths
|
|
105
|
+
: ['sharkcraft'];
|
|
97
106
|
// Strip --watch so the inner snapshot doesn't recurse.
|
|
98
107
|
const innerFlags = new Map(args.flags);
|
|
99
108
|
innerFlags.delete('watch');
|
|
100
109
|
innerFlags.delete('once');
|
|
101
110
|
innerFlags.delete('debounce');
|
|
111
|
+
innerFlags.delete('paths');
|
|
102
112
|
const innerArgs = {
|
|
103
113
|
positional: args.positional,
|
|
104
114
|
flags: innerFlags,
|
|
105
115
|
multiFlags: args.multiFlags,
|
|
106
116
|
...(args.globalCwd ? { globalCwd: args.globalCwd } : {}),
|
|
107
117
|
};
|
|
108
|
-
return runWatchLoop({ cwd, debounce, once }, {
|
|
118
|
+
return runWatchLoop({ cwd, debounce, once, paths }, {
|
|
109
119
|
snapshot: async () => {
|
|
110
120
|
const ts = new Date().toLocaleTimeString();
|
|
111
121
|
process.stdout.write(`\n[watch] ${ts}\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"description": "SharkCraft CLI (`shrk`): structured project intelligence for AI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -47,25 +47,25 @@
|
|
|
47
47
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/config": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
54
|
-
"@shrkcrft/context": "^0.1.0-alpha.
|
|
55
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
56
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
57
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
58
|
-
"@shrkcrft/plugin-api": "^0.1.0-alpha.
|
|
59
|
-
"@shrkcrft/dashboard-api": "^0.1.0-alpha.
|
|
60
|
-
"@shrkcrft/pipelines": "^0.1.0-alpha.
|
|
61
|
-
"@shrkcrft/presets": "^0.1.0-alpha.
|
|
62
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
63
|
-
"@shrkcrft/generator": "^0.1.0-alpha.
|
|
64
|
-
"@shrkcrft/importer": "^0.1.0-alpha.
|
|
65
|
-
"@shrkcrft/inspector": "^0.1.0-alpha.
|
|
66
|
-
"@shrkcrft/ai": "^0.1.0-alpha.
|
|
67
|
-
"@shrkcrft/shared": "^0.1.0-alpha.
|
|
68
|
-
"@shrkcrft/mcp-server": "^0.1.0-alpha.
|
|
50
|
+
"@shrkcrft/core": "^0.1.0-alpha.8",
|
|
51
|
+
"@shrkcrft/config": "^0.1.0-alpha.8",
|
|
52
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.8",
|
|
53
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.8",
|
|
54
|
+
"@shrkcrft/context": "^0.1.0-alpha.8",
|
|
55
|
+
"@shrkcrft/rules": "^0.1.0-alpha.8",
|
|
56
|
+
"@shrkcrft/paths": "^0.1.0-alpha.8",
|
|
57
|
+
"@shrkcrft/templates": "^0.1.0-alpha.8",
|
|
58
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.8",
|
|
59
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.8",
|
|
60
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.8",
|
|
61
|
+
"@shrkcrft/presets": "^0.1.0-alpha.8",
|
|
62
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.8",
|
|
63
|
+
"@shrkcrft/generator": "^0.1.0-alpha.8",
|
|
64
|
+
"@shrkcrft/importer": "^0.1.0-alpha.8",
|
|
65
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.8",
|
|
66
|
+
"@shrkcrft/ai": "^0.1.0-alpha.8",
|
|
67
|
+
"@shrkcrft/shared": "^0.1.0-alpha.8",
|
|
68
|
+
"@shrkcrft/mcp-server": "^0.1.0-alpha.8"
|
|
69
69
|
},
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
-
export declare const pluginRenameCommand: ICommandHandler;
|
|
3
|
-
export declare const pluginRemoveCommand: ICommandHandler;
|
|
4
|
-
export declare const pluginLifecycleListCommand: ICommandHandler;
|
|
5
|
-
export declare const pluginLifecycleInspectCommand: ICommandHandler;
|
|
6
|
-
export declare const pluginLifecycleProfilesCommand: ICommandHandler;
|
|
7
|
-
export declare const pluginLifecycleProfileCommand: ICommandHandler;
|
|
8
|
-
export declare const pluginLifecycleDoctorCommand: ICommandHandler;
|
|
9
|
-
export declare const pluginLifecycleCommand: ICommandHandler;
|
|
10
|
-
export declare const pluginCommand: ICommandHandler;
|
|
11
|
-
//# sourceMappingURL=plugin.command.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.command.d.ts","sourceRoot":"","sources":["../../src/commands/plugin.command.ts"],"names":[],"mappings":"AA+BA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA2BhC,eAAO,MAAM,mBAAmB,EAAE,eAmEjC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eAkEjC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eAwBxC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAsC3C,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,eA4B5C,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAkD3C,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,eA0C1C,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAepC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,eAc3B,CAAC"}
|
|
@@ -1,394 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `shrk plugin` commands, driven by pack/local lifecycle profiles.
|
|
3
|
-
*
|
|
4
|
-
* shrk plugin rename <old> <new> [--profile <id>] [--output <plan.json>] [--json]
|
|
5
|
-
* shrk plugin remove <name> [--profile <id>] [--output <plan.json>] [--json]
|
|
6
|
-
* shrk plugin lifecycle list [--profile <id>] [--json]
|
|
7
|
-
* shrk plugin lifecycle inspect <name> [--profile <id>] [--json]
|
|
8
|
-
* shrk plugin lifecycle profiles [--json]
|
|
9
|
-
* shrk plugin lifecycle profile <id> [--json]
|
|
10
|
-
* shrk plugin lifecycle doctor [--profile <id>] [--json]
|
|
11
|
-
*
|
|
12
|
-
* Every command is plan-only by default. Source is never written by these
|
|
13
|
-
* commands — humans run the regular plan-apply flow with --verify-signature
|
|
14
|
-
* after reviewing the produced plan.
|
|
15
|
-
*/
|
|
16
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
17
|
-
import * as nodePath from 'node:path';
|
|
18
|
-
import { buildPluginLifecycleListing, buildPluginRemovePlan, buildPluginRenamePlan, checkPluginLifecycleProfileHealth, inspectSharkcraft, listPluginLifecycleProfiles, listPluginLifecycleProfileIssues, pluginLifecyclePlanToSavedPlan, renderPluginLifecyclePlanText, resolvePluginLifecycleProfile, } from '@shrkcrft/inspector';
|
|
19
|
-
import { savePlanToFile, signPlan } from '@shrkcrft/generator';
|
|
20
|
-
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
21
|
-
import { asJson, header } from "../output/format-output.js";
|
|
22
|
-
function writePlanFile(content, outputArg, cwd) {
|
|
23
|
-
const abs = nodePath.isAbsolute(outputArg) ? outputArg : nodePath.resolve(cwd, outputArg);
|
|
24
|
-
mkdirSync(nodePath.dirname(abs), { recursive: true });
|
|
25
|
-
writeFileSync(abs, content + '\n', 'utf8');
|
|
26
|
-
return abs;
|
|
27
|
-
}
|
|
28
|
-
async function resolveProfileOrError(cwd, args) {
|
|
29
|
-
const inspection = await inspectSharkcraft({ cwd });
|
|
30
|
-
const profileId = flagString(args, 'profile');
|
|
31
|
-
const resolved = await resolvePluginLifecycleProfile(inspection, {
|
|
32
|
-
profileId,
|
|
33
|
-
allowSingleDefault: true,
|
|
34
|
-
});
|
|
35
|
-
if (!resolved.entry) {
|
|
36
|
-
process.stderr.write(`${resolved.error}\n`);
|
|
37
|
-
return { exitCode: 2 };
|
|
38
|
-
}
|
|
39
|
-
return { entry: resolved.entry };
|
|
40
|
-
}
|
|
41
|
-
export const pluginRenameCommand = {
|
|
42
|
-
name: 'rename',
|
|
43
|
-
description: 'Generate a plan-only rename plan for a plugin (profile-driven). Never writes source. Plan covers the profile key-table + barrels + folder ops (with --emit-folder-ops). Pass --save-plan <file> to emit a saved plan applicable through `shrk apply --allow-folder-ops`.',
|
|
44
|
-
usage: 'shrk plugin rename <old> <new> [--profile <id>] [--output <plan.json>] [--emit-folder-ops] [--save-plan <file>] [--sign] [--json]',
|
|
45
|
-
async run(args) {
|
|
46
|
-
const oldName = args.positional[0];
|
|
47
|
-
const newName = args.positional[1];
|
|
48
|
-
if (!oldName || !newName) {
|
|
49
|
-
process.stderr.write('Usage: shrk plugin rename <old> <new> [--profile <id>]\n');
|
|
50
|
-
return 2;
|
|
51
|
-
}
|
|
52
|
-
const cwd = resolveCwd(args);
|
|
53
|
-
const resolved = await resolveProfileOrError(cwd, args);
|
|
54
|
-
if (!resolved.entry)
|
|
55
|
-
return resolved.exitCode ?? 2;
|
|
56
|
-
const plan = buildPluginRenamePlan({
|
|
57
|
-
projectRoot: cwd,
|
|
58
|
-
profile: resolved.entry.profile,
|
|
59
|
-
oldName,
|
|
60
|
-
newName,
|
|
61
|
-
...(flagBool(args, 'emit-folder-ops') ? { emitFolderOps: true } : {}),
|
|
62
|
-
});
|
|
63
|
-
const output = flagString(args, 'output');
|
|
64
|
-
const savePlanPath = flagString(args, 'save-plan');
|
|
65
|
-
if (savePlanPath) {
|
|
66
|
-
const saved = pluginLifecyclePlanToSavedPlan(plan, cwd);
|
|
67
|
-
let toWrite = saved;
|
|
68
|
-
if (flagBool(args, 'sign')) {
|
|
69
|
-
const signed = signPlan(toWrite);
|
|
70
|
-
if (signed.ok)
|
|
71
|
-
toWrite = signed.value;
|
|
72
|
-
}
|
|
73
|
-
const abs = nodePath.isAbsolute(savePlanPath)
|
|
74
|
-
? savePlanPath
|
|
75
|
-
: nodePath.resolve(cwd, savePlanPath);
|
|
76
|
-
const writeResult = savePlanToFile(toWrite, abs);
|
|
77
|
-
if (!writeResult.ok) {
|
|
78
|
-
process.stderr.write(`Failed to save plan: ${writeResult.error.message}\n`);
|
|
79
|
-
return 1;
|
|
80
|
-
}
|
|
81
|
-
if (!flagBool(args, 'json')) {
|
|
82
|
-
process.stdout.write(renderPluginLifecyclePlanText(plan));
|
|
83
|
-
process.stdout.write(`\nSaved plan to ${abs}\nApply: shrk apply ${abs} --allow-folder-ops${plan.action === 'remove' ? ' --allow-delete-folder' : ''} --verify-signature\n`);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
process.stdout.write(asJson({ saved: abs, plan }) + '\n');
|
|
87
|
-
}
|
|
88
|
-
return 0;
|
|
89
|
-
}
|
|
90
|
-
if (flagBool(args, 'json')) {
|
|
91
|
-
const body = asJson(plan);
|
|
92
|
-
if (output) {
|
|
93
|
-
const abs = writePlanFile(body, output, cwd);
|
|
94
|
-
process.stdout.write(`Wrote ${abs}\n`);
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
process.stdout.write(body + '\n');
|
|
98
|
-
}
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
process.stdout.write(renderPluginLifecyclePlanText(plan));
|
|
102
|
-
if (output) {
|
|
103
|
-
const abs = writePlanFile(asJson(plan), output, cwd);
|
|
104
|
-
process.stdout.write(`\nSaved plan to ${abs}\n`);
|
|
105
|
-
}
|
|
106
|
-
return 0;
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
export const pluginRemoveCommand = {
|
|
110
|
-
name: 'remove',
|
|
111
|
-
description: 'Generate a plan-only remove plan for a plugin (profile-driven). Destructive; requires human approval. Source is never written. Pass --save-plan <file> to emit a saved plan applicable through `shrk apply --allow-folder-ops --allow-delete-folder`.',
|
|
112
|
-
usage: 'shrk plugin remove <name> [--profile <id>] [--output <plan.json>] [--emit-folder-ops] [--save-plan <file>] [--sign] [--json]',
|
|
113
|
-
async run(args) {
|
|
114
|
-
const name = args.positional[0];
|
|
115
|
-
if (!name) {
|
|
116
|
-
process.stderr.write('Usage: shrk plugin remove <name> [--profile <id>]\n');
|
|
117
|
-
return 2;
|
|
118
|
-
}
|
|
119
|
-
const cwd = resolveCwd(args);
|
|
120
|
-
const resolved = await resolveProfileOrError(cwd, args);
|
|
121
|
-
if (!resolved.entry)
|
|
122
|
-
return resolved.exitCode ?? 2;
|
|
123
|
-
const plan = buildPluginRemovePlan({
|
|
124
|
-
projectRoot: cwd,
|
|
125
|
-
profile: resolved.entry.profile,
|
|
126
|
-
oldName: name,
|
|
127
|
-
...(flagBool(args, 'emit-folder-ops') ? { emitFolderOps: true } : {}),
|
|
128
|
-
});
|
|
129
|
-
const output = flagString(args, 'output');
|
|
130
|
-
const savePlanPath = flagString(args, 'save-plan');
|
|
131
|
-
if (savePlanPath) {
|
|
132
|
-
const saved = pluginLifecyclePlanToSavedPlan(plan, cwd);
|
|
133
|
-
let toWrite = saved;
|
|
134
|
-
if (flagBool(args, 'sign')) {
|
|
135
|
-
const signed = signPlan(toWrite);
|
|
136
|
-
if (signed.ok)
|
|
137
|
-
toWrite = signed.value;
|
|
138
|
-
}
|
|
139
|
-
const abs = nodePath.isAbsolute(savePlanPath)
|
|
140
|
-
? savePlanPath
|
|
141
|
-
: nodePath.resolve(cwd, savePlanPath);
|
|
142
|
-
const writeResult = savePlanToFile(toWrite, abs);
|
|
143
|
-
if (!writeResult.ok) {
|
|
144
|
-
process.stderr.write(`Failed to save plan: ${writeResult.error.message}\n`);
|
|
145
|
-
return 1;
|
|
146
|
-
}
|
|
147
|
-
if (!flagBool(args, 'json')) {
|
|
148
|
-
process.stdout.write(renderPluginLifecyclePlanText(plan));
|
|
149
|
-
process.stdout.write(`\n⚠ DESTRUCTIVE — saved plan written to ${abs}\nApply: shrk apply ${abs} --allow-folder-ops --allow-delete-folder --verify-signature\n`);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
process.stdout.write(asJson({ saved: abs, plan }) + '\n');
|
|
153
|
-
}
|
|
154
|
-
return 0;
|
|
155
|
-
}
|
|
156
|
-
if (flagBool(args, 'json')) {
|
|
157
|
-
const body = asJson(plan);
|
|
158
|
-
if (output) {
|
|
159
|
-
const abs = writePlanFile(body, output, cwd);
|
|
160
|
-
process.stdout.write(`Wrote ${abs}\n`);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
process.stdout.write(body + '\n');
|
|
164
|
-
}
|
|
165
|
-
return 0;
|
|
166
|
-
}
|
|
167
|
-
process.stdout.write(renderPluginLifecyclePlanText(plan));
|
|
168
|
-
process.stdout.write('\n⚠ DESTRUCTIVE — human approval required before any of these steps.\n');
|
|
169
|
-
if (output) {
|
|
170
|
-
const abs = writePlanFile(asJson(plan), output, cwd);
|
|
171
|
-
process.stdout.write(`\nSaved plan to ${abs}\n`);
|
|
172
|
-
}
|
|
173
|
-
return 0;
|
|
174
|
-
},
|
|
175
|
-
};
|
|
176
|
-
export const pluginLifecycleListCommand = {
|
|
177
|
-
name: 'list',
|
|
178
|
-
description: 'List plugins detected under the profile plugin roots + profile key-table entries.',
|
|
179
|
-
usage: 'shrk plugin lifecycle list [--profile <id>] [--json]',
|
|
180
|
-
async run(args) {
|
|
181
|
-
const cwd = resolveCwd(args);
|
|
182
|
-
const resolved = await resolveProfileOrError(cwd, args);
|
|
183
|
-
if (!resolved.entry)
|
|
184
|
-
return resolved.exitCode ?? 2;
|
|
185
|
-
const listing = buildPluginLifecycleListing({ projectRoot: cwd, profile: resolved.entry.profile });
|
|
186
|
-
if (flagBool(args, 'json')) {
|
|
187
|
-
process.stdout.write(asJson(listing) + '\n');
|
|
188
|
-
return 0;
|
|
189
|
-
}
|
|
190
|
-
process.stdout.write(header(`Plugins by layer (profile=${resolved.entry.profile.id})`));
|
|
191
|
-
for (const [layer, names] of Object.entries(listing.pluginsByLayer)) {
|
|
192
|
-
process.stdout.write(` ${layer} (${names.length})\n`);
|
|
193
|
-
for (const n of names)
|
|
194
|
-
process.stdout.write(` • ${n}\n`);
|
|
195
|
-
}
|
|
196
|
-
process.stdout.write(header('Key table'));
|
|
197
|
-
for (const k of listing.pluginKeys) {
|
|
198
|
-
process.stdout.write(` ${k.key.padEnd(28)} '${k.value}'\n`);
|
|
199
|
-
}
|
|
200
|
-
return 0;
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
|
-
export const pluginLifecycleInspectCommand = {
|
|
204
|
-
name: 'inspect',
|
|
205
|
-
description: 'Inspect a plugin: which layers reference it, key-table entry, barrels.',
|
|
206
|
-
usage: 'shrk plugin lifecycle inspect <name> [--profile <id>] [--json]',
|
|
207
|
-
async run(args) {
|
|
208
|
-
const name = args.positional[0];
|
|
209
|
-
if (!name) {
|
|
210
|
-
process.stderr.write('Usage: shrk plugin lifecycle inspect <name>\n');
|
|
211
|
-
return 2;
|
|
212
|
-
}
|
|
213
|
-
const cwd = resolveCwd(args);
|
|
214
|
-
const resolved = await resolveProfileOrError(cwd, args);
|
|
215
|
-
if (!resolved.entry)
|
|
216
|
-
return resolved.exitCode ?? 2;
|
|
217
|
-
const listing = buildPluginLifecycleListing({ projectRoot: cwd, profile: resolved.entry.profile });
|
|
218
|
-
const presentInLayers = Object.entries(listing.pluginsByLayer)
|
|
219
|
-
.filter(([, names]) => names.includes(name))
|
|
220
|
-
.map(([layer]) => layer);
|
|
221
|
-
const keyEntry = listing.pluginKeys.find((k) => k.value === name);
|
|
222
|
-
const report = {
|
|
223
|
-
name,
|
|
224
|
-
profile: resolved.entry.profile.id,
|
|
225
|
-
presentInLayers,
|
|
226
|
-
pluginKeysEntry: keyEntry ?? null,
|
|
227
|
-
};
|
|
228
|
-
if (flagBool(args, 'json')) {
|
|
229
|
-
process.stdout.write(asJson(report) + '\n');
|
|
230
|
-
return 0;
|
|
231
|
-
}
|
|
232
|
-
process.stdout.write(header(`Plugin inspect: ${name}`));
|
|
233
|
-
process.stdout.write(` profile ${resolved.entry.profile.id}\n`);
|
|
234
|
-
process.stdout.write(` layers ${presentInLayers.length > 0 ? presentInLayers.join(', ') : '(none)'}\n`);
|
|
235
|
-
process.stdout.write(` key entry ${keyEntry ? `${keyEntry.key} = '${keyEntry.value}'` : '(not registered)'}\n`);
|
|
236
|
-
return 0;
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
export const pluginLifecycleProfilesCommand = {
|
|
240
|
-
name: 'profiles',
|
|
241
|
-
description: 'List registered plugin lifecycle profiles (pack + local).',
|
|
242
|
-
usage: 'shrk plugin lifecycle profiles [--json]',
|
|
243
|
-
async run(args) {
|
|
244
|
-
const cwd = resolveCwd(args);
|
|
245
|
-
const inspection = await inspectSharkcraft({ cwd });
|
|
246
|
-
const entries = await listPluginLifecycleProfiles(inspection);
|
|
247
|
-
if (flagBool(args, 'json')) {
|
|
248
|
-
process.stdout.write(asJson(entries) + '\n');
|
|
249
|
-
return 0;
|
|
250
|
-
}
|
|
251
|
-
process.stdout.write(header('Plugin lifecycle profiles'));
|
|
252
|
-
if (entries.length === 0) {
|
|
253
|
-
process.stdout.write(' (none registered — contribute via a pack manifest "pluginLifecycleProfileFiles" entry or sharkcraft/plugin-lifecycle-profiles.ts)\n');
|
|
254
|
-
return 0;
|
|
255
|
-
}
|
|
256
|
-
for (const e of entries) {
|
|
257
|
-
const src = e.source === 'pack' ? `pack:${e.packageName}` : e.source;
|
|
258
|
-
process.stdout.write(` • ${e.profile.id.padEnd(20)} ${e.profile.title} [${src}]\n`);
|
|
259
|
-
if (e.profile.description) {
|
|
260
|
-
process.stdout.write(` ${e.profile.description}\n`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return 0;
|
|
264
|
-
},
|
|
265
|
-
};
|
|
266
|
-
export const pluginLifecycleProfileCommand = {
|
|
267
|
-
name: 'profile',
|
|
268
|
-
description: 'Show a single plugin lifecycle profile.',
|
|
269
|
-
usage: 'shrk plugin lifecycle profile <id> [--json]',
|
|
270
|
-
async run(args) {
|
|
271
|
-
const id = args.positional[0];
|
|
272
|
-
if (!id) {
|
|
273
|
-
process.stderr.write('Usage: shrk plugin lifecycle profile <id>\n');
|
|
274
|
-
return 2;
|
|
275
|
-
}
|
|
276
|
-
const cwd = resolveCwd(args);
|
|
277
|
-
const inspection = await inspectSharkcraft({ cwd });
|
|
278
|
-
const entries = await listPluginLifecycleProfiles(inspection);
|
|
279
|
-
const entry = entries.find((e) => e.profile.id === id);
|
|
280
|
-
if (!entry) {
|
|
281
|
-
process.stderr.write(`Unknown profile "${id}". Available: ${entries.length === 0 ? '(none)' : entries.map((e) => e.profile.id).join(', ')}.\n`);
|
|
282
|
-
return 2;
|
|
283
|
-
}
|
|
284
|
-
if (flagBool(args, 'json')) {
|
|
285
|
-
process.stdout.write(asJson(entry) + '\n');
|
|
286
|
-
return 0;
|
|
287
|
-
}
|
|
288
|
-
process.stdout.write(header(`Profile ${entry.profile.id}`));
|
|
289
|
-
process.stdout.write(` title ${entry.profile.title}\n`);
|
|
290
|
-
if (entry.profile.description)
|
|
291
|
-
process.stdout.write(` description ${entry.profile.description}\n`);
|
|
292
|
-
process.stdout.write(` source ${entry.source}${entry.packageName ? ' (' + entry.packageName + ')' : ''}\n`);
|
|
293
|
-
process.stdout.write(` sourceFile ${entry.sourceFile}\n`);
|
|
294
|
-
process.stdout.write(` pluginRoots:\n`);
|
|
295
|
-
for (const r of entry.profile.pluginRoots) {
|
|
296
|
-
process.stdout.write(` • ${r.id.padEnd(12)} ${r.path}${r.kind ? ' [' + r.kind + ']' : ''}\n`);
|
|
297
|
-
}
|
|
298
|
-
if (entry.profile.barrels && entry.profile.barrels.length > 0) {
|
|
299
|
-
process.stdout.write(` barrels:\n`);
|
|
300
|
-
for (const b of entry.profile.barrels) {
|
|
301
|
-
process.stdout.write(` • ${b.id.padEnd(12)} ${b.path}\n`);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
if (entry.profile.keyTable) {
|
|
305
|
-
process.stdout.write(` keyTable ${entry.profile.keyTable.path} (key=${entry.profile.keyTable.keyCase} value=${entry.profile.keyTable.valueCase})\n`);
|
|
306
|
-
}
|
|
307
|
-
if (entry.profile.validationCommands && entry.profile.validationCommands.length > 0) {
|
|
308
|
-
process.stdout.write(` validation:\n`);
|
|
309
|
-
for (const c of entry.profile.validationCommands)
|
|
310
|
-
process.stdout.write(` $ ${c}\n`);
|
|
311
|
-
}
|
|
312
|
-
return 0;
|
|
313
|
-
},
|
|
314
|
-
};
|
|
315
|
-
export const pluginLifecycleDoctorCommand = {
|
|
316
|
-
name: 'doctor',
|
|
317
|
-
description: 'Lifecycle-profile doctor: surface load issues + check profile paths exist.',
|
|
318
|
-
usage: 'shrk plugin lifecycle doctor [--profile <id>] [--json]',
|
|
319
|
-
async run(args) {
|
|
320
|
-
const cwd = resolveCwd(args);
|
|
321
|
-
const inspection = await inspectSharkcraft({ cwd });
|
|
322
|
-
const profileId = flagString(args, 'profile');
|
|
323
|
-
const issues = [...(await listPluginLifecycleProfileIssues(inspection))];
|
|
324
|
-
const healthByProfile = {};
|
|
325
|
-
const entries = await listPluginLifecycleProfiles(inspection);
|
|
326
|
-
const targets = profileId ? entries.filter((e) => e.profile.id === profileId) : entries;
|
|
327
|
-
if (profileId && targets.length === 0) {
|
|
328
|
-
process.stderr.write(`Unknown profile "${profileId}". Available: ${entries.map((e) => e.profile.id).join(', ') || '(none)'}.\n`);
|
|
329
|
-
return 2;
|
|
330
|
-
}
|
|
331
|
-
for (const e of targets) {
|
|
332
|
-
healthByProfile[e.profile.id] = checkPluginLifecycleProfileHealth(cwd, e.profile);
|
|
333
|
-
}
|
|
334
|
-
if (flagBool(args, 'json')) {
|
|
335
|
-
process.stdout.write(asJson({ registryIssues: issues, healthByProfile }) + '\n');
|
|
336
|
-
return 0;
|
|
337
|
-
}
|
|
338
|
-
process.stdout.write(header('Lifecycle profile doctor'));
|
|
339
|
-
if (issues.length === 0) {
|
|
340
|
-
process.stdout.write(' Registry: ok (no load issues)\n');
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
process.stdout.write(` Registry issues (${issues.length}):\n`);
|
|
344
|
-
for (const i of issues) {
|
|
345
|
-
process.stdout.write(` ${i.severity.padEnd(7)} [${i.code}] ${i.message}\n`);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
for (const [id, checks] of Object.entries(healthByProfile)) {
|
|
349
|
-
process.stdout.write(`\n ${id}:\n`);
|
|
350
|
-
for (const c of checks) {
|
|
351
|
-
process.stdout.write(` ${c.severity.padEnd(7)} ${c.message}\n`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return 0;
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
export const pluginLifecycleCommand = {
|
|
358
|
-
name: 'lifecycle',
|
|
359
|
-
description: 'Inspect / list profile-driven plugins; manage lifecycle profiles.',
|
|
360
|
-
usage: 'shrk plugin lifecycle list|inspect|profiles|profile|doctor ...',
|
|
361
|
-
async run(args) {
|
|
362
|
-
const sub = args.positional[0];
|
|
363
|
-
args.positional = args.positional.slice(1);
|
|
364
|
-
if (sub === 'list')
|
|
365
|
-
return pluginLifecycleListCommand.run(args);
|
|
366
|
-
if (sub === 'inspect')
|
|
367
|
-
return pluginLifecycleInspectCommand.run(args);
|
|
368
|
-
if (sub === 'profiles')
|
|
369
|
-
return pluginLifecycleProfilesCommand.run(args);
|
|
370
|
-
if (sub === 'profile')
|
|
371
|
-
return pluginLifecycleProfileCommand.run(args);
|
|
372
|
-
if (sub === 'doctor')
|
|
373
|
-
return pluginLifecycleDoctorCommand.run(args);
|
|
374
|
-
process.stderr.write('Usage: shrk plugin lifecycle list|inspect|profiles|profile|doctor ...\n');
|
|
375
|
-
return 2;
|
|
376
|
-
},
|
|
377
|
-
};
|
|
378
|
-
export const pluginCommand = {
|
|
379
|
-
name: 'plugin',
|
|
380
|
-
description: 'Plugin lifecycle helpers (profile-driven). Plan-only — every command emits a structured plan that a human must review and apply.',
|
|
381
|
-
usage: 'shrk plugin rename|remove|lifecycle ...',
|
|
382
|
-
async run(args) {
|
|
383
|
-
const sub = args.positional[0];
|
|
384
|
-
args.positional = args.positional.slice(1);
|
|
385
|
-
if (sub === 'rename')
|
|
386
|
-
return pluginRenameCommand.run(args);
|
|
387
|
-
if (sub === 'remove')
|
|
388
|
-
return pluginRemoveCommand.run(args);
|
|
389
|
-
if (sub === 'lifecycle')
|
|
390
|
-
return pluginLifecycleCommand.run(args);
|
|
391
|
-
process.stderr.write('Usage: shrk plugin rename|remove|lifecycle ...\n');
|
|
392
|
-
return 2;
|
|
393
|
-
},
|
|
394
|
-
};
|