@shrkcrft/cli 0.1.0-alpha.2 → 0.1.0-alpha.20
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/audit/knowledge-audit-llm.d.ts +19 -0
- package/dist/audit/knowledge-audit-llm.d.ts.map +1 -0
- package/dist/audit/knowledge-audit-llm.js +164 -0
- package/dist/audit/knowledge-audit.d.ts +61 -0
- package/dist/audit/knowledge-audit.d.ts.map +1 -0
- package/dist/audit/knowledge-audit.js +203 -0
- package/dist/audit/knowledge-fix-plan-llm.d.ts +11 -0
- package/dist/audit/knowledge-fix-plan-llm.d.ts.map +1 -0
- package/dist/audit/knowledge-fix-plan-llm.js +141 -0
- package/dist/audit/knowledge-fix-plan.d.ts +41 -0
- package/dist/audit/knowledge-fix-plan.d.ts.map +1 -0
- package/dist/audit/knowledge-fix-plan.js +125 -0
- package/dist/audit/pipeline-audit-llm.d.ts +11 -0
- package/dist/audit/pipeline-audit-llm.d.ts.map +1 -0
- package/dist/audit/pipeline-audit-llm.js +134 -0
- package/dist/audit/pipeline-audit.d.ts +69 -0
- package/dist/audit/pipeline-audit.d.ts.map +1 -0
- package/dist/audit/pipeline-audit.js +166 -0
- package/dist/audit/templates-audit-llm.d.ts +19 -0
- package/dist/audit/templates-audit-llm.d.ts.map +1 -0
- package/dist/audit/templates-audit-llm.js +207 -0
- package/dist/audit/templates-audit.d.ts +63 -0
- package/dist/audit/templates-audit.d.ts.map +1 -0
- package/dist/audit/templates-audit.js +171 -0
- package/dist/audit/templates-fix-plan-llm.d.ts +19 -0
- package/dist/audit/templates-fix-plan-llm.d.ts.map +1 -0
- package/dist/audit/templates-fix-plan-llm.js +162 -0
- package/dist/audit/templates-fix-plan.d.ts +37 -0
- package/dist/audit/templates-fix-plan.d.ts.map +1 -0
- package/dist/audit/templates-fix-plan.js +174 -0
- package/dist/command-registry.d.ts +28 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +91 -1
- package/dist/commands/ai-status.command.d.ts +19 -0
- package/dist/commands/ai-status.command.d.ts.map +1 -0
- package/dist/commands/ai-status.command.js +94 -0
- 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 +144 -0
- package/dist/commands/apply.command.d.ts.map +1 -1
- package/dist/commands/apply.command.js +10 -2
- 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/ask.command.d.ts.map +1 -1
- package/dist/commands/ask.command.js +10 -9
- package/dist/commands/cache-align.command.d.ts +12 -0
- package/dist/commands/cache-align.command.d.ts.map +1 -0
- package/dist/commands/cache-align.command.js +78 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +19 -2
- 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/codemod.command.d.ts.map +1 -1
- package/dist/commands/codemod.command.js +27 -6
- package/dist/commands/command-catalog.d.ts +15 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +387 -34
- 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/compress.command.d.ts +8 -0
- package/dist/commands/compress.command.d.ts.map +1 -0
- package/dist/commands/compress.command.js +147 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +89 -23
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +121 -1
- package/dist/commands/contract-gate.command.d.ts.map +1 -1
- package/dist/commands/contract-gate.command.js +5 -1
- package/dist/commands/delegate.command.d.ts +65 -0
- package/dist/commands/delegate.command.d.ts.map +1 -0
- package/dist/commands/delegate.command.js +657 -0
- package/dist/commands/deps-audit.command.d.ts +23 -0
- package/dist/commands/deps-audit.command.d.ts.map +1 -0
- package/dist/commands/deps-audit.command.js +270 -0
- package/dist/commands/dev.command.d.ts.map +1 -1
- package/dist/commands/dev.command.js +5 -1
- 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 +162 -10
- 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 +300 -0
- package/dist/commands/gen.command.d.ts.map +1 -1
- package/dist/commands/gen.command.js +13 -1
- package/dist/commands/graph-code-subverbs.d.ts +33 -0
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
- package/dist/commands/graph-code-subverbs.js +1366 -0
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +31 -2
- 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 +86 -18
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +171 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/ingest.command.d.ts.map +1 -1
- package/dist/commands/ingest.command.js +5 -1
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +174 -7
- package/dist/commands/knowledge-author.command.d.ts.map +1 -1
- package/dist/commands/knowledge-author.command.js +9 -0
- package/dist/commands/knowledge-propose.command.d.ts.map +1 -1
- package/dist/commands/knowledge-propose.command.js +4 -2
- package/dist/commands/knowledge.command.d.ts.map +1 -1
- package/dist/commands/knowledge.command.js +26 -3
- 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/move-plan.command.d.ts +23 -0
- package/dist/commands/move-plan.command.d.ts.map +1 -0
- package/dist/commands/move-plan.command.js +360 -0
- 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/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 +85 -0
- package/dist/commands/preflight.command.d.ts.map +1 -1
- package/dist/commands/preflight.command.js +15 -0
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/recommend.command.d.ts +6 -0
- package/dist/commands/recommend.command.d.ts.map +1 -1
- package/dist/commands/recommend.command.js +119 -5
- package/dist/commands/release.command.js +13 -13
- 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/rules.command.d.ts.map +1 -1
- package/dist/commands/rules.command.js +20 -3
- package/dist/commands/scaffold-validate.command.d.ts +22 -0
- package/dist/commands/scaffold-validate.command.d.ts.map +1 -0
- package/dist/commands/scaffold-validate.command.js +215 -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/smart-context.command.d.ts +67 -0
- package/dist/commands/smart-context.command.d.ts.map +1 -0
- package/dist/commands/smart-context.command.js +4728 -0
- package/dist/commands/spike.command.d.ts +22 -0
- package/dist/commands/spike.command.d.ts.map +1 -0
- package/dist/commands/spike.command.js +235 -0
- package/dist/commands/surface.command.d.ts +1 -0
- package/dist/commands/surface.command.d.ts.map +1 -1
- package/dist/commands/surface.command.js +10 -3
- package/dist/commands/task-context.command.d.ts.map +1 -1
- package/dist/commands/task-context.command.js +5 -17
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +8 -2
- package/dist/commands/template-quality.command.d.ts.map +1 -1
- package/dist/commands/template-quality.command.js +39 -3
- package/dist/commands/templates.command.d.ts.map +1 -1
- package/dist/commands/templates.command.js +37 -2
- package/dist/commands/tests.command.d.ts.map +1 -1
- package/dist/commands/tests.command.js +13 -2
- package/dist/commands/watch.command.d.ts +26 -0
- package/dist/commands/watch.command.d.ts.map +1 -0
- package/dist/commands/watch.command.js +456 -0
- 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 +329 -0
- package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
- package/dist/dashboard/dashboard-api-server.js +256 -2
- package/dist/dashboard/knowledge-ask.d.ts +4 -0
- package/dist/dashboard/knowledge-ask.d.ts.map +1 -0
- package/dist/dashboard/knowledge-ask.js +112 -0
- package/dist/env/load-dotenv.d.ts +15 -0
- package/dist/env/load-dotenv.d.ts.map +1 -0
- package/dist/env/load-dotenv.js +70 -0
- 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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- 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.map +1 -1
- package/dist/main.js +331 -17
- package/dist/output/ccr-store-config.d.ts +18 -0
- package/dist/output/ccr-store-config.d.ts.map +1 -0
- package/dist/output/ccr-store-config.js +41 -0
- package/dist/output/format-output.d.ts.map +1 -1
- package/dist/output/format-output.js +6 -1
- package/dist/output/output-compression.d.ts +15 -0
- package/dist/output/output-compression.d.ts.map +1 -0
- package/dist/output/output-compression.js +60 -0
- package/dist/output/resolve-compress-type.d.ts +22 -0
- package/dist/output/resolve-compress-type.d.ts.map +1 -0
- package/dist/output/resolve-compress-type.js +21 -0
- 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 +384 -36
- package/dist/schemas/json-schemas.d.ts.map +1 -1
- package/dist/schemas/json-schemas.js +247 -36
- package/dist/surface/profiles.d.ts.map +1 -1
- package/dist/surface/profiles.js +54 -9
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +23 -11
- package/dist/validation/run-validation-loop.d.ts.map +1 -1
- package/dist/validation/run-validation-loop.js +5 -1
- package/package.json +35 -21
- 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";
|
|
@@ -133,6 +134,11 @@ async function applyPresetInit(cwd, mode) {
|
|
|
133
134
|
source: 'override',
|
|
134
135
|
});
|
|
135
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);
|
|
136
142
|
process.stdout.write(header('SharkCraft initialized'));
|
|
137
143
|
process.stdout.write(`Preset: ${preset.id} — ${preset.title}\n`);
|
|
138
144
|
process.stdout.write(`Folder: ${plan.sharkcraftDir}\n`);
|
|
@@ -169,16 +175,29 @@ async function applyPresetInit(cwd, mode) {
|
|
|
169
175
|
process.stdout.write('\n' + renderGitignorePatch(patch, false));
|
|
170
176
|
}
|
|
171
177
|
}
|
|
178
|
+
if (pathsAdvisory.annotated) {
|
|
179
|
+
renderPathsAdvisory(pathsAdvisory);
|
|
180
|
+
}
|
|
172
181
|
process.stdout.write('\nNext:\n');
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
]) {
|
|
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 ?? []) {
|
|
177
186
|
process.stdout.write(bullet(`$ ${cmd}`) + '\n');
|
|
178
187
|
}
|
|
179
188
|
process.stdout.write(bullet('Start the MCP server: `shrk mcp serve` (or run it via Claude Code)') + '\n');
|
|
180
189
|
return 0;
|
|
181
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
|
+
}
|
|
182
201
|
function applyLegacyInit(cwd, force) {
|
|
183
202
|
const { root } = detectProjectRoot(cwd);
|
|
184
203
|
const sharkcraftDir = nodePath.join(root, 'sharkcraft');
|
|
@@ -212,6 +231,10 @@ function applyLegacyInit(cwd, force) {
|
|
|
212
231
|
for (const s of skipped)
|
|
213
232
|
process.stdout.write(bullet(s) + '\n');
|
|
214
233
|
}
|
|
234
|
+
const legacyAdvisory = annotatePathsAgainstDisk(cwd, sharkcraftDir);
|
|
235
|
+
if (legacyAdvisory.annotated) {
|
|
236
|
+
renderPathsAdvisory(legacyAdvisory);
|
|
237
|
+
}
|
|
215
238
|
process.stdout.write('\nNext:\n');
|
|
216
239
|
process.stdout.write(bullet('Run `shrk inspect` to see your project summary.') + '\n');
|
|
217
240
|
process.stdout.write(bullet('Run `shrk knowledge list` to see what was seeded.') + '\n');
|
|
@@ -220,13 +243,23 @@ function applyLegacyInit(cwd, force) {
|
|
|
220
243
|
}
|
|
221
244
|
export const initCommand = {
|
|
222
245
|
name: 'init',
|
|
223
|
-
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.',
|
|
224
|
-
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>]',
|
|
225
248
|
async run(args) {
|
|
226
249
|
const force = flagBool(args, 'force');
|
|
227
250
|
const merge = flagBool(args, 'merge');
|
|
228
251
|
const cwd = resolveCwd(args);
|
|
252
|
+
const wantInfer = flagBool(args, 'infer');
|
|
229
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
|
+
}
|
|
230
263
|
if (flagBool(args, 'legacy')) {
|
|
231
264
|
const code = applyLegacyInit(cwd, force);
|
|
232
265
|
if (code === 0 && !skipGitignore) {
|
|
@@ -287,7 +320,7 @@ export const initCommand = {
|
|
|
287
320
|
if (dryRun) {
|
|
288
321
|
process.stdout.write(`Surface profile: ${surfaceDecision.profile} (${surfaceDecision.source}) — ${surfaceDecision.reason}\n`);
|
|
289
322
|
}
|
|
290
|
-
|
|
323
|
+
const presetCode = await applyPresetInit(cwd, {
|
|
291
324
|
presetId,
|
|
292
325
|
dryRun,
|
|
293
326
|
force,
|
|
@@ -297,5 +330,139 @@ export const initCommand = {
|
|
|
297
330
|
surfaceProfile: surfaceDecision.profile,
|
|
298
331
|
surfaceProfileReason: surfaceDecision.reason,
|
|
299
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;
|
|
300
349
|
},
|
|
301
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":"knowledge-author.command.d.ts","sourceRoot":"","sources":["../../src/commands/knowledge-author.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoBH,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAwChC,eAAO,MAAM,mBAAmB,EAAE,eAgEjC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0GpC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAoEpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"knowledge-author.command.d.ts","sourceRoot":"","sources":["../../src/commands/knowledge-author.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoBH,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAwChC,eAAO,MAAM,mBAAmB,EAAE,eAgEjC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0GpC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAoEpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAsElC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAmB3C,CAAC"}
|
|
@@ -300,6 +300,15 @@ export const knowledgeLintCommand = {
|
|
|
300
300
|
async run(args) {
|
|
301
301
|
const cwd = resolveCwd(args);
|
|
302
302
|
const inspection = await inspectSharkcraft({ cwd });
|
|
303
|
+
// Loud guard: a 0-entry scan is NOT a clean pass — it almost always means
|
|
304
|
+
// the loader found nothing (wrong cwd / no `sharkcraft/` folder / no
|
|
305
|
+
// entries), which otherwise reads as "lint passed". Surface it on stderr so
|
|
306
|
+
// it can't be mistaken for success, while keeping stdout/JSON clean.
|
|
307
|
+
if (inspection.knowledgeEntries.length === 0) {
|
|
308
|
+
process.stderr.write('WARN knowledge lint scanned 0 entries — there is nothing to lint (this is NOT a clean pass).\n' +
|
|
309
|
+
' Likely causes: no `sharkcraft/` folder here, not at the workspace root, or no\n' +
|
|
310
|
+
' knowledge entries are defined. Run `shrk doctor` to confirm how many entries load.\n');
|
|
311
|
+
}
|
|
303
312
|
const entryIds = flagList(args, 'id');
|
|
304
313
|
const includeAdvisory = !flagBool(args, 'no-advisory');
|
|
305
314
|
const stale = buildKnowledgeStaleReport(inspection);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge-propose.command.d.ts","sourceRoot":"","sources":["../../src/commands/knowledge-propose.command.ts"],"names":[],"mappings":"AAqBA,OAAO,
|
|
1
|
+
{"version":3,"file":"knowledge-propose.command.d.ts","sourceRoot":"","sources":["../../src/commands/knowledge-propose.command.ts"],"names":[],"mappings":"AAqBA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAkDhC,eAAO,MAAM,uBAAuB,EAAE,eA4ErC,CAAC"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import * as nodePath from 'node:path';
|
|
12
12
|
import { AssetKind, AssetProvenanceOperation, KNOWLEDGE_PROPOSE_SCHEMA, proposeKnowledge, recordProvenance, renderKnowledgeProposeMarkdown, } from '@shrkcrft/inspector';
|
|
13
|
-
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
13
|
+
import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-registry.js";
|
|
14
14
|
import { asJson } from "../output/format-output.js";
|
|
15
15
|
import { detectAuthoringSource } from "../authoring/authoring-kit.js";
|
|
16
16
|
function renderProposalAsTs(p) {
|
|
@@ -54,13 +54,14 @@ function writeDraftFiles(cwd, report) {
|
|
|
54
54
|
export const knowledgeProposeCommand = {
|
|
55
55
|
name: 'propose',
|
|
56
56
|
description: 'Propose stub knowledge entries for exported top-level constructs that lack coverage. Preview-first; --write materialises drafts under .sharkcraft/authoring/proposed/.',
|
|
57
|
-
usage: 'shrk knowledge propose [--path <file>] [--symbol <name>] [--since <ref>|--all] [--json] [--write]',
|
|
57
|
+
usage: 'shrk knowledge propose [--path <file>] [--symbol <name>] [--since <ref>|--all] [--max <n>] [--json] [--write]',
|
|
58
58
|
async run(args) {
|
|
59
59
|
const cwd = resolveCwd(args);
|
|
60
60
|
const path = flagString(args, 'path');
|
|
61
61
|
const symbol = flagString(args, 'symbol');
|
|
62
62
|
const sinceFlag = flagString(args, 'since');
|
|
63
63
|
const all = flagBool(args, 'all');
|
|
64
|
+
const max = flagNumber(args, 'max');
|
|
64
65
|
const since = path
|
|
65
66
|
? undefined
|
|
66
67
|
: symbol
|
|
@@ -73,6 +74,7 @@ export const knowledgeProposeCommand = {
|
|
|
73
74
|
...(path ? { path } : {}),
|
|
74
75
|
...(symbol ? { symbol } : {}),
|
|
75
76
|
...(since !== undefined ? { since } : {}),
|
|
77
|
+
...(max !== undefined && max >= 0 ? { max } : {}),
|
|
76
78
|
});
|
|
77
79
|
if (flagBool(args, 'json')) {
|
|
78
80
|
const payload = flagBool(args, 'write')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge.command.d.ts","sourceRoot":"","sources":["../../src/commands/knowledge.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"knowledge.command.d.ts","sourceRoot":"","sources":["../../src/commands/knowledge.command.ts"],"names":[],"mappings":"AAkBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAoFhC,eAAO,MAAM,oBAAoB,EAAE,eA8ClC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eAuBjC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAqCpC,CAAC;AAoBF,eAAO,MAAM,0BAA0B,EAAE,eAWxC,CAAC;AA8NF,eAAO,MAAM,sBAAsB,EAAE,eAQpC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eA8CxC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAuBrC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,EAAE,eA8B1C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eA8BxC,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,eAkC1C,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join as nodePathJoin, resolve as nodePathResolve } from 'node:path';
|
|
3
3
|
import { buildAnchorUpdatePlan, buildKnowledgeStaleReport, buildRenameFilePlan, buildRenameSymbolPlan, inspectSharkcraft, ReferenceCheckOutcome, resolveChangedFiles, } from '@shrkcrft/inspector';
|
|
4
|
-
import { formatEntryCompact, formatEntryFull, searchKnowledge } from '@shrkcrft/knowledge';
|
|
4
|
+
import { formatEntryCompact, formatEntryFull, projectKnowledgeEntryForJson, searchKnowledge, } from '@shrkcrft/knowledge';
|
|
5
5
|
import { flagBool, flagNumber, flagString, flagList, resolveCwd, } from "../command-registry.js";
|
|
6
6
|
import { asJson, header } from "../output/format-output.js";
|
|
7
7
|
import { maybeRunInWatchMode } from "../output/watch-loop.js";
|
|
@@ -54,7 +54,7 @@ ${p.ci.exitNonZero ? `<p style="color:#a40000;font-weight:bold">FAIL: ${esc(p.ci
|
|
|
54
54
|
export const knowledgeListCommand = {
|
|
55
55
|
name: 'list',
|
|
56
56
|
description: 'List knowledge entries.',
|
|
57
|
-
usage: 'shrk knowledge list [--type rule] [--scope x,y] [--json]',
|
|
57
|
+
usage: 'shrk knowledge list [--type rule] [--scope x,y] [--top N] [--brief] [--json]',
|
|
58
58
|
async run(args) {
|
|
59
59
|
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
60
60
|
const types = flagList(args, 'type');
|
|
@@ -64,8 +64,31 @@ export const knowledgeListCommand = {
|
|
|
64
64
|
entries = entries.filter((e) => types.includes(String(e.type)));
|
|
65
65
|
if (scope.length)
|
|
66
66
|
entries = entries.filter((e) => scope.some((s) => e.scope.includes(s)));
|
|
67
|
+
// --top N: a deterministic, token-bounded slice. Sort by id first so the
|
|
68
|
+
// "top N" is stable across machines (entries otherwise load in fs-scan
|
|
69
|
+
// order). Reduce at the source instead of piping through `shrk compress`.
|
|
70
|
+
const top = flagNumber(args, 'top');
|
|
71
|
+
if (top !== undefined && top > 0) {
|
|
72
|
+
entries = [...entries].sort((a, b) => a.id.localeCompare(b.id)).slice(0, top);
|
|
73
|
+
}
|
|
67
74
|
if (flagBool(args, 'json')) {
|
|
68
|
-
|
|
75
|
+
// --brief: project to the high-signal fields, dropping content / examples
|
|
76
|
+
// / metadata (the bulk of the payload) so an agent pays far fewer tokens.
|
|
77
|
+
const payload = flagBool(args, 'brief')
|
|
78
|
+
? entries.map((e) => ({
|
|
79
|
+
id: e.id,
|
|
80
|
+
type: e.type,
|
|
81
|
+
priority: e.priority,
|
|
82
|
+
title: e.title,
|
|
83
|
+
scope: e.scope,
|
|
84
|
+
tags: e.tags,
|
|
85
|
+
appliesWhen: e.appliesWhen,
|
|
86
|
+
}))
|
|
87
|
+
: // Project the declared IKnowledgeEntry fields by direct access rather
|
|
88
|
+
// than spreading (`{ ...e }`), which copies only own-enumerable props
|
|
89
|
+
// and would strip pack entries whose fields are getters/non-enumerable.
|
|
90
|
+
entries.map(projectKnowledgeEntryForJson);
|
|
91
|
+
process.stdout.write(asJson(payload) + '\n');
|
|
69
92
|
return 0;
|
|
70
93
|
}
|
|
71
94
|
process.stdout.write(header(`Knowledge (${entries.length})`));
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
+
/**
|
|
3
|
+
* `shrk move-plan <source> <target>` — emit a structured plan for
|
|
4
|
+
* moving a source file to a new location. Read-only: NEVER moves
|
|
5
|
+
* anything itself, never rewrites imports. The agent (or a human)
|
|
6
|
+
* uses the plan to do the actual work.
|
|
7
|
+
*
|
|
8
|
+
* Covers:
|
|
9
|
+
* - graph-traced importer rewrites (relative + package-name imports)
|
|
10
|
+
* - exports to revisit if the source was re-exported from an index
|
|
11
|
+
* - cross-package warnings (layer-order risks)
|
|
12
|
+
* - a rollback plan that's the literal reverse of the move
|
|
13
|
+
* - validation commands to run after applying
|
|
14
|
+
*
|
|
15
|
+
* Limitations:
|
|
16
|
+
* - single-file only. Directory moves can be approximated by
|
|
17
|
+
* listing the directory and running this command per file, or
|
|
18
|
+
* wait for a `--folder` follow-up.
|
|
19
|
+
* - `from '@shrkcrft/pkg/sub'` deep-import rewrites are best-effort;
|
|
20
|
+
* ambiguous cases get reported as `review-manually`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const movePlanCommand: ICommandHandler;
|
|
23
|
+
//# sourceMappingURL=move-plan.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move-plan.command.d.ts","sourceRoot":"","sources":["../../src/commands/move-plan.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,eAAe,EAA+B,MAAM,wBAAwB,CAAC;AAqCrG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,eA4M7B,CAAC"}
|