@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.
Files changed (74) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/boundaries.command.d.ts.map +1 -1
  3. package/dist/commands/boundaries.command.js +12 -0
  4. package/dist/commands/check.command.d.ts.map +1 -1
  5. package/dist/commands/check.command.js +30 -20
  6. package/dist/commands/command-catalog.d.ts +3 -7
  7. package/dist/commands/command-catalog.d.ts.map +1 -1
  8. package/dist/commands/command-catalog.js +47 -113
  9. package/dist/commands/commands.command.d.ts.map +1 -1
  10. package/dist/commands/commands.command.js +4 -4
  11. package/dist/commands/constructs.command.d.ts.map +1 -1
  12. package/dist/commands/constructs.command.js +22 -5
  13. package/dist/commands/doctor.command.d.ts.map +1 -1
  14. package/dist/commands/doctor.command.js +9 -42
  15. package/dist/commands/export.command.d.ts.map +1 -1
  16. package/dist/commands/export.command.js +3 -76
  17. package/dist/commands/help.command.d.ts +3 -4
  18. package/dist/commands/help.command.d.ts.map +1 -1
  19. package/dist/commands/help.command.js +21 -77
  20. package/dist/commands/helper.command.js +1 -1
  21. package/dist/commands/import.command.d.ts.map +1 -1
  22. package/dist/commands/import.command.js +5 -121
  23. package/dist/commands/init.command.d.ts.map +1 -1
  24. package/dist/commands/init.command.js +16 -184
  25. package/dist/commands/mcp.command.d.ts.map +1 -1
  26. package/dist/commands/mcp.command.js +131 -2
  27. package/dist/commands/onboard.command.d.ts.map +1 -1
  28. package/dist/commands/onboard.command.js +15 -3
  29. package/dist/commands/packs-new.d.ts +1 -1
  30. package/dist/commands/packs-new.d.ts.map +1 -1
  31. package/dist/commands/packs-new.js +36 -5
  32. package/dist/commands/packs.command.d.ts.map +1 -1
  33. package/dist/commands/packs.command.js +17 -3
  34. package/dist/commands/plugin.command.d.ts +11 -0
  35. package/dist/commands/plugin.command.d.ts.map +1 -0
  36. package/dist/commands/plugin.command.js +394 -0
  37. package/dist/commands/profiles.command.js +4 -4
  38. package/dist/commands/release.command.js +13 -13
  39. package/dist/commands/review.command.d.ts.map +1 -1
  40. package/dist/commands/review.command.js +28 -2
  41. package/dist/commands/search.command.js +1 -1
  42. package/dist/commands/task-context.command.js +16 -0
  43. package/dist/export/export-formats.d.ts +1 -1
  44. package/dist/export/export-formats.d.ts.map +1 -1
  45. package/dist/export/export-formats.js +12 -139
  46. package/dist/init/init-templates.d.ts.map +1 -1
  47. package/dist/init/init-templates.js +113 -133
  48. package/dist/main.d.ts +1 -1
  49. package/dist/main.d.ts.map +1 -1
  50. package/dist/main.js +46 -117
  51. package/dist/output/failure-hints.d.ts +9 -1
  52. package/dist/output/failure-hints.d.ts.map +1 -1
  53. package/dist/output/failure-hints.js +8 -2
  54. package/dist/output/watch-loop.d.ts +1 -9
  55. package/dist/output/watch-loop.d.ts.map +1 -1
  56. package/dist/output/watch-loop.js +3 -13
  57. package/dist/schemas/json-schemas.d.ts +36 -36
  58. package/dist/schemas/json-schemas.js +36 -36
  59. package/dist/surface/about.d.ts.map +1 -1
  60. package/dist/surface/about.js +15 -37
  61. package/dist/surface/no-args-landing.d.ts.map +1 -1
  62. package/dist/surface/no-args-landing.js +13 -9
  63. package/dist/surface/surface-config-writer.d.ts.map +1 -1
  64. package/dist/surface/surface-config-writer.js +11 -23
  65. package/package.json +25 -26
  66. package/dist/commands/diff-check.command.d.ts +0 -30
  67. package/dist/commands/diff-check.command.d.ts.map +0 -1
  68. package/dist/commands/diff-check.command.js +0 -210
  69. package/dist/export/claude-commands-export.d.ts +0 -60
  70. package/dist/export/claude-commands-export.d.ts.map +0 -1
  71. package/dist/export/claude-commands-export.js +0 -276
  72. package/dist/init/paths-advisory.d.ts +0 -20
  73. package/dist/init/paths-advisory.d.ts.map +0 -1
  74. 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 consumer target replaces the previous hardcoded project target.
208
- const BUILTIN_TARGET_IDS = ['sharkcraft', 'dogfood', 'synthetic', 'consumer'];
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('consumer')) {
228
- const consumerRoot = flagString(args, 'consumer-root') ??
229
- process.env['SHARKCRAFT_CONSUMER_ROOT'] ??
227
+ if (want('adopter')) {
228
+ const adopterRoot = flagString(args, 'adopter-root') ??
229
+ process.env['SHARKCRAFT_ADOPTER_ROOT'] ??
230
230
  '';
231
- if (consumerRoot && existsSync(consumerRoot)) {
232
- out.push({ id: 'consumer', cwd: consumerRoot, label: `consumer:${consumerRoot}` });
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: 'consumer',
237
- cwd: consumerRoot || '(unset)',
238
- label: 'consumer target',
239
- warning: 'Consumer root not set (pass --consumer-root or set SHARKCRAFT_CONSUMER_ROOT) — skipped.',
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
- * - `consumer` runs the read-only scenarios that don't write outside the
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 === 'consumer') {
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,eA+E3B,CAAC"}
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 inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
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 inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
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' | 'claude-skill' | 'cursor-rules' | 'copilot-instructions';
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,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;AAqPD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE,aAAa,GACrB,YAAY,CAmCd;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,YAAY,CAQnE;AAED,eAAO,MAAM,kBAAkB,EAAE,SAAS,YAAY,EAMpD,CAAC"}
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"}