@shrkcrft/cli 0.1.0-alpha.11 → 0.1.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/commands/ask.command.d.ts.map +1 -1
  2. package/dist/commands/ask.command.js +10 -9
  3. package/dist/commands/command-catalog.d.ts.map +1 -1
  4. package/dist/commands/command-catalog.js +100 -1
  5. package/dist/commands/deps-audit.command.d.ts +23 -0
  6. package/dist/commands/deps-audit.command.d.ts.map +1 -0
  7. package/dist/commands/deps-audit.command.js +266 -0
  8. package/dist/commands/doctor.command.d.ts.map +1 -1
  9. package/dist/commands/doctor.command.js +60 -1
  10. package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
  11. package/dist/commands/graph-code-subverbs.js +144 -26
  12. package/dist/commands/graph.command.d.ts.map +1 -1
  13. package/dist/commands/graph.command.js +3 -2
  14. package/dist/commands/help.command.d.ts.map +1 -1
  15. package/dist/commands/help.command.js +22 -1
  16. package/dist/commands/impact.command.d.ts.map +1 -1
  17. package/dist/commands/impact.command.js +3 -2
  18. package/dist/commands/move-plan.command.d.ts +23 -0
  19. package/dist/commands/move-plan.command.d.ts.map +1 -0
  20. package/dist/commands/move-plan.command.js +360 -0
  21. package/dist/commands/scaffold-validate.command.d.ts +22 -0
  22. package/dist/commands/scaffold-validate.command.d.ts.map +1 -0
  23. package/dist/commands/scaffold-validate.command.js +215 -0
  24. package/dist/commands/smart-context.command.d.ts +30 -0
  25. package/dist/commands/smart-context.command.d.ts.map +1 -0
  26. package/dist/commands/smart-context.command.js +3763 -0
  27. package/dist/commands/spike.command.d.ts +22 -0
  28. package/dist/commands/spike.command.d.ts.map +1 -0
  29. package/dist/commands/spike.command.js +235 -0
  30. package/dist/commands/watch.command.d.ts +26 -0
  31. package/dist/commands/watch.command.d.ts.map +1 -0
  32. package/dist/commands/watch.command.js +456 -0
  33. package/dist/env/load-dotenv.d.ts +15 -0
  34. package/dist/env/load-dotenv.d.ts.map +1 -0
  35. package/dist/env/load-dotenv.js +70 -0
  36. package/dist/main.d.ts.map +1 -1
  37. package/dist/main.js +83 -2
  38. package/dist/schemas/json-schemas.d.ts +384 -36
  39. package/dist/schemas/json-schemas.d.ts.map +1 -1
  40. package/dist/schemas/json-schemas.js +247 -36
  41. package/package.json +33 -31
@@ -350,13 +350,15 @@ export async function runGraphStatus(args) {
350
350
  }
351
351
  const verify = store.verifyDigest();
352
352
  const snap = store.loadSnapshot();
