@shrkcrft/cli 0.1.0-alpha.8 → 0.1.0-alpha.9
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/README.md +1 -1
- package/dist/commands/boundaries.command.d.ts.map +1 -1
- package/dist/commands/boundaries.command.js +12 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +30 -20
- package/dist/commands/command-catalog.d.ts +3 -7
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +47 -113
- 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 +22 -5
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +9 -42
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +3 -76
- package/dist/commands/help.command.d.ts +3 -4
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +21 -77
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +5 -121
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +16 -184
- package/dist/commands/mcp.command.d.ts.map +1 -1
- package/dist/commands/mcp.command.js +131 -2
- package/dist/commands/onboard.command.d.ts.map +1 -1
- package/dist/commands/onboard.command.js +15 -3
- 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 +36 -5
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +17 -3
- package/dist/commands/plugin.command.d.ts +11 -0
- package/dist/commands/plugin.command.d.ts.map +1 -0
- package/dist/commands/plugin.command.js +394 -0
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/review.command.d.ts.map +1 -1
- package/dist/commands/review.command.js +28 -2
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/task-context.command.js +16 -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 +12 -139
- package/dist/init/init-templates.d.ts.map +1 -1
- package/dist/init/init-templates.js +113 -133
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +46 -117
- package/dist/output/failure-hints.d.ts +9 -1
- package/dist/output/failure-hints.d.ts.map +1 -1
- package/dist/output/failure-hints.js +8 -2
- package/dist/output/watch-loop.d.ts +1 -9
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +3 -13
- package/dist/schemas/json-schemas.d.ts +36 -36
- package/dist/schemas/json-schemas.js +36 -36
- package/dist/surface/about.d.ts.map +1 -1
- package/dist/surface/about.js +15 -37
- package/dist/surface/no-args-landing.d.ts.map +1 -1
- package/dist/surface/no-args-landing.js +13 -9
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +11 -23
- package/package.json +25 -26
- package/dist/commands/diff-check.command.d.ts +0 -30
- package/dist/commands/diff-check.command.d.ts.map +0 -1
- package/dist/commands/diff-check.command.js +0 -210
- package/dist/export/claude-commands-export.d.ts +0 -60
- package/dist/export/claude-commands-export.d.ts.map +0 -1
- package/dist/export/claude-commands-export.js +0 -276
- package/dist/init/paths-advisory.d.ts +0 -20
- package/dist/init/paths-advisory.d.ts.map +0 -1
- package/dist/init/paths-advisory.js +0 -88
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,394 @@
|
|
|
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
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `shrk profiles ...` — unified read-only surface for all pack-/local-
|
|
3
|
-
* contributed profiles (migration, and future kinds).
|
|
3
|
+
* contributed profiles (plugin lifecycle, migration, and future kinds).
|
|
4
4
|
*/
|
|
5
5
|
import { findProfile, inspectSharkcraft, listProfileIssues, listProfiles, ProfileKind, } from '@shrkcrft/inspector';
|
|
6
6
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
@@ -15,7 +15,7 @@ function parseKind(value) {
|
|
|
15
15
|
}
|
|
16
16
|
export const profilesListCommand = {
|
|
17
17
|
name: 'list',
|
|
18
|
-
description: 'List all registered profiles (migration, ...).',
|
|
18
|
+
description: 'List all registered profiles (plugin-lifecycle, migration, ...).',
|
|
19
19
|
usage: 'shrk profiles list [--kind <kind>] [--json]',
|
|
20
20
|
async run(args) {
|
|
21
21
|
const cwd = resolveCwd(args);
|
|
@@ -28,7 +28,7 @@ export const profilesListCommand = {
|
|
|
28
28
|
}
|
|
29
29
|
process.stdout.write(header(`Profiles (${entries.length}${kind ? `, kind=${kind}` : ''})`));
|
|
30
30
|
if (entries.length === 0) {
|
|
31
|
-
process.stdout.write(' (none — contribute via packs: migrationProfileFiles, etc.)\n');
|
|
31
|
+
process.stdout.write(' (none — contribute via packs: pluginLifecycleProfileFiles, migrationProfileFiles, etc.)\n');
|
|
32
32
|
return 0;
|
|
33
33
|
}
|
|
34
34
|
for (const e of entries) {
|
|
@@ -132,7 +132,7 @@ export const profilesSearchCommand = {
|
|
|
132
132
|
};
|
|
133
133
|
export const profilesCommand = {
|
|
134
134
|
name: 'profiles',
|
|
135
|
-
description: 'List / inspect pack-contributed profiles (migration, conventions, …).',
|
|
135
|
+
description: 'List / inspect pack-contributed profiles (plugin-lifecycle, migration, conventions, …).',
|
|
136
136
|
usage: 'shrk profiles list|get|doctor|search ...',
|
|
137
137
|
async run(args) {
|
|
138
138
|
const sub = args.positional[0];
|
|
@@ -204,8 +204,8 @@ function resolveSmokeFlags(args) {
|
|
|
204
204
|
const noAssertions = flagBool(args, 'no-assertions');
|
|
205
205
|
return { assertionsEnabled: !noAssertions };
|
|
206
206
|
}
|
|
207
|
-
// Generic
|
|
208
|
-
const BUILTIN_TARGET_IDS = ['sharkcraft', 'dogfood', 'synthetic', '
|
|
207
|
+
// Generic adopter target replaces the previous hardcoded project target.
|
|
208
|
+
const BUILTIN_TARGET_IDS = ['sharkcraft', 'dogfood', 'synthetic', 'adopter'];
|
|
209
209
|
function resolveTargets(cwd, args, requested) {
|
|
210
210
|
const want = (id) => requested.length === 0 || requested.includes(id);
|
|
211
211
|
const out = [];
|
|
@@ -224,19 +224,19 @@ function resolveTargets(cwd, args, requested) {
|
|
|
224
224
|
writeFileSync(nodePath.join(root, 'package.json'), JSON.stringify({ name: 'sharkcraft-synth', version: '0.0.0', type: 'module' }, null, 2), 'utf8');
|
|
225
225
|
out.push({ id: 'synthetic', cwd: root, label: 'synthetic-fixture' });
|
|
226
226
|
}
|
|
227
|
-
if (want('
|
|
228
|
-
const
|
|
229
|
-
process.env['
|
|
227
|
+
if (want('adopter')) {
|
|
228
|
+
const adopterRoot = flagString(args, 'adopter-root') ??
|
|
229
|
+
process.env['SHARKCRAFT_ADOPTER_ROOT'] ??
|
|
230
230
|
'';
|
|
231
|
-
if (
|
|
232
|
-
out.push({ id: '
|
|
231
|
+
if (adopterRoot && existsSync(adopterRoot)) {
|
|
232
|
+
out.push({ id: 'adopter', cwd: adopterRoot, label: `adopter:${adopterRoot}` });
|
|
233
233
|
}
|
|
234
234
|
else {
|
|
235
235
|
out.push({
|
|
236
|
-
id: '
|
|
237
|
-
cwd:
|
|
238
|
-
label: '
|
|
239
|
-
warning: '
|
|
236
|
+
id: 'adopter',
|
|
237
|
+
cwd: adopterRoot || '(unset)',
|
|
238
|
+
label: 'adopter target',
|
|
239
|
+
warning: 'Adopter root not set (pass --adopter-root or set SHARKCRAFT_ADOPTER_ROOT) — skipped.',
|
|
240
240
|
});
|
|
241
241
|
}
|
|
242
242
|
}
|
|
@@ -292,7 +292,7 @@ async function runReleaseSmoke(args) {
|
|
|
292
292
|
* examples/dogfood-target as the fixture.
|
|
293
293
|
* - `synthetic` runs the scenarios that don't depend on a prepared source
|
|
294
294
|
* (unconfigured-repo + pack-authoring).
|
|
295
|
-
* - `
|
|
295
|
+
* - `adopter` runs the read-only scenarios that don't write outside the
|
|
296
296
|
* fixture (e.g. an external project that consumes a SharkCraft pack).
|
|
297
297
|
*/
|
|
298
298
|
function isScenarioApplicableTo(scenario, target) {
|
|
@@ -304,7 +304,7 @@ function isScenarioApplicableTo(scenario, target) {
|
|
|
304
304
|
if (target.id === 'dogfood') {
|
|
305
305
|
return scenario === 'dev-workflow' || scenario === 'pr-review' || scenario === 'governance';
|
|
306
306
|
}
|
|
307
|
-
if (target.id === '
|
|
307
|
+
if (target.id === 'adopter') {
|
|
308
308
|
return scenario === 'unconfigured-repo' || scenario === 'pack-authoring' || scenario === 'governance';
|
|
309
309
|
}
|
|
310
310
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.command.d.ts","sourceRoot":"","sources":["../../src/commands/review.command.ts"],"names":[],"mappings":"AAgBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA6GhC,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"review.command.d.ts","sourceRoot":"","sources":["../../src/commands/review.command.ts"],"names":[],"mappings":"AAgBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA6GhC,eAAO,MAAM,aAAa,EAAE,eA8F3B,CAAC"}
|
|
@@ -95,8 +95,21 @@ export const reviewCommand = {
|
|
|
95
95
|
if (args.positional[0] === 'packet') {
|
|
96
96
|
return runPacket(args);
|
|
97
97
|
}
|
|
98
|
-
const
|
|
98
|
+
const cwd = resolveCwd(args);
|
|
99
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
99
100
|
const since = flagString(args, 'since');
|
|
101
|
+
if (since) {
|
|
102
|
+
const { verifyGitRef } = await import('@shrkcrft/inspector');
|
|
103
|
+
const verify = verifyGitRef(cwd, since);
|
|
104
|
+
if (!verify.valid) {
|
|
105
|
+
process.stderr.write(`error: --since ref "${since}" does not resolve to a commit in this repository.\n` +
|
|
106
|
+
(verify.suggestions && verify.suggestions.length > 0
|
|
107
|
+
? `\nDid you mean:\n${verify.suggestions.map((s) => ` --since ${s}`).join('\n')}\n`
|
|
108
|
+
: '') +
|
|
109
|
+
'\nUse `git branch -a` to list available refs.\n');
|
|
110
|
+
return 2;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
100
113
|
const files = flagList(args, 'files');
|
|
101
114
|
const packet = buildReviewPacket(inspection, {
|
|
102
115
|
...(since ? { since } : {}),
|
|
@@ -295,8 +308,21 @@ function isReviewPacketV3Shape(v) {
|
|
|
295
308
|
return v.schema === REVIEW_PACKET_V3_SCHEMA;
|
|
296
309
|
}
|
|
297
310
|
async function runPacket(args) {
|
|
298
|
-
const
|
|
311
|
+
const cwd = resolveCwd(args);
|
|
312
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
299
313
|
const since = flagString(args, 'since');
|
|
314
|
+
if (since) {
|
|
315
|
+
const { verifyGitRef } = await import('@shrkcrft/inspector');
|
|
316
|
+
const verify = verifyGitRef(cwd, since);
|
|
317
|
+
if (!verify.valid) {
|
|
318
|
+
process.stderr.write(`error: --since ref "${since}" does not resolve to a commit in this repository.\n` +
|
|
319
|
+
(verify.suggestions && verify.suggestions.length > 0
|
|
320
|
+
? `\nDid you mean:\n${verify.suggestions.map((s) => ` --since ${s}`).join('\n')}\n`
|
|
321
|
+
: '') +
|
|
322
|
+
'\nUse `git branch -a` to list available refs.\n');
|
|
323
|
+
return 2;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
300
326
|
const files = flagList(args, 'files');
|
|
301
327
|
const v2 = flagBool(args, 'v2');
|
|
302
328
|
const baselineFile = flagString(args, 'quality-baseline');
|
|
@@ -27,7 +27,7 @@ function parseSources(args) {
|
|
|
27
27
|
}
|
|
28
28
|
export const searchCommand = {
|
|
29
29
|
name: 'search',
|
|
30
|
-
description: 'Universal search across commands, MCP tools, knowledge, rules, paths, conventions, templates, helpers, playbooks, constructs, policies, decisions, scaffold patterns, contract templates, migration profiles, feedback rules, task routing hints, docs, recent reports. Default emits the 7-section unified output; pass --legacy for the flat output.',
|
|
30
|
+
description: 'Universal search across commands, MCP tools, knowledge, rules, paths, conventions, templates, helpers, playbooks, constructs, policies, decisions, scaffold patterns, contract templates, migration profiles, plugin lifecycle profiles, feedback rules, task routing hints, docs, recent reports. Default emits the 7-section unified output; pass --legacy for the flat output.',
|
|
31
31
|
usage: 'shrk search <query> [--kind <kind>] [--source local|pack|...] [--limit N] [--explain] [--commands-only] [--actions-only] [--format text|markdown|json] [--legacy]',
|
|
32
32
|
async run(args) {
|
|
33
33
|
// Sub-dispatch for `shrk search tuning [list|doctor]`.
|
|
@@ -399,6 +399,22 @@ async function collectLikelyFilesV2(input) {
|
|
|
399
399
|
}
|
|
400
400
|
}
|
|
401
401
|
}
|
|
402
|
+
// Boost files that sit on registered plugin-lifecycle profile barrels.
|
|
403
|
+
try {
|
|
404
|
+
const { listPluginLifecycleProfiles } = await import('@shrkcrft/inspector');
|
|
405
|
+
const profiles = await listPluginLifecycleProfiles(inspection);
|
|
406
|
+
for (const entry of profiles) {
|
|
407
|
+
for (const b of entry.profile.barrels ?? []) {
|
|
408
|
+
for (const f of [...scoreByPath.keys()]) {
|
|
409
|
+
if (f.includes(b.path))
|
|
410
|
+
bump(f, 3, `lifecycle profile barrel: ${b.id}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
// Profile registry unavailable — skip the boost.
|
|
417
|
+
}
|
|
402
418
|
// 10) Tests — files that look like they test the matched files.
|
|
403
419
|
const tests = [];
|
|
404
420
|
for (const f of [...scoreByPath.keys()]) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ISharkcraftInspection } from '@shrkcrft/inspector';
|
|
2
|
-
export type ExportFormat = 'agents-md' | 'claude-md' | '
|
|
2
|
+
export type ExportFormat = 'agents-md' | 'claude-md' | 'cursor-rules' | 'copilot-instructions';
|
|
3
3
|
export interface ExportOptions {
|
|
4
4
|
format: ExportFormat;
|
|
5
5
|
/** Optional task to scope the export. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-formats.d.ts","sourceRoot":"","sources":["../../src/export/export-formats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAIjE,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,WAAW,GACX,cAAc,GACd,
|
|
1
|
+
{"version":3,"file":"export-formats.d.ts","sourceRoot":"","sources":["../../src/export/export-formats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAIjE,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,WAAW,GACX,cAAc,GACd,sBAAsB,CAAC;AAE3B,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqHD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE,aAAa,GACrB,YAAY,CAsBd;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,YAAY,CAOnE;AAED,eAAO,MAAM,kBAAkB,EAAE,SAAS,YAAY,EAKpD,CAAC"}
|