@shrkcrft/cli 0.1.0-alpha.1 → 0.1.0-alpha.11
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/api-diff.command.d.ts +11 -0
- package/dist/commands/api-diff.command.d.ts.map +1 -0
- package/dist/commands/api-diff.command.js +116 -0
- package/dist/commands/arch.command.d.ts +9 -0
- package/dist/commands/arch.command.d.ts.map +1 -0
- package/dist/commands/arch.command.js +186 -0
- package/dist/commands/boundaries.command.d.ts.map +1 -1
- package/dist/commands/boundaries.command.js +0 -12
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +20 -30
- package/dist/commands/code-intel.command.d.ts +18 -0
- package/dist/commands/code-intel.command.d.ts.map +1 -0
- package/dist/commands/code-intel.command.js +146 -0
- 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 +201 -47
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/completion.command.d.ts +10 -0
- package/dist/commands/completion.command.d.ts.map +1 -0
- package/dist/commands/completion.command.js +121 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +5 -22
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +89 -0
- 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 +42 -9
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/framework.command.d.ts +12 -0
- package/dist/commands/framework.command.d.ts.map +1 -0
- package/dist/commands/framework.command.js +180 -0
- package/dist/commands/gate.command.d.ts +15 -0
- package/dist/commands/gate.command.d.ts.map +1 -0
- package/dist/commands/gate.command.js +296 -0
- package/dist/commands/graph-code-subverbs.d.ts +11 -0
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
- package/dist/commands/graph-code-subverbs.js +818 -0
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +22 -0
- 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 +77 -21
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +170 -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 +184 -16
- package/dist/commands/mcp.command.d.ts.map +1 -1
- package/dist/commands/mcp.command.js +2 -131
- package/dist/commands/migrate.command.d.ts +13 -0
- package/dist/commands/migrate.command.d.ts.map +1 -0
- package/dist/commands/migrate.command.js +152 -0
- package/dist/commands/onboard.command.d.ts.map +1 -1
- package/dist/commands/onboard.command.js +3 -15
- 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 +3 -17
- package/dist/commands/plan-context.command.d.ts +11 -0
- package/dist/commands/plan-context.command.d.ts.map +1 -0
- package/dist/commands/plan-context.command.js +77 -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 +2 -28
- package/dist/commands/rule-graph-subverbs.d.ts +3 -0
- package/dist/commands/rule-graph-subverbs.d.ts.map +1 -0
- package/dist/commands/rule-graph-subverbs.js +132 -0
- package/dist/commands/search-structural.command.d.ts +18 -0
- package/dist/commands/search-structural.command.d.ts.map +1 -0
- package/dist/commands/search-structural.command.js +376 -0
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/task-context.command.js +0 -16
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +8 -2
- package/dist/dashboard/code-intelligence-data.d.ts +33 -0
- package/dist/dashboard/code-intelligence-data.d.ts.map +1 -0
- package/dist/dashboard/code-intelligence-data.js +307 -0
- package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
- package/dist/dashboard/dashboard-api-server.js +162 -1
- 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/init/init-templates.d.ts.map +1 -1
- package/dist/init/init-templates.js +133 -113
- package/dist/init/paths-advisory.d.ts +20 -0
- package/dist/init/paths-advisory.d.ts.map +1 -0
- package/dist/init/paths-advisory.js +88 -0
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +137 -46
- package/dist/output/failure-hints.d.ts +1 -9
- package/dist/output/failure-hints.d.ts.map +1 -1
- package/dist/output/failure-hints.js +2 -8
- 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/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 +37 -15
- package/dist/surface/no-args-landing.d.ts.map +1 -1
- package/dist/surface/no-args-landing.js +9 -13
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +23 -11
- package/package.json +37 -25
- 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
|
@@ -6,6 +6,7 @@ import { listBuiltInSurfaceProfiles, suggestSurfaceProfile } from '@shrkcrft/ins
|
|
|
6
6
|
import { INIT_FILES } from "../init/init-templates.js";
|
|
7
7
|
import { buildDetectedBlock, renderDetectedBlockText } from "../init/detected-block.js";
|
|
8
8
|
import { ensureSharkcraftGitignore, renderGitignorePatch } from "../init/gitignore.js";
|
|
9
|
+
import { annotatePathsAgainstDisk } from "../init/paths-advisory.js";
|
|
9
10
|
import { applySurfaceTextEdit } from "../surface/surface-config-writer.js";
|
|
10
11
|
import { flagBool, flagString, resolveCwd } from "../command-registry.js";
|
|
11
12
|
import { bullet, header } from "../output/format-output.js";
|
|
@@ -108,8 +109,13 @@ async function applyPresetInit(cwd, mode) {
|
|
|
108
109
|
process.stdout.write(bullet(`(warning) ${warn}`) + '\n');
|
|
109
110
|
}
|
|
110
111
|
process.stdout.write('\nNext:\n');
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
for (const cmd of preset.recommendedNextCommands ?? [
|
|
113
|
+
'shrk init --zero-config --write',
|
|
114
|
+
'shrk doctor',
|
|
115
|
+
'shrk context --task "<task>"',
|
|
116
|
+
]) {
|
|
117
|
+
process.stdout.write(bullet(`$ ${cmd}`) + '\n');
|
|
118
|
+
}
|
|
113
119
|
if (!mode.skipGitignore) {
|
|
114
120
|
const patch = ensureSharkcraftGitignore({ cwd, dryRun: true });
|
|
115
121
|
process.stdout.write('\n' + renderGitignorePatch(patch, true));
|
|
@@ -128,6 +134,11 @@ async function applyPresetInit(cwd, mode) {
|
|
|
128
134
|
source: 'override',
|
|
129
135
|
});
|
|
130
136
|
}
|
|
137
|
+
// Workspace-shape advisory: when the preset emits path conventions
|
|
138
|
+
// that don't exist in this repo (common with generic presets in
|
|
139
|
+
// framework-specific repos), annotate paths.ts so the user knows
|
|
140
|
+
// which defaults to fix.
|
|
141
|
+
const pathsAdvisory = annotatePathsAgainstDisk(cwd, plan.sharkcraftDir);
|
|
131
142
|
process.stdout.write(header('SharkCraft initialized'));
|
|
132
143
|
process.stdout.write(`Preset: ${preset.id} — ${preset.title}\n`);
|
|
133
144
|
process.stdout.write(`Folder: ${plan.sharkcraftDir}\n`);
|
|
@@ -164,20 +175,29 @@ async function applyPresetInit(cwd, mode) {
|
|
|
164
175
|
process.stdout.write('\n' + renderGitignorePatch(patch, false));
|
|
165
176
|
}
|
|
166
177
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
process.stdout.write(bullet('$ shrk review packet --v3 --since main') + '\n');
|
|
170
|
-
process.stdout.write('\nOptional:\n');
|
|
171
|
-
process.stdout.write(bullet('$ shrk doctor') + '\n');
|
|
172
|
-
process.stdout.write(bullet('$ shrk mcp serve # plug into Claude Code / Cursor / Cline') + '\n');
|
|
173
|
-
if (preset.recommendedNextCommands && preset.recommendedNextCommands.length > 0) {
|
|
174
|
-
process.stdout.write('\nPreset-specific next steps:\n');
|
|
175
|
-
for (const cmd of preset.recommendedNextCommands) {
|
|
176
|
-
process.stdout.write(bullet(`$ ${cmd}`) + '\n');
|
|
177
|
-
}
|
|
178
|
+
if (pathsAdvisory.annotated) {
|
|
179
|
+
renderPathsAdvisory(pathsAdvisory);
|
|
178
180
|
}
|
|
181
|
+
process.stdout.write('\nNext:\n');
|
|
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
|
+
process.stdout.write(bullet(`$ ${cmd}`) + '\n');
|
|
187
|
+
}
|
|
188
|
+
process.stdout.write(bullet('Start the MCP server: `shrk mcp serve` (or run it via Claude Code)') + '\n');
|
|
179
189
|
return 0;
|
|
180
190
|
}
|
|
191
|
+
function renderPathsAdvisory(advisory) {
|
|
192
|
+
process.stdout.write('\n');
|
|
193
|
+
process.stdout.write(header('Paths advisory'));
|
|
194
|
+
process.stdout.write('These preset-default paths do not exist in this repo:\n');
|
|
195
|
+
for (const p of advisory.missingPaths) {
|
|
196
|
+
process.stdout.write(bullet(p) + '\n');
|
|
197
|
+
}
|
|
198
|
+
process.stdout.write('\nEdit sharkcraft/paths.ts to match your real layout. ' +
|
|
199
|
+
'Run `shrk onboard --dry-run` to see what the engine infers.\n');
|
|
200
|
+
}
|
|
181
201
|
function applyLegacyInit(cwd, force) {
|
|
182
202
|
const { root } = detectProjectRoot(cwd);
|
|
183
203
|
const sharkcraftDir = nodePath.join(root, 'sharkcraft');
|
|
@@ -211,6 +231,10 @@ function applyLegacyInit(cwd, force) {
|
|
|
211
231
|
for (const s of skipped)
|
|
212
232
|
process.stdout.write(bullet(s) + '\n');
|
|
213
233
|
}
|
|
234
|
+
const legacyAdvisory = annotatePathsAgainstDisk(cwd, sharkcraftDir);
|
|
235
|
+
if (legacyAdvisory.annotated) {
|
|
236
|
+
renderPathsAdvisory(legacyAdvisory);
|
|
237
|
+
}
|
|
214
238
|
process.stdout.write('\nNext:\n');
|
|
215
239
|
process.stdout.write(bullet('Run `shrk inspect` to see your project summary.') + '\n');
|
|
216
240
|
process.stdout.write(bullet('Run `shrk knowledge list` to see what was seeded.') + '\n');
|
|
@@ -219,13 +243,23 @@ function applyLegacyInit(cwd, force) {
|
|
|
219
243
|
}
|
|
220
244
|
export const initCommand = {
|
|
221
245
|
name: 'init',
|
|
222
|
-
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.',
|
|
223
|
-
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>]',
|
|
224
248
|
async run(args) {
|
|
225
249
|
const force = flagBool(args, 'force');
|
|
226
250
|
const merge = flagBool(args, 'merge');
|
|
227
251
|
const cwd = resolveCwd(args);
|
|
252
|
+
const wantInfer = flagBool(args, 'infer');
|
|
228
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
|
+
}
|
|
229
263
|
if (flagBool(args, 'legacy')) {
|
|
230
264
|
const code = applyLegacyInit(cwd, force);
|
|
231
265
|
if (code === 0 && !skipGitignore) {
|
|
@@ -286,7 +320,7 @@ export const initCommand = {
|
|
|
286
320
|
if (dryRun) {
|
|
287
321
|
process.stdout.write(`Surface profile: ${surfaceDecision.profile} (${surfaceDecision.source}) — ${surfaceDecision.reason}\n`);
|
|
288
322
|
}
|
|
289
|
-
|
|
323
|
+
const presetCode = await applyPresetInit(cwd, {
|
|
290
324
|
presetId,
|
|
291
325
|
dryRun,
|
|
292
326
|
force,
|
|
@@ -296,5 +330,139 @@ export const initCommand = {
|
|
|
296
330
|
surfaceProfile: surfaceDecision.profile,
|
|
297
331
|
surfaceProfileReason: surfaceDecision.reason,
|
|
298
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;
|
|
299
349
|
},
|
|
300
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.command.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.command.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAKhC,eAAO,MAAM,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"mcp.command.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.command.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAKhC,eAAO,MAAM,UAAU,EAAE,eAiCxB,CAAC"}
|
|
@@ -6,7 +6,7 @@ import { buildSurfaceSummary, findCommandInSummary } from "../surface/surface-su
|
|
|
6
6
|
export const mcpCommand = {
|
|
7
7
|
name: 'mcp',
|
|
8
8
|
description: 'MCP server operations (subcommand required).',
|
|
9
|
-
usage: 'shrk [--cwd <dir>] mcp serve [--verbose] [--watch] [--http] [--port <n>] [--host <h>]
|
|
9
|
+
usage: 'shrk [--cwd <dir>] mcp serve [--verbose] [--watch] [--http] [--port <n>] [--host <h>]',
|
|
10
10
|
async run(args) {
|
|
11
11
|
const sub = args.positional[0];
|
|
12
12
|
if (sub === 'serve') {
|
|
@@ -35,139 +35,10 @@ export const mcpCommand = {
|
|
|
35
35
|
return 1;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
const harness = args.positional[1];
|
|
40
|
-
const showAll = flagBool(args, 'all-paths');
|
|
41
|
-
if (harness !== undefined && !HARNESSES.some((h) => h.id === harness)) {
|
|
42
|
-
process.stderr.write(`Unknown harness: ${harness}\nKnown: ${HARNESSES.map((h) => h.id).join(', ')}\n`);
|
|
43
|
-
return 2;
|
|
44
|
-
}
|
|
45
|
-
process.stdout.write(renderMcpInstallInstructions(harness, showAll));
|
|
46
|
-
return 0;
|
|
47
|
-
}
|
|
48
|
-
process.stderr.write('Usage:\n' +
|
|
49
|
-
' shrk mcp serve [--http] [--port N] [--watch]\n' +
|
|
50
|
-
' shrk mcp install [claude-code|claude-desktop|cursor|cline]\n');
|
|
38
|
+
process.stderr.write('Usage: shrk mcp serve [--http] [--port N] [--watch]\n');
|
|
51
39
|
return 2;
|
|
52
40
|
},
|
|
53
41
|
};
|
|
54
|
-
const HARNESSES = [
|
|
55
|
-
{
|
|
56
|
-
id: 'claude-code',
|
|
57
|
-
label: 'Claude Code (Anthropic CLI)',
|
|
58
|
-
configPaths: [
|
|
59
|
-
{ os: '*', path: '<repo>/.mcp.json # project-scoped (preferred)' },
|
|
60
|
-
{ os: '*', path: '~/.claude.json # user-scoped (fallback)' },
|
|
61
|
-
],
|
|
62
|
-
note: 'Claude Code reads both; project-scoped wins when present.',
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
id: 'claude-desktop',
|
|
66
|
-
label: 'Claude Desktop',
|
|
67
|
-
configPaths: [
|
|
68
|
-
{ os: 'darwin', path: '~/Library/Application Support/Claude/claude_desktop_config.json' },
|
|
69
|
-
{ os: 'win32', path: '%APPDATA%\\Claude\\claude_desktop_config.json' },
|
|
70
|
-
{ os: 'linux', path: '~/.config/Claude/claude_desktop_config.json' },
|
|
71
|
-
],
|
|
72
|
-
note: 'Restart Claude Desktop after editing.',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
id: 'cursor',
|
|
76
|
-
label: 'Cursor IDE',
|
|
77
|
-
configPaths: [
|
|
78
|
-
{ os: '*', path: '~/.cursor/mcp.json # user-scoped' },
|
|
79
|
-
{ os: '*', path: '<repo>/.cursor/mcp.json # project-scoped' },
|
|
80
|
-
],
|
|
81
|
-
note: 'Cursor merges both. Reload the IDE after editing.',
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
id: 'cline',
|
|
85
|
-
label: 'Cline (VS Code extension)',
|
|
86
|
-
configPaths: [
|
|
87
|
-
{
|
|
88
|
-
os: 'darwin',
|
|
89
|
-
path: '~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json',
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
os: 'win32',
|
|
93
|
-
path: '%APPDATA%\\Code\\User\\globalStorage\\saoudrizwan.claude-dev\\settings\\cline_mcp_settings.json',
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
os: 'linux',
|
|
97
|
-
path: '~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json',
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
note: 'Reload the Cline panel after editing.',
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
function currentOs() {
|
|
104
|
-
const p = process.platform;
|
|
105
|
-
if (p === 'darwin' || p === 'win32' || p === 'linux')
|
|
106
|
-
return p;
|
|
107
|
-
return 'other';
|
|
108
|
-
}
|
|
109
|
-
function pathsForPlatform(target, showAll) {
|
|
110
|
-
if (showAll)
|
|
111
|
-
return target.configPaths.map((p) => p.path);
|
|
112
|
-
const os = currentOs();
|
|
113
|
-
const matched = target.configPaths.filter((p) => p.os === '*' || p.os === os);
|
|
114
|
-
// If the current OS has no specific entry, fall back to all to avoid an
|
|
115
|
-
// empty list. (`other` platforms like FreeBSD land here.)
|
|
116
|
-
if (matched.length === 0)
|
|
117
|
-
return target.configPaths.map((p) => p.path);
|
|
118
|
-
return matched.map((p) => p.path);
|
|
119
|
-
}
|
|
120
|
-
const SHARKCRAFT_MCP_SNIPPET = `{
|
|
121
|
-
"mcpServers": {
|
|
122
|
-
"sharkcraft": {
|
|
123
|
-
"command": "shrk",
|
|
124
|
-
"args": ["mcp", "serve"]
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}`;
|
|
128
|
-
function renderMcpInstallInstructions(harness, showAll) {
|
|
129
|
-
const lines = [];
|
|
130
|
-
if (!harness) {
|
|
131
|
-
lines.push('SharkCraft MCP server entry (universal, stdio transport):');
|
|
132
|
-
lines.push('');
|
|
133
|
-
lines.push(SHARKCRAFT_MCP_SNIPPET);
|
|
134
|
-
lines.push('');
|
|
135
|
-
lines.push('Paste it into one of these harnesses (`shrk mcp install <id>` for exact paths):');
|
|
136
|
-
lines.push('');
|
|
137
|
-
for (const h of HARNESSES) {
|
|
138
|
-
lines.push(` ${h.id.padEnd(16)} ${h.label}`);
|
|
139
|
-
}
|
|
140
|
-
lines.push('');
|
|
141
|
-
lines.push('After pasting, restart/reload the harness. The server is read-only — agents cannot write.');
|
|
142
|
-
return lines.join('\n') + '\n';
|
|
143
|
-
}
|
|
144
|
-
const target = HARNESSES.find((h) => h.id === harness);
|
|
145
|
-
if (!target) {
|
|
146
|
-
return (`Unknown harness: ${harness}\n` +
|
|
147
|
-
`Known: ${HARNESSES.map((h) => h.id).join(', ')}\n`);
|
|
148
|
-
}
|
|
149
|
-
const paths = pathsForPlatform(target, showAll);
|
|
150
|
-
const os = currentOs();
|
|
151
|
-
lines.push(`${target.label}`);
|
|
152
|
-
lines.push('');
|
|
153
|
-
lines.push(showAll || os === 'other'
|
|
154
|
-
? 'Config file (all platforms):'
|
|
155
|
-
: `Config file (${os}; pass --all-paths to see every platform):`);
|
|
156
|
-
for (const p of paths)
|
|
157
|
-
lines.push(` ${p}`);
|
|
158
|
-
lines.push('');
|
|
159
|
-
lines.push('Add this entry (merge with any existing `mcpServers` block):');
|
|
160
|
-
lines.push('');
|
|
161
|
-
lines.push(SHARKCRAFT_MCP_SNIPPET);
|
|
162
|
-
if (target.note) {
|
|
163
|
-
lines.push('');
|
|
164
|
-
lines.push(target.note);
|
|
165
|
-
}
|
|
166
|
-
lines.push('');
|
|
167
|
-
lines.push('Verify by asking the agent: "List MCP tools available." You should see ~250 sharkcraft tools.');
|
|
168
|
-
lines.push('The server is read-only — agents cannot write. Use `shrk apply --verify-signature` for writes.');
|
|
169
|
-
return lines.join('\n') + '\n';
|
|
170
|
-
}
|
|
171
42
|
/**
|
|
172
43
|
* Build the MCP tier-gate resolver from the surface summary.
|
|
173
44
|
* Returns a function that, given a tool, decides whether to refuse the
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
+
/**
|
|
3
|
+
* `shrk migrate` — run a multi-step migration definition.
|
|
4
|
+
*
|
|
5
|
+
* - shrk migrate plan <id> preview what each step would do
|
|
6
|
+
* - shrk migrate apply <id> execute the migration (writes!)
|
|
7
|
+
*
|
|
8
|
+
* Migrations live in `sharkcraft/migrations/<id>.ts` by default; pass
|
|
9
|
+
* `--from <path>` to point at a specific file. Each migration file
|
|
10
|
+
* default-exports an `IMigration` (use `defineMigration({ ... })`).
|
|
11
|
+
*/
|
|
12
|
+
export declare const migrateCommand: ICommandHandler;
|
|
13
|
+
//# sourceMappingURL=migrate.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.command.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.command.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,eAsI5B,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import * as nodePath from 'node:path';
|
|
3
|
+
import { safeImport } from '@shrkcrft/core';
|
|
4
|
+
import { applyMigration, planMigration, pruneMigrations, resumeMigration, } from '@shrkcrft/migrate';
|
|
5
|
+
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
6
|
+
import { asJson, header, kv } from "../output/format-output.js";
|
|
7
|
+
/**
|
|
8
|
+
* `shrk migrate` — run a multi-step migration definition.
|
|
9
|
+
*
|
|
10
|
+
* - shrk migrate plan <id> preview what each step would do
|
|
11
|
+
* - shrk migrate apply <id> execute the migration (writes!)
|
|
12
|
+
*
|
|
13
|
+
* Migrations live in `sharkcraft/migrations/<id>.ts` by default; pass
|
|
14
|
+
* `--from <path>` to point at a specific file. Each migration file
|
|
15
|
+
* default-exports an `IMigration` (use `defineMigration({ ... })`).
|
|
16
|
+
*/
|
|
17
|
+
export const migrateCommand = {
|
|
18
|
+
name: 'migrate',
|
|
19
|
+
description: 'Orchestrate multi-step refactors: structural rewrites + shell + checks in one named, replayable migration.',
|
|
20
|
+
usage: 'shrk migrate plan <id> [--from <path>] [--json] | shrk migrate apply <id> [--from <path>] [--dry-run] [--no-stop-on-failure] [--json] | shrk migrate resume <id> [--from <path>] [--json] | shrk migrate prune [--older-than <days>] [--include-failed] [--dry-run] [--json]',
|
|
21
|
+
async run(args) {
|
|
22
|
+
const sub = args.positional[0];
|
|
23
|
+
if (sub !== 'plan' && sub !== 'apply' && sub !== 'resume' && sub !== 'prune') {
|
|
24
|
+
process.stderr.write(this.usage + '\n');
|
|
25
|
+
return 2;
|
|
26
|
+
}
|
|
27
|
+
const cwd = resolveCwd(args);
|
|
28
|
+
const wantJson = flagBool(args, 'json');
|
|
29
|
+
if (sub === 'prune') {
|
|
30
|
+
const olderThanRaw = flagString(args, 'older-than');
|
|
31
|
+
const olderThanDays = olderThanRaw !== undefined ? Number(olderThanRaw) : undefined;
|
|
32
|
+
if (olderThanDays !== undefined && (!Number.isFinite(olderThanDays) || olderThanDays < 0)) {
|
|
33
|
+
process.stderr.write(`Invalid --older-than: ${olderThanRaw}\n`);
|
|
34
|
+
return 2;
|
|
35
|
+
}
|
|
36
|
+
const result = pruneMigrations({
|
|
37
|
+
projectRoot: cwd,
|
|
38
|
+
...(olderThanDays !== undefined ? { olderThanDays } : {}),
|
|
39
|
+
includeFailed: flagBool(args, 'include-failed'),
|
|
40
|
+
dryRun: flagBool(args, 'dry-run'),
|
|
41
|
+
});
|
|
42
|
+
if (wantJson) {
|
|
43
|
+
process.stdout.write(asJson(result) + '\n');
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
process.stdout.write(header(`Migrate prune (${result.dryRun ? 'dry-run' : 'applied'})`));
|
|
47
|
+
process.stdout.write(kv('scanned', String(result.scanned)) + '\n');
|
|
48
|
+
process.stdout.write(kv('eligible', String(result.eligible)) + '\n');
|
|
49
|
+
process.stdout.write(kv('removed', String(result.removed)) + '\n');
|
|
50
|
+
for (const e of result.entries.slice(0, 50)) {
|
|
51
|
+
process.stdout.write(` ${e.id} (${e.overall}, ${e.ageDays}d, reason=${e.reason})\n`);
|
|
52
|
+
}
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
const id = args.positional[1];
|
|
56
|
+
if (!id) {
|
|
57
|
+
process.stderr.write('Usage: shrk migrate ' + sub + ' <id>\n');
|
|
58
|
+
return 2;
|
|
59
|
+
}
|
|
60
|
+
const fromFlag = flagString(args, 'from');
|
|
61
|
+
const candidate = fromFlag
|
|
62
|
+
? (nodePath.isAbsolute(fromFlag) ? fromFlag : nodePath.resolve(cwd, fromFlag))
|
|
63
|
+
: nodePath.resolve(cwd, 'sharkcraft', 'migrations', `${id}.ts`);
|
|
64
|
+
if (!existsSync(candidate)) {
|
|
65
|
+
process.stderr.write(`Migration file not found: ${candidate}\n`);
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
const result = await safeImport(candidate);
|
|
69
|
+
if (!result.ok) {
|
|
70
|
+
process.stderr.write(`Migration load failed: ${result.error.message}\n`);
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
const migration = result.module.default ?? result.module.migration;
|
|
74
|
+
if (!migration) {
|
|
75
|
+
process.stderr.write(`Migration module ${candidate} does not export a default migration.\n`);
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
if (migration.id !== id) {
|
|
79
|
+
process.stderr.write(`Migration id mismatch: requested "${id}", file contains "${migration.id}".\n`);
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
if (sub === 'plan') {
|
|
83
|
+
const plan = planMigration(migration, cwd);
|
|
84
|
+
if (wantJson) {
|
|
85
|
+
process.stdout.write(asJson(plan) + '\n');
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
process.stdout.write(header(`Migration plan: ${plan.migration.title}`));
|
|
89
|
+
process.stdout.write(kv('id', plan.migration.id) + '\n');
|
|
90
|
+
process.stdout.write(kv('total steps', String(plan.plannedSteps.length)) + '\n');
|
|
91
|
+
process.stdout.write(kv('total edits', String(plan.totalEdits)) + '\n');
|
|
92
|
+
process.stdout.write(kv('files affected', String(plan.totalFiles)) + '\n');
|
|
93
|
+
for (const step of plan.plannedSteps) {
|
|
94
|
+
process.stdout.write(`\n [${step.index + 1}/${plan.plannedSteps.length}] ${step.id} (${step.step.kind})\n`);
|
|
95
|
+
if (step.description)
|
|
96
|
+
process.stdout.write(` ${step.description}\n`);
|
|
97
|
+
if (step.rewritePlan) {
|
|
98
|
+
process.stdout.write(` files=${step.rewritePlan.files.length} edits=${step.rewritePlan.totalEdits}\n`);
|
|
99
|
+
}
|
|
100
|
+
else if (step.step.kind === 'shell' || step.step.kind === 'check') {
|
|
101
|
+
process.stdout.write(` $ ${step.step.command}\n`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
// apply / resume
|
|
107
|
+
const dryRun = flagBool(args, 'dry-run');
|
|
108
|
+
const noStop = flagBool(args, 'no-stop-on-failure');
|
|
109
|
+
let report;
|
|
110
|
+
let resumedFromIndex = 0;
|
|
111
|
+
const resumeDiagnostics = [];
|
|
112
|
+
if (sub === 'resume') {
|
|
113
|
+
const result = resumeMigration(migration, {
|
|
114
|
+
projectRoot: cwd,
|
|
115
|
+
dryRun,
|
|
116
|
+
stopOnFailure: !noStop,
|
|
117
|
+
});
|
|
118
|
+
report = result.report;
|
|
119
|
+
resumedFromIndex = result.resumedFromIndex;
|
|
120
|
+
for (const d of result.diagnostics)
|
|
121
|
+
resumeDiagnostics.push(d);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
report = applyMigration(migration, {
|
|
125
|
+
projectRoot: cwd,
|
|
126
|
+
dryRun,
|
|
127
|
+
stopOnFailure: !noStop,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (wantJson) {
|
|
131
|
+
process.stdout.write(asJson({ ...report, resumedFromIndex, resumeDiagnostics }) + '\n');
|
|
132
|
+
return report.overall === 'fail' ? 1 : 0;
|
|
133
|
+
}
|
|
134
|
+
if (sub === 'resume') {
|
|
135
|
+
for (const d of resumeDiagnostics)
|
|
136
|
+
process.stdout.write(`! ${d}\n`);
|
|
137
|
+
}
|
|
138
|
+
process.stdout.write(header(`Migration ${dryRun ? '(dry-run)' : '(applied)'}: ${report.overall.toUpperCase()}`));
|
|
139
|
+
process.stdout.write(kv('id', report.migration.id) + '\n');
|
|
140
|
+
process.stdout.write(kv('total duration', `${report.totalDurationMs}ms`) + '\n');
|
|
141
|
+
for (const s of report.steps) {
|
|
142
|
+
process.stdout.write(` [${s.status.padEnd(8)}] ${s.id} (${s.kind}) (${s.durationMs}ms)\n`);
|
|
143
|
+
process.stdout.write(` ${s.message}\n`);
|
|
144
|
+
if (s.rewriteStats && s.rewriteStats.conflicts.length > 0) {
|
|
145
|
+
for (const c of s.rewriteStats.conflicts.slice(0, 5)) {
|
|
146
|
+
process.stdout.write(` conflict: ${c}\n`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return report.overall === 'fail' ? 1 : 0;
|
|
151
|
+
},
|
|
152
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onboard.command.d.ts","sourceRoot":"","sources":["../../src/commands/onboard.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"onboard.command.d.ts","sourceRoot":"","sources":["../../src/commands/onboard.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC,eAAO,MAAM,cAAc,EAAE,eA4N5B,CAAC"}
|
|
@@ -5,8 +5,8 @@ import { flagBool, flagNumber, flagString, flagList, resolveCwd, } from "../comm
|
|
|
5
5
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
6
6
|
export const onboardCommand = {
|
|
7
7
|
name: 'onboard',
|
|
8
|
-
description: 'Analyze an existing repository and produce a SharkCraft onboarding plan (rules / paths / templates / boundaries / pipelines + readiness estimate). Default is dry-run; `--write-drafts` writes advisory drafts under sharkcraft/onboarding/ (never overwrites rules.ts / paths.ts / templates.ts).
|
|
9
|
-
usage: 'shrk [--cwd <dir>] onboard [--dry-run] [--write-drafts] [--
|
|
8
|
+
description: 'Analyze an existing repository and produce a SharkCraft onboarding plan (rules / paths / templates / boundaries / pipelines + readiness estimate). Default is dry-run; `--write-drafts` writes advisory drafts under sharkcraft/onboarding/ (never overwrites rules.ts / paths.ts / templates.ts). `--scaffold-templates` drafts runnable template bodies. `--import-agents` parses AGENTS.md / CLAUDE.md / .cursor/rules into a draft. `--diff` compares the plan against the live config.',
|
|
9
|
+
usage: 'shrk [--cwd <dir>] onboard [--dry-run] [--write-drafts] [--scaffold-templates] [--import-agents] [--diff] [--preset <id>] [--json]',
|
|
10
10
|
async run(args) {
|
|
11
11
|
// Dispatch sub-verb: `shrk onboard adopt [...]`.
|
|
12
12
|
if (args.positional[0] === 'adopt') {
|
|
@@ -15,7 +15,6 @@ export const onboardCommand = {
|
|
|
15
15
|
}
|
|
16
16
|
const cwd = resolveCwd(args);
|
|
17
17
|
const writeDrafts = flagBool(args, 'write-drafts');
|
|
18
|
-
const abortOnConflict = flagBool(args, 'abort-on-conflict');
|
|
19
18
|
const scaffoldTemplates = flagBool(args, 'scaffold-templates');
|
|
20
19
|
const importAgents = flagBool(args, 'import-agents');
|
|
21
20
|
const diffMode = flagBool(args, 'diff');
|
|
@@ -36,7 +35,6 @@ export const onboardCommand = {
|
|
|
36
35
|
written = writeOnboardingDrafts(plan, {
|
|
37
36
|
projectRoot: cwd,
|
|
38
37
|
...(importedAgentRules ? { importedAgentRules } : {}),
|
|
39
|
-
abortOnConflict,
|
|
40
38
|
});
|
|
41
39
|
}
|
|
42
40
|
const diff = diffMode ? buildOnboardingDiff(inspection, plan) : undefined;
|
|
@@ -168,18 +166,8 @@ export const onboardCommand = {
|
|
|
168
166
|
if (writeDrafts && written) {
|
|
169
167
|
process.stdout.write(`Wrote ${written.files.length} draft file(s) to:\n ${written.outDir}\n`);
|
|
170
168
|
for (const f of written.files) {
|
|
171
|
-
process.stdout.write(` + ${f.path} (${f.bytes} bytes)
|
|
169
|
+
process.stdout.write(` + ${f.path} (${f.bytes} bytes)\n`);
|
|
172
170
|
}
|
|
173
|
-
if (written.conflicts > 0) {
|
|
174
|
-
process.stderr.write(`\nConflict regions emitted in ${written.conflicts} draft file(s). ` +
|
|
175
|
-
'Resolve <<<<<<< / ======= / >>>>>>> markers before adopting.\n');
|
|
176
|
-
}
|
|
177
|
-
if (written.aborted > 0) {
|
|
178
|
-
process.stderr.write(`\n--abort-on-conflict: ${written.aborted} draft file(s) left unchanged due to conflicts.\n`);
|
|
179
|
-
return 1;
|
|
180
|
-
}
|
|
181
|
-
if (written.conflicts > 0)
|
|
182
|
-
return 2;
|
|
183
171
|
}
|
|
184
172
|
else if (dryRun) {
|
|
185
173
|
process.stdout.write('Dry-run only. Re-run with `--write-drafts` to write advisory drafts.\n');
|
|
@@ -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"}
|