353
+ const manifestNodeCount = sumValues(snap.manifest.nodesByKind);
354
+ const manifestEdgeCount = sumValues(snap.manifest.edgesByKind);
353
355
  const payload = {
354
356
  ok: verify.ok,
355
357
  state: verify.ok ? 'fresh' : 'corrupt',
356
358
  schema: snap.manifest.schema,
357
359
  fileCount: snap.manifest.filesIndexed,
358
- nodeCount: snap.nodes.size,
359
- edgeCount: snap.edges.size,
360
+ nodeCount: manifestNodeCount,
361
+ edgeCount: manifestEdgeCount,
360
362
  lastIndexedAt: snap.manifest.lastIndexedAt,
361
363
  lastIndexDurationMs: snap.manifest.lastIndexDurationMs,
362
364
  workspacePackages: snap.manifest.workspacePackages,
@@ -394,8 +396,10 @@ export async function runGraphSearch(args) {
394
396
  const cwd = resolveCwd(args);
395
397
  const wantJson = flagBool(args, 'json');
396
398
  const query = args.positional[1];
397
- if (!query) {
398
- process.stderr.write('Usage: shrk graph search <query> [--kind file|symbol|package] [--limit N]\n');
399
+ const hasUnresolved = flagBool(args, 'has-unresolved-imports');
400
+ if (!query && !hasUnresolved) {
401
+ process.stderr.write('Usage: shrk graph search <query> [--kind file|symbol|package] [--limit N]\n' +
402
+ ' shrk graph search --kind file --has-unresolved-imports [--limit N]\n');
399
403
  return 2;
400
404
  }
401
405
  const kindFlag = flagString(args, 'kind');
@@ -403,7 +407,16 @@ export async function runGraphSearch(args) {
403
407
  const api = loadOrFail(cwd, wantJson);
404
408
  if (!api)
405
409
  return 1;
406
- const matches = collectSearchMatches(api, query, kindFlag, limit);
410
+ let matches;
411
+ if (hasUnresolved) {
412
+ const all = api.filesWithUnresolvedImports();
413
+ matches = (query
414
+ ? all.filter((n) => (n.path ?? '').toLowerCase().includes(query.toLowerCase()))
415
+ : [...all]).slice(0, limit);
416
+ }
417
+ else {
418
+ matches = collectSearchMatches(api, query, kindFlag, limit);
419
+ }
407
420
  if (wantJson) {
408
421
  process.stdout.write(asJson({
409
422
  schema: 'sharkcraft.graph-search/v1',
@@ -414,11 +427,12 @@ export async function runGraphSearch(args) {
414
427
  }) + '\n');
415
428
  return 0;
416
429
  }
430
+ const headerLabel = query ?? (hasUnresolved ? 'files with unresolved imports' : '');
417
431
  if (matches.length === 0) {
418
- process.stdout.write(`No matches for "${query}".\n`);
432
+ process.stdout.write(`No matches for "${headerLabel}".\n`);
419
433
  return 0;
420
434
  }
421
- process.stdout.write(header(`Graph search: ${query}`));
435
+ process.stdout.write(header(`Graph search: ${headerLabel}`));
422
436
  for (const m of matches) {
423
437
  process.stdout.write(` ${m.kind.padEnd(8)} ${m.label}${m.path ? ' ' + m.path : ''}${m.line ? ':' + m.line : ''}\n`);
424
438
  }
@@ -449,22 +463,29 @@ export async function runGraphContext(args) {
449
463
  process.stderr.write(`No graph node matched "${target}".\n`);
450
464
  return 1;
451
465
  }
452
- const neighbours = api.neighbours(anchor.id);
466
+ const anchorFile = anchor.kind === NodeKind.File
467
+ ? anchor
468
+ : declaringFileOf(api, anchor.id) ?? (anchor.path ? api.findFile(anchor.path) : undefined);
469
+ const subjectNodeId = anchorFile?.id ?? anchor.id;
470
+ const neighbours = api.neighbours(subjectNodeId);
453
471
  const symbols = anchor.kind === NodeKind.File ? api.symbolsIn(anchor.id) : [];
472
+ const references = anchor.kind === NodeKind.Symbol ? dedupeNodes(api.referencesOf(anchor.id)) : [];
473
+ const callers = anchor.kind === NodeKind.Symbol ? dedupeNodes(api.callersOf(anchor.id)) : [];
454
474
  // Optional bridge enrichment: rules / paths / templates applying to
455
- // the anchor file (only meaningful when anchor.kind === File).
475
+ // the anchor file (or a symbol's containing file).
456
476
  const bridgeStore = new BridgeStore(cwd);
457
- const bridgeFor = (includeBridge && bridgeStore.exists() && anchor.kind === NodeKind.File && anchor.path)
458
- ? RuleGraphQueryApi.fromStores(cwd).forFile(anchor.path)
477
+ const bridgeFor = (includeBridge && bridgeStore.exists() && anchorFile?.path)
478
+ ? RuleGraphQueryApi.fromStores(cwd).forFile(anchorFile.path)
459
479
  : undefined;
460
480
  // Optional framework enrichment.
461
481
  const frameworkStore = new FrameworkStore(cwd);
462
- const frameworkEntities = (includeFramework && frameworkStore.exists() && anchor.kind === NodeKind.File && anchor.path)
463
- ? FrameworkQueryApi.fromStore(cwd).forFile(anchor.path)
482
+ const frameworkEntities = (includeFramework && frameworkStore.exists() && anchorFile?.path)
483
+ ? FrameworkQueryApi.fromStore(cwd).forFile(anchorFile.path)
464
484
  : [];
465
485
  const payload = {
466
486
  schema: 'sharkcraft.graph-context/v1',
467
487
  anchor: nodeSummary(anchor),
488
+ declaredIn: anchor.kind === NodeKind.Symbol && anchorFile ? nodeSummary(anchorFile) : null,
468
489
  depth,
469
490
  importsFrom: neighbours.out
470
491
  .filter((o) => o.edge.kind === 'imports-file')
@@ -475,6 +496,8 @@ export async function runGraphContext(args) {
475
496
  .slice(0, 50)
476
497
  .map((i) => 'source' in i ? sourceSummary(i.source) : { id: 'unknown', resolved: false }),
477
498
  symbols: symbols.slice(0, 50).map(nodeSummary),
499
+ referencedBy: references.slice(0, 50).map(nodeSummary),
500
+ calledBy: callers.slice(0, 50).map(nodeSummary),
478
501
  bridge: bridgeFor
479
502
  ? {
480
503
  rules: bridgeFor.rules.map((h) => ({
@@ -503,12 +526,29 @@ export async function runGraphContext(args) {
503
526
  }
504
527
  process.stdout.write(header(`Graph context: ${anchor.kind}:${anchor.label}`));
505
528
  process.stdout.write(kv('path', anchor.path ?? '(none)') + '\n');
529
+ if (anchor.line)
530
+ process.stdout.write(kv('line', String(anchor.line)) + '\n');
531
+ if (payload.declaredIn) {
532
+ process.stdout.write(kv('declared in', payload.declaredIn.path ?? payload.declaredIn.id) + '\n');
533
+ }
506
534
  if (payload.symbols.length > 0) {
507
535
  process.stdout.write(`\nDeclares ${payload.symbols.length} symbols:\n`);
508
536
  for (const s of payload.symbols.slice(0, 20)) {
509
537
  process.stdout.write(` ${s.label}${s.line ? ':' + s.line : ''}\n`);
510
538
  }
511
539
  }
540
+ if (payload.referencedBy.length > 0) {
541
+ process.stdout.write(`\nReferenced by (${payload.referencedBy.length}):\n`);
542
+ for (const r of payload.referencedBy.slice(0, 20)) {
543
+ process.stdout.write(` ← ${r.path ?? r.id}\n`);
544
+ }
545
+ }
546
+ if (payload.calledBy.length > 0) {
547
+ process.stdout.write(`\nCalled by (${payload.calledBy.length}):\n`);
548
+ for (const c of payload.calledBy.slice(0, 20)) {
549
+ process.stdout.write(` ← ${c.path ?? c.id}\n`);
550
+ }
551
+ }
512
552
  if (payload.importsFrom.length > 0) {
513
553
  process.stdout.write(`\nImports from (${payload.importsFrom.length}):\n`);
514
554
  for (const o of payload.importsFrom.slice(0, 20)) {
@@ -610,7 +650,7 @@ export async function runGraphImpact(args) {
610
650
  process.stderr.write(`No graph node matched "${target}".\n`);
611
651
  return 1;
612
652
  }
613
- const closure = reverseClosure(api, anchor.id, maxDepth, limit);
653
+ const closure = reverseClosure(api, anchor, maxDepth, limit);
614
654
  const direct = closure.layer[1] ?? [];
615
655
  const transitive = closure.all.filter((id) => id !== anchor.id && !direct.includes(id));
616
656
  const payload = {
@@ -740,6 +780,26 @@ function collectSearchMatches(api, query, kind, limit) {
740
780
  const f = api.findFile(query);
741
781
  if (f)
742
782
  out.push(f);
783
+ // Fuzzy fallback: substring match on path/basename so `shrk graph
784
+ // search Foo --kind file` finds `libs/x/y/Foo.ts` without forcing the
785
+ // caller to type the full path. Skips the node if exact match already
786
+ // included it.
787
+ if (out.length < limit) {
788
+ const q = query.toLowerCase();
789
+ const seen = new Set(out.map((n) => n.id));
790
+ for (const node of api.allFiles()) {
791
+ if (seen.has(node.id))
792
+ continue;
793
+ const p = node.path?.toLowerCase() ?? '';
794
+ const base = p.includes('/') ? p.slice(p.lastIndexOf('/') + 1) : p;
795
+ if (base.includes(q) || p.includes(q)) {
796
+ out.push(node);
797
+ seen.add(node.id);
798
+ if (out.length >= limit)
799
+ break;
800
+ }
801
+ }
802
+ }
743
803
  }
744
804
  if (!kind || kind === 'symbol') {
745
805
  for (const s of api.findSymbol(query, { exact: false, limit }))
@@ -752,21 +812,29 @@ function collectSearchMatches(api, query, kind, limit) {
752
812
  }
753
813
  return out.slice(0, limit);
754
814
  }
755
- function reverseClosure(api, startId, maxDepth, limit) {
756
- const seen = new Set([startId]);
815
+ function reverseClosure(api, anchor, maxDepth, limit) {
816
+ const seen = new Set([anchor.id]);
757
817
  const layer = {};
758
- let frontier = [startId];
759
- let depth = 1;
818
+ let frontier = directDependentsForAnchor(api, anchor);
760
819
  let truncated = false;
761
- while (depth <= maxDepth && frontier.length > 0) {
820
+ frontier = frontier.filter((id) => !seen.has(id));
821
+ if (frontier.length > limit) {
822
+ frontier = frontier.slice(0, limit);
823
+ truncated = true;
824
+ }
825
+ for (const id of frontier)
826
+ seen.add(id);
827
+ if (frontier.length > 0)
828
+ layer[1] = frontier;
829
+ let depth = 2;
830
+ while (depth <= maxDepth && frontier.length > 0 && !truncated) {
762
831
  const next = [];
763
832
  for (const id of frontier) {
764
- const importers = api.importersOf(id);
765
- for (const imp of importers) {
766
- if (seen.has(imp.id))
833
+ for (const dep of nextDependents(api, anchor.kind, id)) {
834
+ if (seen.has(dep.id))
767
835
  continue;
768
- seen.add(imp.id);
769
- next.push(imp.id);
836
+ seen.add(dep.id);
837
+ next.push(dep.id);
770
838
  if (seen.size - 1 >= limit) {
771
839
  truncated = true;
772
840
  break;
@@ -779,11 +847,50 @@ function reverseClosure(api, startId, maxDepth, limit) {
779
847
  layer[depth] = next;
780
848
  frontier = next;
781
849
  depth += 1;
782
- if (truncated)
783
- break;
784
850
  }
785
851
  return { all: [...seen], layer, truncated };
786
852
  }
853
+ function directDependentsForAnchor(api, anchor) {
854
+ if (anchor.kind === NodeKind.Symbol) {
855
+ const owner = declaringFileOf(api, anchor.id);
856
+ const refs = dedupeNodes([...api.referencesOf(anchor.id), ...api.callersOf(anchor.id)])
857
+ .filter((n) => n.kind === NodeKind.File && n.id !== owner?.id)
858
+ .map((n) => n.id);
859
+ if (refs.length > 0)
860
+ return refs;
861
+ return owner ? api.importersOf(owner.id).map((n) => n.id) : [];
862
+ }
863
+ if (anchor.kind === NodeKind.Package) {
864
+ return api.packageDependents(packageNameFor(anchor)).map((n) => n.id);
865
+ }
866
+ return api.importersOf(anchor.id).map((n) => n.id);
867
+ }
868
+ function nextDependents(api, anchorKind, nodeId) {
869
+ if (anchorKind === NodeKind.Package) {
870
+ const node = api.neighbours(nodeId)?.node;
871
+ if (!node)
872
+ return [];
873
+ return api.packageDependents(packageNameFor(node));
874
+ }
875
+ return api.importersOf(nodeId);
876
+ }
877
+ function declaringFileOf(api, symbolId) {
878
+ const neighbours = api.neighbours(symbolId);
879
+ if (!neighbours)
880
+ return undefined;
881
+ for (const incoming of neighbours.in) {
882
+ if (incoming.edge.kind !== EdgeKind.DeclaresSymbol)
883
+ continue;
884
+ if ('resolved' in incoming.source)
885
+ continue;
886
+ if (incoming.source.kind === NodeKind.File)
887
+ return incoming.source;
888
+ }
889
+ return undefined;
890
+ }
891
+ function packageNameFor(node) {
892
+ return node.id.startsWith('package:') ? node.id.slice('package:'.length) : node.label;
893
+ }
787
894
  function nodeSummary(n) {
788
895
  return {
789
896
  id: n.id,
@@ -816,3 +923,14 @@ function sumValues(record) {
816
923
  n += v;
817
924
  return n;
818
925
  }
926
+ function dedupeNodes(nodes) {
927
+ const seen = new Set();
928
+ const out = [];
929
+ for (const node of nodes) {
930
+ if (seen.has(node.id))
931
+ continue;
932
+ seen.add(node.id);
933
+ out.push(node);
934
+ }
935
+ return out;
936
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"graph.command.d.ts","sourceRoot":"","sources":["../../src/commands/graph.command.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA0BhC,eAAO,MAAM,YAAY,EAAE,eA0M1B,CAAC"}
1
+ {"version":3,"file":"graph.command.d.ts","sourceRoot":"","sources":["../../src/commands/graph.command.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA0BhC,eAAO,MAAM,YAAY,EAAE,eA2M1B,CAAC"}
@@ -17,8 +17,9 @@ const KNOWN_KINDS = [
17
17
  ];
18
18
  export const graphCommand = {
19
19
  name: 'graph',
20
- description: 'Show the SharkCraft knowledge graph: nodes (knowledge/rules/paths/templates/pipelines/presets/packs/boundaries) and edges (related-template, preset-references, pipeline-step-references, …). Supports text|json|dot|mermaid output and an `export` subcommand for writing to file.',
21
- usage: 'shrk [--cwd <dir>] graph [<id>] [--type <kind>] [--format text|json|dot|mermaid] [--output <file>] [--json] | shrk graph export --format dot|mermaid --output <file>',
20
+ description: 'Show the SharkCraft knowledge graph and the code-intelligence graph surface. Use `shrk graph <id>` for asset-graph nodes and `shrk graph index|status|search|context|impact|callers|cycles|unresolved|deps|why|export` for code-graph workflows.',
21
+ usage: 'shrk [--cwd <dir>] graph [<id>] [--type <kind>] [--format text|json|dot|mermaid] [--output <file>] [--json]\n' +
22
+ 'shrk graph index|status|search|context|impact|callers|cycles|unresolved|deps|why|export ...',
22
23
  async run(args) {
23
24
  // Code-intelligence subverbs (R65) don't need the knowledge graph —
24
25
  // dispatch them before the expensive inspection so they stay fast.
@@ -1 +1 @@
1
- {"version":3,"file":"help.command.d.ts","sourceRoot":"","sources":["../../src/commands/help.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAI9D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAiD1C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe;;;;cAK3C;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAA;KAAE,GAAG,MAAM;EAyHpF"}
1
+ {"version":3,"file":"help.command.d.ts","sourceRoot":"","sources":["../../src/commands/help.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAqB9D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAmD1C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe;;;;cAK3C;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAA;KAAE,GAAG,MAAM;EA2HpF"}
@@ -1,5 +1,21 @@
1
1
  import { header } from "../output/format-output.js";
2
2
  import { COMMAND_CATALOG, defaultShowInHelp } from "./command-catalog.js";
3
+ const EXTRA_HELP_LINES = Object.freeze({
4
+ graph: [
5
+ '',
6
+ 'Code-intelligence subverbs:',
7
+ ' graph index — build or refresh the code graph',
8
+ ' graph status — freshness, counts, and unresolved-import summary',
9
+ ' graph search — find files/symbols/packages in the code graph',
10
+ ' graph context — inspect one file or symbol with bridge enrichment',
11
+ ' graph impact — reverse dependent closure for a file or symbol',
12
+ ' graph callers — files that call/reference a symbol',
13
+ ' graph cycles — list import cycles',
14
+ ' graph unresolved — list unresolved imports grouped by file',
15
+ ' graph deps — inbound/outbound package dependencies',
16
+ ' graph why — shortest-path explanation in the knowledge graph',
17
+ ],
18
+ });
3
19
  /**
4
20
  * Product start screen for bare `shrk` / `shrk --help`. Shows the
5
21
  * curated ~20-command "starter" surface organized by workflow phase.
@@ -28,6 +44,7 @@ export function renderStartScreen() {
28
44
  lines.push(' $ shrk recommend "<task>" — what should I do?');
29
45
  lines.push(' $ shrk context --task "<task>" — token-budgeted relevant context');
30
46
  lines.push(' $ shrk task "<task>" — full AI-ready task packet (JSON)');
47
+ lines.push(' $ shrk code-intel — one-shot code-intelligence health summary');
31
48
  lines.push(' $ shrk coverage — what knowledge is missing');
32
49
  lines.push('');
33
50
  lines.push('Generate code safely:');
@@ -37,6 +54,7 @@ export function renderStartScreen() {
37
54
  lines.push(' $ shrk quality — pre-PR gate (doctor + boundaries + coverage + drift)');
38
55
  lines.push('');
39
56
  lines.push('Browse what shrk knows:');
57
+ lines.push(' $ shrk graph status — current code-graph freshness and health');
40
58
  lines.push(' $ shrk knowledge list — knowledge entries');
41
59
  lines.push(' $ shrk rules list — rules + conventions');
42
60
  lines.push(' $ shrk templates list — generator templates');
@@ -76,10 +94,13 @@ export function makeHelpCommand(registry) {
76
94
  ? args.positional[0].split(/\s+/).filter(Boolean)
77
95
  : args.positional.filter(Boolean);
78
96
  const { handler, matchedPath, node } = registry.resolve(tokens);
79
- if (handler && matchedPath.join(' ') === tokens.join(' ')) {
97
+ if (handler && matchedPath.join(' ') === tokens.join(' ') && node.children.size === 0) {
80
98
  // Exact match on a callable command.
81
99
  const canonical = registry.listCommandAliases().get(tokens[0]);
82
100
  process.stdout.write(`${matchedPath.join(' ')} — ${handler.description}\n${handler.usage}\n`);
101
+ const extra = EXTRA_HELP_LINES[matchedPath.join(' ')];
102
+ if (extra)
103
+ process.stdout.write(extra.join('\n') + '\n');
83
104
  if (canonical && tokens.length === 1) {
84
105
  process.stdout.write(`(alias for: ${canonical})\n`);
85
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"impact.command.d.ts","sourceRoot":"","sources":["../../src/commands/impact.command.ts"],"names":[],"mappings":"AAsBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAyVhC,eAAO,MAAM,aAAa,EAAE,eA8V3B,CAAC"}
1
+ {"version":3,"file":"impact.command.d.ts","sourceRoot":"","sources":["../../src/commands/impact.command.ts"],"names":[],"mappings":"AAsBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA0VhC,eAAO,MAAM,aAAa,EAAE,eA8V3B,CAAC"}
@@ -209,13 +209,14 @@ async function runViaGraph(args) {
209
209
  const cwd = resolveCwd(args);
210
210
  const wantJson = flagBool(args, 'json') || flagString(args, 'format') === 'json';
211
211
  const positional = args.positional[0];
212
+ const viaGraphRaw = args.flags.get('via-graph');
212
213
  const files = flagList(args, 'files');
213
214
  const since = flagString(args, 'since');
214
215
  const symbol = flagString(args, 'symbol');
215
216
  const fileFlag = flagString(args, 'file');
216
217
  const limit = flagNumber(args, 'limit') ?? 200;
217
218
  const maxDepth = flagNumber(args, 'max-depth') ?? 5;
218
- const target = positional ?? fileFlag;
219
+ const target = positional ?? fileFlag ?? (typeof viaGraphRaw === 'string' ? viaGraphRaw : undefined);
219
220
  const inputs = files.length > 0
220
221
  ? { kind: 'files', files }
221
222
  : symbol
@@ -295,7 +296,7 @@ export const impactCommand = {
295
296
  // graph-backed payload (sharkcraft.graph-impact-analysis/v3). Keeps
296
297
  // the legacy v2 inspector path as the default so existing
297
298
  // consumers don't shift.
298
- if (flagBool(args, 'via-graph')) {
299
+ if (args.flags.has('via-graph')) {
299
300
  return runViaGraph(args);
300
301
  }
301
302
  const cwd = resolveCwd(args);
@@ -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"}