@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
|
@@ -179,10 +179,10 @@ async function applyPresetInit(cwd, mode) {
|
|
|
179
179
|
renderPathsAdvisory(pathsAdvisory);
|
|
180
180
|
}
|
|
181
181
|
process.stdout.write('\nNext:\n');
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
]) {
|
|
182
|
+
process.stdout.write(bullet('$ shrk doctor — verify the setup (shape-aware verdict)') + '\n');
|
|
183
|
+
process.stdout.write(bullet('$ shrk brief — single-page brief Claude reads first') + '\n');
|
|
184
|
+
process.stdout.write(bullet('$ shrk export claude-skill --write — inline the rules into Claude\'s prompt via .claude/skills/') + '\n');
|
|
185
|
+
for (const cmd of preset.recommendedNextCommands ?? []) {
|
|
186
186
|
process.stdout.write(bullet(`$ ${cmd}`) + '\n');
|
|
187
187
|
}
|
|
188
188
|
process.stdout.write(bullet('Start the MCP server: `shrk mcp serve` (or run it via Claude Code)') + '\n');
|
|
@@ -243,13 +243,23 @@ function applyLegacyInit(cwd, force) {
|
|
|
243
243
|
}
|
|
244
244
|
export const initCommand = {
|
|
245
245
|
name: 'init',
|
|
246
|
-
description: 'Initialize a sharkcraft/ folder in the current repository. Pass --preset <id> to apply a built-in preset (default: generic). Use --zero-config or --preset auto to detect the workspace and pick a preset automatically. Use --legacy for the full pre-preset seed.',
|
|
247
|
-
usage: 'shrk init [--preset <id|auto>] [--zero-config] [--dry-run] [--write] [--legacy] [--force] [--merge] [--suggest-only] [--no-gitignore] [--surface-profile <id>]',
|
|
246
|
+
description: 'Initialize a sharkcraft/ folder in the current repository. Pass --preset <id> to apply a built-in preset (default: generic). Use --zero-config or --preset auto to detect the workspace and pick a preset automatically. Use --legacy for the full pre-preset seed. Pass --infer to scan the repo and populate sharkcraft/* with the real signals it finds (paths from disk, rules from tsconfig/package.json, boundaries from layer structure) — combines with --preset to add inferred entries on top of the preset baseline. Pass --with-claude-skill to also generate .claude/skills/<name>/SKILL.md so Claude Code picks up the rules automatically.',
|
|
247
|
+
usage: 'shrk init [--preset <id|auto>] [--zero-config] [--infer] [--dry-run] [--write] [--with-claude-skill] [--legacy] [--force] [--merge] [--suggest-only] [--no-gitignore] [--surface-profile <id>]',
|
|
248
248
|
async run(args) {
|
|
249
249
|
const force = flagBool(args, 'force');
|
|
250
250
|
const merge = flagBool(args, 'merge');
|
|
251
251
|
const cwd = resolveCwd(args);
|
|
252
|
+
const wantInfer = flagBool(args, 'infer');
|
|
252
253
|
const skipGitignore = flagBool(args, 'no-gitignore');
|
|
254
|
+
// `--infer` mode short-circuits the preset path entirely. The
|
|
255
|
+
// inferred output IS the populated sharkcraft/*, no preset
|
|
256
|
+
// baseline to merge against. This is the cleaner contract: the
|
|
257
|
+
// user opted into "scan my repo and tell me what's there", and
|
|
258
|
+
// adding a preset's static defaults on top would muddy the
|
|
259
|
+
// confidence reporting in .inferred-report.md.
|
|
260
|
+
if (wantInfer) {
|
|
261
|
+
return runInferInit(cwd, args, force);
|
|
262
|
+
}
|
|
253
263
|
if (flagBool(args, 'legacy')) {
|
|
254
264
|
const code = applyLegacyInit(cwd, force);
|
|
255
265
|
if (code === 0 && !skipGitignore) {
|
|
@@ -310,7 +320,7 @@ export const initCommand = {
|
|
|
310
320
|
if (dryRun) {
|
|
311
321
|
process.stdout.write(`Surface profile: ${surfaceDecision.profile} (${surfaceDecision.source}) — ${surfaceDecision.reason}\n`);
|
|
312
322
|
}
|
|
313
|
-
|
|
323
|
+
const presetCode = await applyPresetInit(cwd, {
|
|
314
324
|
presetId,
|
|
315
325
|
dryRun,
|
|
316
326
|
force,
|
|
@@ -320,5 +330,139 @@ export const initCommand = {
|
|
|
320
330
|
surfaceProfile: surfaceDecision.profile,
|
|
321
331
|
surfaceProfileReason: surfaceDecision.reason,
|
|
322
332
|
});
|
|
333
|
+
// `--with-claude-skill` chains the claude-skill export onto the init
|
|
334
|
+
// so a fresh user goes from `npx shrk init --with-claude-skill --write`
|
|
335
|
+
// to a working .claude/skills/<name>/SKILL.md in one step. Skipped in
|
|
336
|
+
// dry-run + when init itself didn't succeed.
|
|
337
|
+
if (presetCode === 0 &&
|
|
338
|
+
!dryRun &&
|
|
339
|
+
(flagBool(args, 'with-claude-skill') || flagBool(args, 'with-skill'))) {
|
|
340
|
+
const skillCode = await runClaudeSkillExportAfterInit(cwd, force);
|
|
341
|
+
// Init success is what we report; skill failure is logged but
|
|
342
|
+
// doesn't fail the init exit code (otherwise users would see a
|
|
343
|
+
// half-applied repo with a non-zero exit and panic).
|
|
344
|
+
if (skillCode !== 0) {
|
|
345
|
+
process.stderr.write('\n(claude-skill export failed — re-run `shrk export claude-skill --write` to retry.)\n');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return presetCode;
|
|
323
349
|
},
|
|
324
350
|
};
|
|
351
|
+
/**
|
|
352
|
+
* Chain the claude-skill export onto a successful init. Loads the
|
|
353
|
+
* exporter lazily (it depends on inspectSharkcraft which has its own
|
|
354
|
+
* caching) and writes the skill file using the same `--force` semantics
|
|
355
|
+
* as init itself.
|
|
356
|
+
*/
|
|
357
|
+
/**
|
|
358
|
+
* `shrk init --infer` — scan the repo and populate `sharkcraft/*`
|
|
359
|
+
* with the real signals it finds, instead of writing preset defaults.
|
|
360
|
+
*
|
|
361
|
+
* Pipeline:
|
|
362
|
+
* 1. `inspectSharkcraft({ cwd })` builds the full inspection.
|
|
363
|
+
* 2. `buildOnboardingPlan(inspection)` extracts inferred paths,
|
|
364
|
+
* rules, boundaries, pipelines, verification commands.
|
|
365
|
+
* 3. `synthesizeFromOnboarding(plan)` triages each entry by
|
|
366
|
+
* confidence and emits populated `sharkcraft/*.ts` files plus
|
|
367
|
+
* a companion `.inferred-report.md` + `.inferred-report.json`.
|
|
368
|
+
* 4. Writer respects `--dry-run` / `--write` / `--force` /
|
|
369
|
+
* `--with-claude-skill` semantics consistently with the
|
|
370
|
+
* preset-init path.
|
|
371
|
+
*
|
|
372
|
+
* Honest-by-default: every adopted entry is tagged with its source
|
|
373
|
+
* signal; medium-confidence rows get a `// TODO: review` marker; low-
|
|
374
|
+
* confidence rows are dropped from the populated files and listed in
|
|
375
|
+
* the report so the user knows exactly what was inferred vs needs
|
|
376
|
+
* authoring.
|
|
377
|
+
*/
|
|
378
|
+
async function runInferInit(cwd, args, force) {
|
|
379
|
+
const { inspectSharkcraft, buildOnboardingPlan, synthesizeFromOnboarding } = await import('@shrkcrft/inspector');
|
|
380
|
+
const dryRun = !flagBool(args, 'write');
|
|
381
|
+
const sharkcraftDir = nodePath.join(cwd, 'sharkcraft');
|
|
382
|
+
process.stdout.write(header('SharkCraft init — infer'));
|
|
383
|
+
process.stdout.write(`Folder: ${sharkcraftDir}\n`);
|
|
384
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
385
|
+
const plan = buildOnboardingPlan(inspection);
|
|
386
|
+
const result = synthesizeFromOnboarding(plan);
|
|
387
|
+
// Summary block — print BEFORE writing so the user can ctrl-C if the
|
|
388
|
+
// confidence triage doesn't look right.
|
|
389
|
+
process.stdout.write(`\nDetected profiles: ${plan.projectSummary.profiles.join(', ') || '(none)'}\n`);
|
|
390
|
+
process.stdout.write(`Inference triage: ${result.report.adoptedHigh.length} adopted directly · ` +
|
|
391
|
+
`${result.report.adoptedMedium.length} marked for review · ` +
|
|
392
|
+
`${result.report.dropped.length} dropped (in report).\n\n`);
|
|
393
|
+
const written = [];
|
|
394
|
+
const skipped = [];
|
|
395
|
+
const wouldWrite = [];
|
|
396
|
+
for (const file of result.files) {
|
|
397
|
+
const fullPath = nodePath.join(sharkcraftDir, file.path);
|
|
398
|
+
if (dryRun) {
|
|
399
|
+
wouldWrite.push(file.path);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
mkdirSync(nodePath.dirname(fullPath), { recursive: true });
|
|
403
|
+
if (existsSync(fullPath) && !force) {
|
|
404
|
+
skipped.push(file.path);
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
writeFileSync(fullPath, file.content, 'utf8');
|
|
408
|
+
written.push(file.path);
|
|
409
|
+
}
|
|
410
|
+
if (dryRun) {
|
|
411
|
+
process.stdout.write('Would write:\n');
|
|
412
|
+
for (const p of wouldWrite)
|
|
413
|
+
process.stdout.write(bullet(p) + '\n');
|
|
414
|
+
process.stdout.write('\nRe-run with --write to persist.\n');
|
|
415
|
+
return 0;
|
|
416
|
+
}
|
|
417
|
+
if (written.length) {
|
|
418
|
+
process.stdout.write('Wrote:\n');
|
|
419
|
+
for (const p of written)
|
|
420
|
+
process.stdout.write(bullet(p) + '\n');
|
|
421
|
+
}
|
|
422
|
+
if (skipped.length) {
|
|
423
|
+
process.stdout.write('\nSkipped (already exist; use --force to overwrite):\n');
|
|
424
|
+
for (const p of skipped)
|
|
425
|
+
process.stdout.write(bullet(p) + '\n');
|
|
426
|
+
}
|
|
427
|
+
process.stdout.write(`\nRead the confidence report: \`${nodePath.join('sharkcraft', '.inferred-report.md')}\`\n` +
|
|
428
|
+
`It lists what was adopted high-confidence, what's marked for your review, ` +
|
|
429
|
+
`and what shrk can't infer (project-specific decisions you should author by hand).\n`);
|
|
430
|
+
process.stdout.write('\nNext:\n');
|
|
431
|
+
process.stdout.write(bullet('$ shrk doctor — verify the setup (shape-aware verdict)') + '\n');
|
|
432
|
+
process.stdout.write(bullet('$ shrk brief — single-page brief Claude reads first') + '\n');
|
|
433
|
+
process.stdout.write(bullet('$ shrk export claude-skill --write — inline the rules into Claude\'s prompt') + '\n');
|
|
434
|
+
// Chain claude-skill if requested.
|
|
435
|
+
if (flagBool(args, 'with-claude-skill') || flagBool(args, 'with-skill')) {
|
|
436
|
+
const skillCode = await runClaudeSkillExportAfterInit(cwd, force);
|
|
437
|
+
if (skillCode !== 0) {
|
|
438
|
+
process.stderr.write('\n(claude-skill export failed — re-run `shrk export claude-skill --write` to retry.)\n');
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Gitignore + paths advisory same as preset path.
|
|
442
|
+
const skipGitignore = flagBool(args, 'no-gitignore');
|
|
443
|
+
if (!skipGitignore) {
|
|
444
|
+
const patch = ensureSharkcraftGitignore({ cwd, dryRun: false });
|
|
445
|
+
if (patch.added.length > 0) {
|
|
446
|
+
process.stdout.write('\n' + renderGitignorePatch(patch, false));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return 0;
|
|
450
|
+
}
|
|
451
|
+
async function runClaudeSkillExportAfterInit(cwd, force) {
|
|
452
|
+
const { inspectSharkcraft } = await import('@shrkcrft/inspector');
|
|
453
|
+
const { renderExport } = await import("../export/export-formats.js");
|
|
454
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
455
|
+
const result = renderExport(inspection, { format: 'claude-skill' });
|
|
456
|
+
const outputPath = nodePath.join(cwd, result.suggestedPath);
|
|
457
|
+
mkdirSync(nodePath.dirname(outputPath), { recursive: true });
|
|
458
|
+
if (existsSync(outputPath) && !force) {
|
|
459
|
+
process.stdout.write(`\nSkipped claude-skill export — ${result.suggestedPath} already exists. Pass --force to overwrite, or run \`shrk export claude-skill --write --force\`.\n`);
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
462
|
+
writeFileSync(outputPath, result.content, 'utf8');
|
|
463
|
+
process.stdout.write('\n');
|
|
464
|
+
process.stdout.write(header('Claude-skill exported'));
|
|
465
|
+
process.stdout.write(`Wrote ${result.suggestedPath}\n` +
|
|
466
|
+
` → Claude Code will auto-load this skill in any session opened against this repo.\n`);
|
|
467
|
+
return 0;
|
|
468
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
-
export type PackKind = 'generic' | 'framework' | 'architecture' | 'enterprise'
|
|
2
|
+
export type PackKind = 'generic' | 'framework' | 'architecture' | 'enterprise';
|
|
3
3
|
interface IScaffoldFile {
|
|
4
4
|
/** Path relative to the new pack root. */
|
|
5
5
|
relativePath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packs-new.d.ts","sourceRoot":"","sources":["../../src/commands/packs-new.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"packs-new.d.ts","sourceRoot":"","sources":["../../src/commands/packs-new.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAIhC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,GAAG,YAAY,CAAC;AAS/E,UAAU,aAAa;IACrB,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CAyG/E;AA0SD,eAAO,MAAM,eAAe,EAAE,eAoG7B,CAAC;AAUF,eAAO,MAAM,gBAAgB,EAAE,eAqI9B,CAAC"}
|
|
@@ -1,21 +1,13 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
1
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
10
2
|
import * as nodePath from 'node:path';
|
|
11
3
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
12
4
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
5
|
+
import { importModuleViaLoader } from '@shrkcrft/core';
|
|
13
6
|
const VALID_KINDS = new Set([
|
|
14
7
|
'generic',
|
|
15
8
|
'framework',
|
|
16
9
|
'architecture',
|
|
17
10
|
'enterprise',
|
|
18
|
-
'platform-adopter',
|
|
19
11
|
]);
|
|
20
12
|
/** Pure: compute the file set to write. No IO. */
|
|
21
13
|
export function planPackScaffold(input) {
|
|
@@ -108,12 +100,6 @@ export function planPackScaffold(input) {
|
|
|
108
100
|
body: renderBoundariesAsset(),
|
|
109
101
|
});
|
|
110
102
|
}
|
|
111
|
-
if (input.kind === 'platform-adopter' || input.withExamples) {
|
|
112
|
-
files.push({
|
|
113
|
-
relativePath: 'src/assets/contracts/plugin-contract.example.ts',
|
|
114
|
-
body: renderPluginContractExample(),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
103
|
if (input.kind === 'enterprise') {
|
|
118
104
|
files.push({
|
|
119
105
|
relativePath: 'docs/review-workflow.md',
|
|
@@ -239,12 +225,6 @@ function renderKnowledgeAsset(input) {
|
|
|
239
225
|
['framework.overview', 'Framework overview', 'High', 'What this framework is for.'],
|
|
240
226
|
]);
|
|
241
227
|
}
|
|
242
|
-
if (input.kind === 'platform-adopter') {
|
|
243
|
-
return knowledgeBody([
|
|
244
|
-
['platform.policy', 'Policy capability', 'Medium', 'Describe the policy/capability model your platform exposes.'],
|
|
245
|
-
['platform.adapter', 'Adapter contract', 'Medium', 'Describe the adapter contract your platform expects.'],
|
|
246
|
-
]);
|
|
247
|
-
}
|
|
248
228
|
return knowledgeBody([
|
|
249
229
|
['pack.overview', 'Pack overview', 'Medium', 'Short overview of what this pack contributes.'],
|
|
250
230
|
]);
|
|
@@ -357,17 +337,6 @@ function renderBoundariesAsset() {
|
|
|
357
337
|
``,
|
|
358
338
|
].join('\n');
|
|
359
339
|
}
|
|
360
|
-
function renderPluginContractExample() {
|
|
361
|
-
return [
|
|
362
|
-
`// Example: an adapter-style plugin contract.`,
|
|
363
|
-
`// Replace with the actual interface your platform expects.`,
|
|
364
|
-
`export interface IPluginCapability {`,
|
|
365
|
-
` id: string;`,
|
|
366
|
-
` invoke(input: unknown): Promise<unknown>;`,
|
|
367
|
-
`}`,
|
|
368
|
-
``,
|
|
369
|
-
].join('\n');
|
|
370
|
-
}
|
|
371
340
|
function renderEnterpriseReviewDocs() {
|
|
372
341
|
return [
|
|
373
342
|
`# Review workflow`,
|
|
@@ -414,11 +383,11 @@ function renderDocsOverview(input, fullName) {
|
|
|
414
383
|
export const packsNewCommand = {
|
|
415
384
|
name: 'new',
|
|
416
385
|
description: 'Scaffold a new SharkCraft pack package (rules / paths / templates / pipelines / presets / boundaries). Dry-run by default — pass --write to materialize. No install, no publish, no overwrite without --force.',
|
|
417
|
-
usage: 'shrk [--cwd <dir>] packs new <name> [--scope @org] [--preset <id>] [--kind generic|framework|architecture|enterprise
|
|
386
|
+
usage: 'shrk [--cwd <dir>] packs new <name> [--scope @org] [--preset <id>] [--kind generic|framework|architecture|enterprise] [--with-examples] [--write] [--force] [--json]',
|
|
418
387
|
async run(args) {
|
|
419
388
|
const name = args.positional[0];
|
|
420
389
|
if (!name) {
|
|
421
|
-
process.stderr.write('Usage: shrk packs new <name> [--scope @org] [--preset <id>] [--kind generic|framework|architecture|enterprise
|
|
390
|
+
process.stderr.write('Usage: shrk packs new <name> [--scope @org] [--preset <id>] [--kind generic|framework|architecture|enterprise] [--with-examples] [--write]\n');
|
|
422
391
|
return 2;
|
|
423
392
|
}
|
|
424
393
|
const cwd = resolveCwd(args);
|
|
@@ -645,7 +614,7 @@ async function runRuntimePackTest(input) {
|
|
|
645
614
|
if (existsSync(entry)) {
|
|
646
615
|
try {
|
|
647
616
|
const { pathToFileURL } = await import('node:url');
|
|
648
|
-
const mod = (await
|
|
617
|
+
const mod = (await importModuleViaLoader(entry));
|
|
649
618
|
const value = mod.default ?? mod;
|
|
650
619
|
const shape = describeShape(value);
|
|
651
620
|
modules.push({
|
|
@@ -692,7 +661,7 @@ async function runRuntimePackTest(input) {
|
|
|
692
661
|
continue;
|
|
693
662
|
try {
|
|
694
663
|
const { pathToFileURL } = await import('node:url');
|
|
695
|
-
const mod = (await
|
|
664
|
+
const mod = (await importModuleViaLoader(full));
|
|
696
665
|
const value = mod.default;
|
|
697
666
|
const arr = Array.isArray(value) ? value : null;
|
|
698
667
|
modules.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packs.command.d.ts","sourceRoot":"","sources":["../../src/commands/packs.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"packs.command.d.ts","sourceRoot":"","sources":["../../src/commands/packs.command.ts"],"names":[],"mappings":"AAoBA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAQhC,eAAO,MAAM,yBAAyB,EAAE,eAoCvC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,eAsGzC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eA+CnC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,eAuD9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,eAsE7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eAqDjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,eAyFhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,eAqEhC,CAAC;AA4DF,eAAO,MAAM,gBAAgB,EAAE,eA+K9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmCtC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,eAmFhC,CAAC;AAMF,eAAO,MAAM,qBAAqB,EAAE,eA4BnC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,eA+E/B,CAAC"}
|
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
1
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
10
2
|
import * as nodePath from 'node:path';
|
|
11
|
-
import { pathToFileURL } from 'node:url';
|
|
12
3
|
import { buildPackDoctorReport, buildPackSignatureStatusReport, checkPackSymbolCompat, explainPackSignatureStatus, inspectSharkcraft, mergePackReleaseChecks, runPackReleaseCheck, runPackReleaseChecksForReport, } from '@shrkcrft/inspector';
|
|
13
4
|
import { PACK_SECRET_ENV, signPackManifest, validatePackManifest, verifyPackManifest, } from '@shrkcrft/plugin-api';
|
|
14
5
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
15
6
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
7
|
+
import { importModuleViaLoader } from '@shrkcrft/core';
|
|
16
8
|
function statusLabel(valid) {
|
|
17
9
|
return valid ? 'OK ' : 'INVALID';
|
|
18
10
|
}
|
|
@@ -553,7 +545,7 @@ async function loadManifestFromPath(manifestPath) {
|
|
|
553
545
|
if (manifestPath.endsWith('.json')) {
|
|
554
546
|
return JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
555
547
|
}
|
|
556
|
-
const mod = (await
|
|
548
|
+
const mod = (await importModuleViaLoader(manifestPath));
|
|
557
549
|
return (mod.default ?? mod);
|
|
558
550
|
}
|
|
559
551
|
export const packsSignCommand = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `shrk profiles ...` — unified read-only surface for all pack-/local-
|
|
3
|
-
* contributed profiles (
|
|
3
|
+
* contributed profiles (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 (
|
|
18
|
+
description: 'List all registered profiles (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:
|
|
31
|
+
process.stdout.write(' (none — contribute via packs: 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 (
|
|
135
|
+
description: 'List / inspect pack-contributed profiles (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 consumer target replaces the previous hardcoded project target.
|
|
208
|
+
const BUILTIN_TARGET_IDS = ['sharkcraft', 'dogfood', 'synthetic', 'consumer'];
|
|
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('consumer')) {
|
|
228
|
+
const consumerRoot = flagString(args, 'consumer-root') ??
|
|
229
|
+
process.env['SHARKCRAFT_CONSUMER_ROOT'] ??
|
|
230
230
|
'';
|
|
231
|
-
if (
|
|
232
|
-
out.push({ id: '
|
|
231
|
+
if (consumerRoot && existsSync(consumerRoot)) {
|
|
232
|
+
out.push({ id: 'consumer', cwd: consumerRoot, label: `consumer:${consumerRoot}` });
|
|
233
233
|
}
|
|
234
234
|
else {
|
|
235
235
|
out.push({
|
|
236
|
-
id: '
|
|
237
|
-
cwd:
|
|
238
|
-
label: '
|
|
239
|
-
warning: '
|
|
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.',
|
|
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
|
+
* - `consumer` 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 === 'consumer') {
|
|
308
308
|
return scenario === 'unconfigured-repo' || scenario === 'pack-authoring' || scenario === 'governance';
|
|
309
309
|
}
|
|
310
310
|
return true;
|
|
@@ -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,
|
|
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.',
|
|
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,22 +399,6 @@ 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
|
-
}
|
|
418
402
|
// 10) Tests — files that look like they test the matched files.
|
|
419
403
|
const tests = [];
|
|
420
404
|
for (const f of [...scoreByPath.keys()]) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.claude/commands/` generator — emits per-project slash commands
|
|
3
|
+
* for Claude Code. Companion to `claude-skill` export, but with a
|
|
4
|
+
* different inversion semantics:
|
|
5
|
+
*
|
|
6
|
+
* - **claude-skill** loads rules into Claude's prompt automatically
|
|
7
|
+
* based on description match. Passive — Claude reads the rules.
|
|
8
|
+
* - **claude-commands** registers slash commands the USER invokes
|
|
9
|
+
* (`/new-service`, `/check-changes`). Active — the command IS the
|
|
10
|
+
* recipe; Claude follows it step-by-step.
|
|
11
|
+
*
|
|
12
|
+
* Generated commands fall into two buckets:
|
|
13
|
+
*
|
|
14
|
+
* **Static commands** (always present, project-agnostic recipes):
|
|
15
|
+
* - `/follow-shrk` — short reminder of the apply-gate flow.
|
|
16
|
+
* - `/check-changes` — runs `shrk check boundaries --changed-only`
|
|
17
|
+
* scoped to the current diff and reports back.
|
|
18
|
+
* - `/shrk-brief` — runs `shrk brief` and uses the output for the
|
|
19
|
+
* current task.
|
|
20
|
+
* - `/explain-file <path>` — per-file rules / paths / boundary
|
|
21
|
+
* lookup (pairs with `shrk advise <path>` from Phase 3).
|
|
22
|
+
*
|
|
23
|
+
* **Per-template commands** (one per id in `sharkcraft/templates.ts`):
|
|
24
|
+
* - `/new-<template-id>` — Claude runs `shrk gen <template-id>
|
|
25
|
+
* <name> --dry-run --save-plan ...`, reviews the plan, and
|
|
26
|
+
* applies via `shrk apply ... --verify-signature --validate`.
|
|
27
|
+
*
|
|
28
|
+
* Generated files are self-contained markdown — no `@shrkcrft/*`
|
|
29
|
+
* imports, no shell expansions. Each one is a complete "recipe in a
|
|
30
|
+
* file" that Claude Code reads when the user types the slash command.
|
|
31
|
+
*/
|
|
32
|
+
import type { ISharkcraftInspection } from '@shrkcrft/inspector';
|
|
33
|
+
export interface IClaudeCommandFile {
|
|
34
|
+
/** Path relative to project root (e.g. `.claude/commands/new-service.md`). */
|
|
35
|
+
path: string;
|
|
36
|
+
/** Full markdown body, including YAML frontmatter. */
|
|
37
|
+
content: string;
|
|
38
|
+
/** The slash name users type (e.g. `new-service` → `/new-service`). */
|
|
39
|
+
slash: string;
|
|
40
|
+
/** Why this command was generated — surfaces in the dry-run summary. */
|
|
41
|
+
source: 'static' | 'template';
|
|
42
|
+
}
|
|
43
|
+
export interface IClaudeCommandsResult {
|
|
44
|
+
files: readonly IClaudeCommandFile[];
|
|
45
|
+
}
|
|
46
|
+
export interface IClaudeCommandsOptions {
|
|
47
|
+
/**
|
|
48
|
+
* Cap on the number of per-template commands to emit. Default 20.
|
|
49
|
+
* Templates are sorted by id; the first N are kept.
|
|
50
|
+
*/
|
|
51
|
+
maxTemplateCommands?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the full set of `.claude/commands/*.md` files for a project.
|
|
55
|
+
*
|
|
56
|
+
* Pure — caller writes the bytes. Same shape as the `synthesize-*`
|
|
57
|
+
* functions in this codebase: input inspection → output file list.
|
|
58
|
+
*/
|
|
59
|
+
export declare function buildClaudeCommands(inspection: ISharkcraftInspection, options?: IClaudeCommandsOptions): IClaudeCommandsResult;
|
|
60
|
+
//# sourceMappingURL=claude-commands-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-commands-export.d.ts","sourceRoot":"","sources":["../../src/export/claude-commands-export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACtC;AA0MD,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,qBAAqB,EACjC,OAAO,GAAE,sBAA2B,GACnC,qBAAqB,CAsDvB"}
|