@shrkcrft/cli 0.1.0-alpha.19 → 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/commands/api-diff.command.js +35 -7
- 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 +8 -0
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +21 -0
- package/dist/commands/compress.command.d.ts.map +1 -1
- package/dist/commands/compress.command.js +14 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +85 -2
- package/dist/commands/contract-gate.command.d.ts.map +1 -1
- package/dist/commands/contract-gate.command.js +5 -1
- package/dist/commands/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +5 -1
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +10 -1
- package/dist/commands/ingest.command.d.ts.map +1 -1
- package/dist/commands/ingest.command.js +5 -1
- package/dist/commands/knowledge.command.d.ts.map +1 -1
- package/dist/commands/knowledge.command.js +5 -2
- package/dist/commands/plan-context.command.d.ts.map +1 -1
- package/dist/commands/plan-context.command.js +13 -5
- package/dist/commands/recommend.command.d.ts.map +1 -1
- package/dist/commands/recommend.command.js +47 -5
- package/dist/commands/task-context.command.d.ts.map +1 -1
- package/dist/commands/task-context.command.js +5 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +9 -1
- package/dist/surface/profiles.d.ts.map +1 -1
- package/dist/surface/profiles.js +54 -9
- package/package.json +34 -34
|
@@ -15,7 +15,7 @@ import { asJson, header, kv } from "../output/format-output.js";
|
|
|
15
15
|
export const apiDiffCommand = {
|
|
16
16
|
name: 'api-diff',
|
|
17
17
|
description: 'Compare the current public API surface to a saved baseline. Reports added / removed / kind-changed / moved symbols, with breaking-change severity.',
|
|
18
|
-
usage: 'shrk api-diff capture --output <path> [--packages a
|
|
18
|
+
usage: 'shrk api-diff capture --output <path> [--packages @scope/a,@scope/b] [--with-signatures] | shrk api-diff <baseline.json> [--packages @scope/a,@scope/b] [--with-signatures] [--json] [--fail-on-breaking] (--packages takes EXACT workspace package names, comma-separated or repeated)',
|
|
19
19
|
async run(args) {
|
|
20
20
|
const cwd = resolveCwd(args);
|
|
21
21
|
const wantJson = flagBool(args, 'json');
|
|
@@ -96,6 +96,7 @@ async function runDiff(args, cwd, wantJson, baselinePath) {
|
|
|
96
96
|
function readSurfaceFromCwd(cwd, args) {
|
|
97
97
|
const packages = flagList(args, 'packages');
|
|
98
98
|
const withSignatures = flagBool(args, 'with-signatures');
|
|
99
|
+
let surface;
|
|
99
100
|
if (withSignatures) {
|
|
100
101
|
const result = extractApiSurfaceWithProgram({
|
|
101
102
|
projectRoot: cwd,
|
|
@@ -104,13 +105,40 @@ function readSurfaceFromCwd(cwd, args) {
|
|
|
104
105
|
for (const d of result.diagnostics.slice(0, 5)) {
|
|
105
106
|
process.stderr.write(`! ${d}\n`);
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
+
surface = result.surface;
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
else {
|
|
111
|
+
const store = new GraphStore(cwd);
|
|
112
|
+
if (!store.exists()) {
|
|
113
|
+
process.stderr.write("Code-graph store missing. Run 'shrk graph index' first.\n");
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const snap = store.loadSnapshot();
|
|
117
|
+
surface = extractApiSurface(snap, {
|
|
118
|
+
...(packages.length > 0 ? { packageFilter: packages } : {}),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return applyPackageFilterGuard(surface, packages);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A `--packages` filter that resolves to no known workspace package is a quiet
|
|
125
|
+
* footgun: the extractor silently returns a 0-symbol surface (exit 0) that is
|
|
126
|
+
* indistinguishable from a package that genuinely exports nothing. When EVERY
|
|
127
|
+
* requested filter is unknown, abort loudly; when only some are, warn and keep
|
|
128
|
+
* the partial result.
|
|
129
|
+
*/
|
|
130
|
+
function applyPackageFilterGuard(surface, packages) {
|
|
131
|
+
const unmatched = surface.unmatchedFilters ?? [];
|
|
132
|
+
if (packages.length === 0 || unmatched.length === 0)
|
|
133
|
+
return surface;
|
|
134
|
+
const matched = Object.keys(surface.countsByPackage).filter((k) => k !== '<no-package>');
|
|
135
|
+
if (unmatched.length === packages.length) {
|
|
136
|
+
process.stderr.write(`--packages matched no known workspace package: ${unmatched.join(', ')}\n` +
|
|
137
|
+
' Pass exact package names (npm "name", e.g. @shrkcrft/core), comma-separated or repeated.\n');
|
|
112
138
|
return undefined;
|
|
113
139
|
}
|
|
114
|
-
|
|
115
|
-
|
|
140
|
+
process.stderr.write(`! --packages: ignoring unknown package(s): ${unmatched.join(', ')}` +
|
|
141
|
+
(matched.length > 0 ? ` (matched: ${matched.join(', ')})` : '') +
|
|
142
|
+
'\n');
|
|
143
|
+
return surface;
|
|
116
144
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codemod.command.d.ts","sourceRoot":"","sources":["../../src/commands/codemod.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codemod.command.d.ts","sourceRoot":"","sources":["../../src/commands/codemod.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAuEhC,eAAO,MAAM,cAAc,EAAE,eAsE5B,CAAC"}
|
|
@@ -8,23 +8,41 @@
|
|
|
8
8
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import * as nodePath from 'node:path';
|
|
10
10
|
import { affectedFromCheckReport, buildCodemodAssistReport, inspectSharkcraft, parseCustomCheckReportFromFile, renderCodemodAssistMarkdown, } from '@shrkcrft/inspector';
|
|
11
|
-
import {
|
|
11
|
+
import { formatRuleCompact } from '@shrkcrft/rules';
|
|
12
|
+
import { flagBool, flagNumber, flagString, flagList, resolveCwd, } from "../command-registry.js";
|
|
12
13
|
import { asJson, header } from "../output/format-output.js";
|
|
13
14
|
async function loadRule(args) {
|
|
14
15
|
const ruleId = flagString(args, 'rule');
|
|
15
16
|
if (!ruleId) {
|
|
16
|
-
process.stderr.write('Missing --rule <ruleId
|
|
17
|
+
process.stderr.write('Missing --rule <ruleId>. Run `shrk codemod list` to see available rule ids.\n');
|
|
17
18
|
return null;
|
|
18
19
|
}
|
|
19
20
|
const cwd = resolveCwd(args);
|
|
20
21
|
const inspection = await inspectSharkcraft({ cwd });
|
|
21
22
|
const rule = inspection.ruleService.get(ruleId);
|
|
22
23
|
if (!rule) {
|
|
23
|
-
process.stderr.write(`No rule with id "${ruleId}".\n`);
|
|
24
|
+
process.stderr.write(`No rule with id "${ruleId}". Run \`shrk codemod list\` to see available rule ids.\n`);
|
|
24
25
|
return null;
|
|
25
26
|
}
|
|
26
27
|
return { rule, cwd };
|
|
27
28
|
}
|
|
29
|
+
/** `shrk codemod list` — enumerate the rule ids codemod-assist accepts. */
|
|
30
|
+
async function listRules(args) {
|
|
31
|
+
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
32
|
+
let rules = inspection.ruleService.list();
|
|
33
|
+
const top = flagNumber(args, 'top');
|
|
34
|
+
if (top !== undefined && top > 0) {
|
|
35
|
+
rules = [...rules].sort((a, b) => a.id.localeCompare(b.id)).slice(0, top);
|
|
36
|
+
}
|
|
37
|
+
if (flagBool(args, 'json')) {
|
|
38
|
+
process.stdout.write(asJson(rules.map((r) => ({ id: r.id, type: r.type, priority: r.priority, title: r.title }))) + '\n');
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
process.stdout.write(header(`Codemod rules (${rules.length})`));
|
|
42
|
+
for (const r of rules)
|
|
43
|
+
process.stdout.write(formatRuleCompact(r) + '\n');
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
28
46
|
async function gatherAffected(args) {
|
|
29
47
|
const fromReport = flagString(args, 'from-report');
|
|
30
48
|
const out = [];
|
|
@@ -57,14 +75,17 @@ function writeAssistOutputs(cwd, ruleId, markdown, scriptTemplate) {
|
|
|
57
75
|
export const codemodCommand = {
|
|
58
76
|
name: 'codemod',
|
|
59
77
|
description: 'Codemod-assist (NOT a codemod engine). Inventory + risk grouping + checklist + project-script template. Never rewrites source.',
|
|
60
|
-
usage: 'shrk codemod <inventory|plan|checklist> --rule <ruleId> [--from-report <path>] [--targets a,b,c] [--write-preview] [--json]',
|
|
78
|
+
usage: 'shrk codemod <list|inventory|plan|checklist> --rule <ruleId> [--from-report <path>] [--targets a,b,c] [--write-preview] [--json]',
|
|
61
79
|
async run(args) {
|
|
62
80
|
const sub = args.positional[0] ?? 'plan';
|
|
63
|
-
if (!['inventory', 'plan', 'checklist'].includes(sub)) {
|
|
64
|
-
process.stderr.write('Usage: shrk codemod <inventory|plan|checklist> --rule <ruleId>\n');
|
|
81
|
+
if (!['list', 'inventory', 'plan', 'checklist'].includes(sub)) {
|
|
82
|
+
process.stderr.write('Usage: shrk codemod <list|inventory|plan|checklist> --rule <ruleId>\n');
|
|
65
83
|
return 2;
|
|
66
84
|
}
|
|
67
85
|
const inner = { ...args, positional: args.positional.slice(1) };
|
|
86
|
+
// `list` enumerates rule ids and needs no --rule.
|
|
87
|
+
if (sub === 'list')
|
|
88
|
+
return listRules(inner);
|
|
68
89
|
const loaded = await loadRule(inner);
|
|
69
90
|
if (!loaded)
|
|
70
91
|
return 1;
|
|
@@ -266,4 +266,12 @@ export interface ICommandSafetyMatrixRow {
|
|
|
266
266
|
}
|
|
267
267
|
export declare function buildCommandSafetyMatrix(): readonly ICommandSafetyMatrixRow[];
|
|
268
268
|
export declare function renderCommandSafetyMatrixMarkdown(rows: readonly ICommandSafetyMatrixRow[]): string;
|
|
269
|
+
/**
|
|
270
|
+
* The set of TOP-LEVEL command verbs in the catalogue (the first token of each
|
|
271
|
+
* entry's `command`). The single source of truth for "is `shrk <verb>` a real
|
|
272
|
+
* command" checks — e.g. the contradictions doc-vs-CLI scan, which lives in the
|
|
273
|
+
* inspector layer and so receives this set by injection rather than importing
|
|
274
|
+
* the CLI.
|
|
275
|
+
*/
|
|
276
|
+
export declare function cliCommandNameSet(): Set<string>;
|
|
269
277
|
//# sourceMappingURL=command-catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -3572,3 +3572,24 @@ export function renderCommandSafetyMatrixMarkdown(rows) {
|
|
|
3572
3572
|
}
|
|
3573
3573
|
return lines.join('\n') + '\n';
|
|
3574
3574
|
}
|
|
3575
|
+
/**
|
|
3576
|
+
* The set of TOP-LEVEL command verbs in the catalogue (the first token of each
|
|
3577
|
+
* entry's `command`). The single source of truth for "is `shrk <verb>` a real
|
|
3578
|
+
* command" checks — e.g. the contradictions doc-vs-CLI scan, which lives in the
|
|
3579
|
+
* inspector layer and so receives this set by injection rather than importing
|
|
3580
|
+
* the CLI.
|
|
3581
|
+
*/
|
|
3582
|
+
export function cliCommandNameSet() {
|
|
3583
|
+
const out = new Set();
|
|
3584
|
+
for (const entry of COMMAND_CATALOG) {
|
|
3585
|
+
const top = entry.command.split(/\s+/)[0];
|
|
3586
|
+
if (top)
|
|
3587
|
+
out.add(top);
|
|
3588
|
+
for (const alias of entry.aliases) {
|
|
3589
|
+
const aliasTop = alias.split(/\s+/)[0];
|
|
3590
|
+
if (aliasTop)
|
|
3591
|
+
out.add(aliasTop);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
return out;
|
|
3595
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.command.d.ts","sourceRoot":"","sources":["../../src/commands/compress.command.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"compress.command.d.ts","sourceRoot":"","sources":["../../src/commands/compress.command.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAgChC,eAAO,MAAM,eAAe,EAAE,eA8F7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,eA4B3B,CAAC"}
|
|
@@ -5,6 +5,10 @@ import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-regist
|
|
|
5
5
|
import { asJson } from "../output/format-output.js";
|
|
6
6
|
import { ccrDir, openCcrStore } from "../output/ccr-store-config.js";
|
|
7
7
|
const CONTENT_TYPES = new Set(Object.values(EContentType));
|
|
8
|
+
// Below this size a passthrough no-op isn't worth a warning (tiny snippets
|
|
9
|
+
// legitimately have nothing to compress). Above it, a silent `−0%` re-emit is
|
|
10
|
+
// the opposite of the tool's purpose — nudge the user toward `--type`.
|
|
11
|
+
const PASSTHROUGH_HINT_MIN_BYTES = 128;
|
|
8
12
|
function readInput(args) {
|
|
9
13
|
const positional = args.positional[0];
|
|
10
14
|
const useStdin = flagBool(args, 'stdin') || positional === undefined || positional === '-';
|
|
@@ -97,6 +101,16 @@ export const compressCommand = {
|
|
|
97
101
|
process.stdout.write(result.compressed + '\n');
|
|
98
102
|
const cached = result.ccrKey ? ` · original cached as ${result.ccrKey} (shrk expand ${result.ccrKey})` : '';
|
|
99
103
|
process.stderr.write(`${result.strategy}: ~${result.savings.before} → ~${result.savings.after} tokens (−${pct}%, est.)${cached}\n`);
|
|
104
|
+
// Token-economy guard: when auto-detect declines to compress a non-trivial
|
|
105
|
+
// input, a silent `−0%` re-emit looks like success. Nudge toward `--type`
|
|
106
|
+
// (stdout stays the verbatim blob; exit code unchanged).
|
|
107
|
+
const inputBytes = Buffer.byteLength(content, 'utf8');
|
|
108
|
+
if (result.strategy === ECompressionStrategy.Passthrough &&
|
|
109
|
+
inputBytes >= PASSTHROUGH_HINT_MIN_BYTES &&
|
|
110
|
+
!flagBool(args, 'lossless')) {
|
|
111
|
+
process.stderr.write(`hint: nothing was compressed — auto-detect classified this as ${result.contentType} and found no win. ` +
|
|
112
|
+
'Try `--type <content-type>` to force a strategy (json, git-diff, search-results, build-log, source-code, markdown).\n');
|
|
113
|
+
}
|
|
100
114
|
return 0;
|
|
101
115
|
},
|
|
102
116
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"AA8BA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAiGhC,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAoDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAwFpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAoErC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmCtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAwBpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAiClC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA4BrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA8BrC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0DpC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0LpC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import * as nodePath from 'node:path';
|
|
3
3
|
import { AdoptionCheckpointStatus, buildConstructAdoptionDiff, buildConstructAdoptionPlan, buildSearchIndex, ConstructAdoptionCategory, evaluateAdoptionCheckpoint, hashDiffBody, inferConstructs, InferredConstructConfidence, inspectSharkcraft, loadConstructs, loadPlaybooks, readAdoptionCheckpoint, readConstructAdoptionStatus, recordAdoptionCheckpoint, renderConstructAdoptionDiff, renderConstructAdoptionMarkdown, renderConstructDraftsModule, searchIndex, SearchKind, traceConstruct, writeConstructAdoption, } from '@shrkcrft/inspector';
|
|
4
|
+
import { GraphQueryApi, GraphStore } from '@shrkcrft/graph';
|
|
4
5
|
import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-registry.js";
|
|
5
6
|
import { asJson, header } from "../output/format-output.js";
|
|
6
7
|
async function loadAll(args) {
|
|
@@ -9,6 +10,64 @@ async function loadAll(args) {
|
|
|
9
10
|
const constructs = await loadConstructs(inspection);
|
|
10
11
|
return { constructs, inspection };
|
|
11
12
|
}
|
|
13
|
+
const GLOB_MAGIC = /[*?[\]{}]/;
|
|
14
|
+
function globToRegExp(glob) {
|
|
15
|
+
// Compile a minimal file glob (`**`, `*`, `?`) to an anchored RegExp. Mark the
|
|
16
|
+
// wildcards with control-char placeholders BEFORE regex-escaping the rest, so
|
|
17
|
+
// the escape pass and the wildcard expansion can never clobber each other (an
|
|
18
|
+
// earlier space-sentinel version was corrupted by editor whitespace handling).
|
|
19
|
+
const DSTAR_SLASH = '\u0000';
|
|
20
|
+
const DSTAR = '\u0001';
|
|
21
|
+
const STAR = '\u0002';
|
|
22
|
+
const QMARK = '\u0003';
|
|
23
|
+
const marked = glob
|
|
24
|
+
.replace(/\*\*\//g, DSTAR_SLASH)
|
|
25
|
+
.replace(/\*\*/g, DSTAR)
|
|
26
|
+
.replace(/\*/g, STAR)
|
|
27
|
+
.replace(/\?/g, QMARK);
|
|
28
|
+
const pattern = marked
|
|
29
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
30
|
+
.replaceAll(DSTAR_SLASH, '(?:.*/)?')
|
|
31
|
+
.replaceAll(DSTAR, '.*')
|
|
32
|
+
.replaceAll(STAR, '[^/]*')
|
|
33
|
+
.replaceAll(QMARK, '[^/]');
|
|
34
|
+
return new RegExp(`^${pattern}$`);
|
|
35
|
+
}
|
|
36
|
+
function enrichTraceWithGraph(declaredFiles, declaredNames, cwd) {
|
|
37
|
+
if (!new GraphStore(cwd).exists()) {
|
|
38
|
+
return { graphState: 'missing', resolvedFiles: [], unresolvedGlobs: [], undeclaredSymbols: [] };
|
|
39
|
+
}
|
|
40
|
+
const api = GraphQueryApi.fromStore(cwd);
|
|
41
|
+
const allPaths = [...api.allFiles()].map((n) => n.path).filter((p) => !!p);
|
|
42
|
+
const resolved = new Set();
|
|
43
|
+
const unresolvedGlobs = [];
|
|
44
|
+
for (const entry of declaredFiles) {
|
|
45
|
+
if (GLOB_MAGIC.test(entry)) {
|
|
46
|
+
const re = globToRegExp(entry);
|
|
47
|
+
const matches = allPaths.filter((p) => re.test(p));
|
|
48
|
+
if (matches.length === 0)
|
|
49
|
+
unresolvedGlobs.push(entry);
|
|
50
|
+
for (const m of matches)
|
|
51
|
+
resolved.add(m);
|
|
52
|
+
}
|
|
53
|
+
else if (api.findFile(entry)) {
|
|
54
|
+
resolved.add(entry);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const undeclared = new Set();
|
|
58
|
+
for (const path of resolved) {
|
|
59
|
+
for (const sym of api.symbolsIn(`file:${path}`)) {
|
|
60
|
+
if (sym.label && !declaredNames.has(sym.label))
|
|
61
|
+
undeclared.add(sym.label);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
graphState: 'fresh',
|
|
66
|
+
resolvedFiles: [...resolved].sort(),
|
|
67
|
+
unresolvedGlobs,
|
|
68
|
+
undeclaredSymbols: [...undeclared].sort(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
12
71
|
export const constructsListCommand = {
|
|
13
72
|
name: 'list',
|
|
14
73
|
description: 'List registered constructs.',
|
|
@@ -91,7 +150,7 @@ export const constructsGetCommand = {
|
|
|
91
150
|
};
|
|
92
151
|
export const constructsTraceCommand = {
|
|
93
152
|
name: 'trace',
|
|
94
|
-
description: 'Trace
|
|
153
|
+
description: 'Trace a construct\'s declared files / publicApi / events / tokens, verified against the code graph (expands file globs, flags globs that match nothing, lists undeclared symbols defined in those files). --deep adds related / test pointers.',
|
|
95
154
|
usage: 'shrk constructs trace <id> [--deep] [--json]',
|
|
96
155
|
async run(args) {
|
|
97
156
|
const id = args.positional[0];
|
|
@@ -107,6 +166,10 @@ export const constructsTraceCommand = {
|
|
|
107
166
|
}
|
|
108
167
|
const trace = traceConstruct(c);
|
|
109
168
|
const deep = flagBool(args, 'deep');
|
|
169
|
+
// Verify the hand-declared inventory against the code graph (additive — does
|
|
170
|
+
// not change the declared files/tokens the other subverbs rely on).
|
|
171
|
+
const declaredNames = new Set([...trace.publicApi, ...trace.tokens, ...trace.events]);
|
|
172
|
+
const graph = enrichTraceWithGraph(trace.files, declaredNames, resolveCwd(args));
|
|
110
173
|
const relatedAll = [
|
|
111
174
|
...(c.relatedKnowledge ?? []),
|
|
112
175
|
...(c.relatedRules ?? []),
|
|
@@ -122,7 +185,7 @@ export const constructsTraceCommand = {
|
|
|
122
185
|
}
|
|
123
186
|
: undefined;
|
|
124
187
|
if (flagBool(args, 'json')) {
|
|
125
|
-
process.stdout.write(asJson({ ...trace, ...(deepBlock ? { deep: deepBlock } : {}) }) + '\n');
|
|
188
|
+
process.stdout.write(asJson({ ...trace, graph, ...(deepBlock ? { deep: deepBlock } : {}) }) + '\n');
|
|
126
189
|
return 0;
|
|
127
190
|
}
|
|
128
191
|
process.stdout.write(header(`Trace: ${id}`));
|
|
@@ -145,6 +208,26 @@ export const constructsTraceCommand = {
|
|
|
145
208
|
for (const w of trace.warnings)
|
|
146
209
|
process.stdout.write(` ! ${w}\n`);
|
|
147
210
|
}
|
|
211
|
+
// Graph-verified view: this is the part that makes the declared inventory
|
|
212
|
+
// trustworthy rather than a hand-typed partial map.
|
|
213
|
+
if (graph.graphState === 'missing') {
|
|
214
|
+
process.stdout.write('\n(declared inventory only — run `shrk graph index` for a graph-verified inventory)\n');
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
if (graph.unresolvedGlobs.length > 0) {
|
|
218
|
+
process.stdout.write('Unresolved file globs (matched 0 files in the graph):\n');
|
|
219
|
+
for (const g of graph.unresolvedGlobs)
|
|
220
|
+
process.stdout.write(` ! ${g}\n`);
|
|
221
|
+
}
|
|
222
|
+
if (graph.undeclaredSymbols.length > 0) {
|
|
223
|
+
process.stdout.write(`Graph found ${graph.undeclaredSymbols.length} symbol(s) defined in these files but NOT declared on the construct:\n`);
|
|
224
|
+
for (const s of graph.undeclaredSymbols.slice(0, 30))
|
|
225
|
+
process.stdout.write(` + ${s}\n`);
|
|
226
|
+
if (graph.undeclaredSymbols.length > 30) {
|
|
227
|
+
process.stdout.write(` … (${graph.undeclaredSymbols.length - 30} more)\n`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
148
231
|
if (deepBlock) {
|
|
149
232
|
process.stdout.write('\nDeep:\n');
|
|
150
233
|
if (deepBlock.related.length > 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/contract-gate.command.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAWhC,eAAO,MAAM,oBAAoB,EAAE,eAqDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA6EpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"contract-gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/contract-gate.command.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAWhC,eAAO,MAAM,oBAAoB,EAAE,eAqDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA6EpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAiEnC,CAAC"}
|
|
@@ -148,7 +148,11 @@ export const contractStatusCommand = {
|
|
|
148
148
|
async run(args) {
|
|
149
149
|
const contractFile = args.positional[0];
|
|
150
150
|
if (!contractFile) {
|
|
151
|
-
|
|
151
|
+
// `contract status` inspects a SAVED contract file — it is not a zero-arg
|
|
152
|
+
// project-health command. Point at the canonical task form so the verb
|
|
153
|
+
// doesn't read as a broken status command.
|
|
154
|
+
process.stderr.write('Usage: shrk contract status <contract.json> (inspect a saved contract file)\n');
|
|
155
|
+
process.stderr.write('To build/inspect a contract for a task, run: shrk contract "<task>"\n');
|
|
152
156
|
return 2;
|
|
153
157
|
}
|
|
154
158
|
const cwd = resolveCwd(args);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/gate.command.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/gate.command.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,eA+FzB,CAAC"}
|
|
@@ -18,7 +18,7 @@ import { asJson, header, kv } from "../output/format-output.js";
|
|
|
18
18
|
export const gateCommand = {
|
|
19
19
|
name: 'gate',
|
|
20
20
|
description: 'Aggregator: runs the code-intelligence quality gates (graph freshness, architecture, impact-since-ref) and reports a single pass/fail.',
|
|
21
|
-
usage: 'shrk gate [--since <gitref>] [--fail-on critical,high] [--disable arch,impact,api-diff] [--api-baseline <path>] [--no-fail-on-breaking] [--strict] [--no-persist] [--json] [--markdown] [--output <path>]\n shrk gate scaffold-ci [--provider github|generic] [--force] [--json]\n shrk gate scaffold-hook [--provider husky|raw] [--force] [--json]',
|
|
21
|
+
usage: 'shrk gate [--since <gitref>] [--fail-on critical,high] [--arch-all] [--disable arch,impact,api-diff] [--api-baseline <path>] [--no-fail-on-breaking] [--strict] [--no-persist] [--json] [--markdown] [--output <path>]\n (the arch gate is baseline-relative by default once a baseline is frozen — fails only on NEW errors; --arch-all fails on total)\n shrk gate scaffold-ci [--provider github|generic] [--force] [--json]\n shrk gate scaffold-hook [--provider husky|raw] [--force] [--json]',
|
|
22
22
|
async run(args) {
|
|
23
23
|
if (args.positional[0] === 'scaffold-ci') {
|
|
24
24
|
const sliced = { ...args, positional: args.positional.slice(1) };
|
|
@@ -42,8 +42,12 @@ export const gateCommand = {
|
|
|
42
42
|
? failOnRaw.split(',').map((s) => s.trim()).filter(Boolean)
|
|
43
43
|
: undefined;
|
|
44
44
|
const disable = disableRaw ? disableRaw.split(',').map((s) => s.trim()).filter(Boolean) : undefined;
|
|
45
|
+
// --arch-all: fail on TOTAL architecture errors (ignore the frozen baseline).
|
|
46
|
+
// By default the arch gate is baseline-relative — it fails only on NEW errors.
|
|
47
|
+
const archAll = flagBool(args, 'arch-all');
|
|
45
48
|
const report = runQualityGates({
|
|
46
49
|
projectRoot: cwd,
|
|
50
|
+
...(archAll ? { arch: { baselineRelative: false } } : {}),
|
|
47
51
|
impact: {
|
|
48
52
|
...(sinceRef ? { sinceRef } : {}),
|
|
49
53
|
...(failOn ? { failOn } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-code-subverbs.d.ts","sourceRoot":"","sources":["../../src/commands/graph-code-subverbs.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiI3F,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBrE;AA4FD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+DtE;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAwF1E;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8EpE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmFtE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDtE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgMvE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"graph-code-subverbs.d.ts","sourceRoot":"","sources":["../../src/commands/graph-code-subverbs.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiI3F,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBrE;AA4FD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+DtE;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAwF1E;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8EpE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmFtE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDtE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgMvE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8HtE;AAID;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+CpE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+EvE;AAyBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgHpE"}
|
|
@@ -878,6 +878,11 @@ export async function runGraphImpact(args) {
|
|
|
878
878
|
for (const d of liveDirect.slice(0, 30)) {
|
|
879
879
|
process.stdout.write(` ${d.path ?? d.id}\n`);
|
|
880
880
|
}
|
|
881
|
+
// No silent caps: when the reverse closure hit the limit, say so explicitly so
|
|
882
|
+
// the reader knows the blast radius is larger than what's shown.
|
|
883
|
+
if (closure.truncated) {
|
|
884
|
+
process.stdout.write(`\n ⓘ Showing ${liveDirect.length + liveTransitive.length} of ${payload.totalReached} dependents (capped at --limit ${limit}); raise --limit to see the full blast radius.\n`);
|
|
885
|
+
}
|
|
881
886
|
if (fresh.field) {
|
|
882
887
|
process.stdout.write(`\n ⚠ ${fresh.modified.length} dependent file(s) changed, ${fresh.deleted.length} deleted since indexing — run \`shrk graph index --changed\`.\n`);
|
|
883
888
|
}
|
|
@@ -980,7 +985,11 @@ export async function runGraphCallers(args) {
|
|
|
980
985
|
const ambiguityNote = alsoNamed > 0
|
|
981
986
|
? `${alsoNamed + 1} symbols named "${sym.label}"; showing callers of the one at ${sym.path ?? sym.id}${sym.line ? ':' + sym.line : ''}. Pass a symbol: id to disambiguate.`
|
|
982
987
|
: undefined;
|
|
983
|
-
|
|
988
|
+
// `total` is distinct caller FILES: at index time the graph collapses many
|
|
989
|
+
// call/reference sites in one file to a single edge. Say so, otherwise `total`
|
|
990
|
+
// reads as a raw invocation count and under-reports.
|
|
991
|
+
const dedupNote = 'total counts distinct caller files — multiple sites within one file collapse to a single entry.';
|
|
992
|
+
const note = [ambiguityNote, langNote, dedupNote].filter(Boolean).join(' ');
|
|
984
993
|
const payload = {
|
|
985
994
|
schema: 'sharkcraft.graph-callers/v1',
|
|
986
995
|
symbol: nodeSummary(sym),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest.command.d.ts","sourceRoot":"","sources":["../../src/commands/ingest.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ingest.command.d.ts","sourceRoot":"","sources":["../../src/commands/ingest.command.ts"],"names":[],"mappings":"AA0CA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAOhC,eAAO,MAAM,aAAa,EAAE,eA4B3B,CAAC;AAmZF,eAAO,MAAM,qBAAqB,EAAE,eAkBnC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,eA8B9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,eAkC9B,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import * as nodePath from 'node:path';
|
|
3
|
+
import { cliCommandNameSet } from "./command-catalog.js";
|
|
3
4
|
import { applyIngestPlan, buildContradictionReport, buildGeneratedCodeReport, buildIngestAdoptionPlan, buildIngestApplyPlan, buildRepositoryKnowledgeModel, buildStabilityMap, inspectSharkcraft, IngestAdoptionStatus, IngestDepth, IngestSection, loadIngestApplyPlan, renderContradictionReportHtml, renderContradictionReportJson, renderContradictionReportMarkdown, renderContradictionReportText, renderGeneratedCodeReportJson, renderGeneratedCodeReportMarkdown, renderGeneratedCodeReportText, renderIngestAdoptionPatch, renderIngestAdoptionPlanMarkdown, renderIngestApplyReviewMarkdown, renderRepositoryKnowledgeModelHtml, renderRepositoryKnowledgeModelJson, renderRepositoryKnowledgeModelMarkdown, renderRepositoryKnowledgeModelText, renderStabilityMapJson, renderStabilityMapMarkdown, renderStabilityMapText, saveIngestApplyPlan, signIngestApplyPlan, writeIngestAdoption, writeIngestDrafts, } from '@shrkcrft/inspector';
|
|
4
5
|
import { flagBool, flagString, flagList, resolveCwd, } from "../command-registry.js";
|
|
5
6
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
@@ -442,7 +443,10 @@ export const contradictionsCommand = {
|
|
|
442
443
|
const cwd = resolveCwd(args);
|
|
443
444
|
const format = parseFormat(flagString(args, 'format'));
|
|
444
445
|
const inspection = await inspectSharkcraft({ cwd });
|
|
445
|
-
const report = buildContradictionReport({
|
|
446
|
+
const report = buildContradictionReport({
|
|
447
|
+
inspection,
|
|
448
|
+
cliCommandNames: cliCommandNameSet(),
|
|
449
|
+
});
|
|
446
450
|
if (format === 'json')
|
|
447
451
|
process.stdout.write(renderContradictionReportJson(report) + '\n');
|
|
448
452
|
else if (format === 'markdown')
|
|
@@ -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";
|
|
@@ -84,7 +84,10 @@ export const knowledgeListCommand = {
|
|
|
84
84
|
tags: e.tags,
|
|
85
85
|
appliesWhen: e.appliesWhen,
|
|
86
86
|
}))
|
|
87
|
-
:
|
|
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);
|
|
88
91
|
process.stdout.write(asJson(payload) + '\n');
|
|
89
92
|
return 0;
|
|
90
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-context.command.d.ts","sourceRoot":"","sources":["../../src/commands/plan-context.command.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"plan-context.command.d.ts","sourceRoot":"","sources":["../../src/commands/plan-context.command.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAsEhC,CAAC"}
|
|
@@ -11,7 +11,7 @@ import { asJson, header, kv } from "../output/format-output.js";
|
|
|
11
11
|
*/
|
|
12
12
|
export const planContextCommand = {
|
|
13
13
|
name: 'plan-context',
|
|
14
|
-
description: 'Produce a deterministic, token-budgeted context pack (`sharkcraft.context-pack/v1`) for an AI agent: ranked files,
|
|
14
|
+
description: 'Produce a deterministic, token-budgeted context pack (`sharkcraft.context-pack/v1`) for an AI agent: ranked files, likely tests, and (shallow) surfaced risks / do-not-touch zones. Rules/paths/templates require the rule-graph bridge (`shrk rule-graph index`); the pack reports per-field `coverage` so empty sections are distinguishable from not-computed ones.',
|
|
15
15
|
usage: 'shrk plan-context "<task>" [--budget N] [--max-files N] [--hint-file <path>] [--hint-package <prefix>] [--json]',
|
|
16
16
|
async run(args) {
|
|
17
17
|
const cwd = resolveCwd(args);
|
|
@@ -40,11 +40,19 @@ export const planContextCommand = {
|
|
|
40
40
|
process.stdout.write(header(`Context pack: ${task}`));
|
|
41
41
|
process.stdout.write(kv('intent', pack.intent) + '\n');
|
|
42
42
|
process.stdout.write(kv('files', String(pack.files.length)) + '\n');
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// Distinguish "computed, none apply" from "not computed". When the bridge
|
|
44
|
+
// is missing, rules/paths/templates are omitted, not empty — say so rather
|
|
45
|
+
// than printing a misleading `0`.
|
|
46
|
+
if (pack.coverage.rulesComputed) {
|
|
47
|
+
process.stdout.write(kv('rules', String(pack.rules.length)) + '\n');
|
|
48
|
+
process.stdout.write(kv('paths', String(pack.paths.length)) + '\n');
|
|
49
|
+
process.stdout.write(kv('templates', String(pack.templates.length)) + '\n');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
process.stdout.write(kv('rules/paths/templates', 'not computed (run `shrk rule-graph index`)') + '\n');
|
|
53
|
+
}
|
|
46
54
|
process.stdout.write(kv('tests', String(pack.tests.length)) + '\n');
|
|
47
|
-
process.stdout.write(kv('risks', String(pack.risks.length)) + '\n');
|
|
55
|
+
process.stdout.write(kv('risks', pack.coverage.risksComputed ? String(pack.risks.length) : 'not computed') + '\n');
|
|
48
56
|
process.stdout.write(kv('budget', `${pack.budget.used}/${pack.budget.requested} tokens` + (pack.budget.truncated ? ' (truncated)' : '')) + '\n');
|
|
49
57
|
if (pack.files.length > 0) {
|
|
50
58
|
process.stdout.write('\nTop files:\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recommend.command.d.ts","sourceRoot":"","sources":["../../src/commands/recommend.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recommend.command.d.ts","sourceRoot":"","sources":["../../src/commands/recommend.command.ts"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAShC,eAAO,MAAM,gBAAgB,EAAE,eAkP9B,CAAC;AA0HF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAY3D;AAcD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAcxD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { buildUniversalSearch, entrypointBanner, explainTaskRouting, inspectSharkcraft, recommendCommands, renderUncertaintyReportText, } from '@shrkcrft/inspector';
|
|
2
|
+
import { buildUniversalSearch, entrypointBanner, explainTaskRouting, inspectSharkcraft, rankAll, recommendCommands, renderUncertaintyReportText, } from '@shrkcrft/inspector';
|
|
3
3
|
import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-registry.js";
|
|
4
4
|
import { asJson } from "../output/format-output.js";
|
|
5
5
|
import { loadSurfaceContext } from "../surface/load-surface-context.js";
|
|
@@ -65,6 +65,10 @@ export const recommendCommand = {
|
|
|
65
65
|
const machineJson = flagBool(args, 'json') || flagBool(args, 'machine-json');
|
|
66
66
|
let routingMatches = [];
|
|
67
67
|
let searchReport = null;
|
|
68
|
+
// Reconcile with `brief`/`task`: those route through the SAME shared ranker
|
|
69
|
+
// (`rankAll`). Consult it here so `recommend` never claims a "coverage gap"
|
|
70
|
+
// for a task the rest of the engine confidently matches to a template/pipeline.
|
|
71
|
+
let ranking = null;
|
|
68
72
|
if (query.length > 0) {
|
|
69
73
|
try {
|
|
70
74
|
routingMatches = await explainTaskRouting(inspection, query);
|
|
@@ -78,7 +82,17 @@ export const recommendCommand = {
|
|
|
78
82
|
catch {
|
|
79
83
|
searchReport = null;
|
|
80
84
|
}
|
|
85
|
+
try {
|
|
86
|
+
ranking = rankAll(inspection, query);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
ranking = null;
|
|
90
|
+
}
|
|
81
91
|
}
|
|
92
|
+
const topTemplate = ranking?.templates[0];
|
|
93
|
+
const topPipeline = ranking?.pipelines[0];
|
|
94
|
+
const engineHasMatch = (topTemplate?.score ?? 0) >= TEMPLATE_MATCH_THRESHOLD ||
|
|
95
|
+
(topPipeline?.score ?? 0) >= PIPELINE_MATCH_THRESHOLD;
|
|
82
96
|
// R1 — promote a strongly-matched task-routing hint's recommends.commands
|
|
83
97
|
// into the HEADLINE for create/build intents. Routing hints are scored by
|
|
84
98
|
// explainTaskRouting but were previously only shown under --verbose, so the
|
|
@@ -115,6 +129,12 @@ export const recommendCommand = {
|
|
|
115
129
|
routingMatches,
|
|
116
130
|
search: searchReport,
|
|
117
131
|
gated,
|
|
132
|
+
rankerMatch: ranking
|
|
133
|
+
? {
|
|
134
|
+
topTemplate: topTemplate ? { id: topTemplate.item.id, score: topTemplate.score } : null,
|
|
135
|
+
topPipeline: topPipeline ? { id: topPipeline.item.id, score: topPipeline.score } : null,
|
|
136
|
+
}
|
|
137
|
+
: null,
|
|
118
138
|
}) + '\n');
|
|
119
139
|
return 0;
|
|
120
140
|
}
|
|
@@ -158,16 +178,29 @@ export const recommendCommand = {
|
|
|
158
178
|
}
|
|
159
179
|
}
|
|
160
180
|
}
|
|
161
|
-
// Coverage gap — explicit if recommendations look thin
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
181
|
+
// Coverage gap — explicit if recommendations look thin AND no routing hint
|
|
182
|
+
// fired AND the shared ranker (the engine `brief`/`task` use) also found no
|
|
183
|
+
// template/pipeline. The last clause stops `recommend` from contradicting
|
|
184
|
+
// `task`/`brief`, which would confidently route the same task.
|
|
185
|
+
const thinResult = report.recommendations.length <= 1 && routingMatches.length === 0 && query.length > 0;
|
|
186
|
+
if (thinResult && !engineHasMatch) {
|
|
165
187
|
process.stdout.write(`\n⚠ Coverage gap — no recipe, no routing hint, and no helper/template matched "${query}".\n` +
|
|
166
188
|
` Suggest:\n` +
|
|
167
189
|
` shrk coverage scaffolds --task "${query}"\n` +
|
|
168
190
|
` shrk feedback actions\n` +
|
|
169
191
|
` (or contribute a pack template / helper / routing hint)\n`);
|
|
170
192
|
}
|
|
193
|
+
else if (thinResult && engineHasMatch && !actionsOnly) {
|
|
194
|
+
// The recipe/routing surface was thin, but the shared ranker DID match —
|
|
195
|
+
// surface that concrete next step instead of a misleading gap.
|
|
196
|
+
process.stdout.write('\nEngine match (shared ranker — same as `shrk task` / `shrk brief`):\n');
|
|
197
|
+
if (topTemplate && topTemplate.score >= TEMPLATE_MATCH_THRESHOLD) {
|
|
198
|
+
process.stdout.write(` $ shrk gen ${topTemplate.item.id} <name> --dry-run [writes-source] — template "${topTemplate.item.name}" matched (score ${topTemplate.score}).\n`);
|
|
199
|
+
}
|
|
200
|
+
if (topPipeline && topPipeline.score >= PIPELINE_MATCH_THRESHOLD) {
|
|
201
|
+
process.stdout.write(` Pipeline: ${topPipeline.item.id} — run \`shrk task "${query}"\` for the full packet.\n`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
171
204
|
if (gated.length > 0 && !actionsOnly) {
|
|
172
205
|
process.stdout.write(`\nGated (experimental, not enabled in this repo):\n`);
|
|
173
206
|
for (const g of gated.slice(0, 3)) {
|
|
@@ -287,6 +320,15 @@ const PLANNING_VERBS = new Set([
|
|
|
287
320
|
* keyword/regex hits — a real match, not a single weak keyword.
|
|
288
321
|
*/
|
|
289
322
|
const ROUTING_HINT_PROMOTE_THRESHOLD = 3;
|
|
323
|
+
/**
|
|
324
|
+
* Minimum `rankAll` score for a template / pipeline to count as a real engine
|
|
325
|
+
* match — used only to suppress a false "coverage gap" verdict (and surface the
|
|
326
|
+
* match) when the recipe/routing surface is thin but the shared ranker, which
|
|
327
|
+
* `brief`/`task` also use, found project coverage. Conservative: a single weak
|
|
328
|
+
* token hit scores below this.
|
|
329
|
+
*/
|
|
330
|
+
const TEMPLATE_MATCH_THRESHOLD = 3;
|
|
331
|
+
const PIPELINE_MATCH_THRESHOLD = 3;
|
|
290
332
|
const CREATE_BUILD_VERBS = new Set([
|
|
291
333
|
'create', 'build', 'add', 'generate', 'scaffold', 'implement', 'make', 'new', 'introduce', 'write',
|
|
292
334
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-context.command.d.ts","sourceRoot":"","sources":["../../src/commands/task-context.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"task-context.command.d.ts","sourceRoot":"","sources":["../../src/commands/task-context.command.ts"],"names":[],"mappings":"AAuBA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAahC,eAAO,MAAM,qBAAqB,EAAE,eAyEnC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAsEnC,CAAC;AAIF,eAAO,MAAM,mBAAmB,EAAE,eA2DjC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAoBlC,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import * as nodePath from 'node:path';
|
|
3
|
+
import { cliCommandNameSet } from "./command-catalog.js";
|
|
3
4
|
import { analyzeImportGraph, buildAgentBrief, buildContradictionReport, buildGeneratedCodeReport, buildRepositoryKnowledgeModel, buildTaskPacket, buildTaskRiskReport, classifyChangeIntent, detectLanguageProfiles, getChangedFiles, getStatusSummary, inspectSharkcraft, isGitRepo, listConstructs, loadRepositoryMemory, } from '@shrkcrft/inspector';
|
|
4
5
|
import { flagBool, flagString, flagList, resolveCwd, } from "../command-registry.js";
|
|
5
6
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
@@ -102,7 +103,10 @@ export const validateChangeCommand = {
|
|
|
102
103
|
}
|
|
103
104
|
// Fallback path through getStatusSummary not necessary — getChangedFiles already covers it.
|
|
104
105
|
void getStatusSummary;
|
|
105
|
-
const contradictions = buildContradictionReport({
|
|
106
|
+
const contradictions = buildContradictionReport({
|
|
107
|
+
inspection,
|
|
108
|
+
cliCommandNames: cliCommandNameSet(),
|
|
109
|
+
});
|
|
106
110
|
const generated = buildGeneratedCodeReport({ inspection });
|
|
107
111
|
const generatedPaths = new Set(generated.generatedFiles.map((f) => f.path));
|
|
108
112
|
const boundaryHits = changed.filter((f) => looksLikeBoundaryViolation(f));
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AAwX/B,wBAAgB,aAAa,IAAI,eAAe,CA4X/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;AAsHD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AAwX/B,wBAAgB,aAAa,IAAI,eAAe,CA4X/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;AAsHD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAoDxE"}
|
package/dist/main.js
CHANGED
|
@@ -644,7 +644,15 @@ async function runCliInner(argv) {
|
|
|
644
644
|
* Exported for tests.
|
|
645
645
|
*/
|
|
646
646
|
export function looksLikeFreeFormTask(tokens) {
|
|
647
|
-
|
|
647
|
+
// Flatten on internal whitespace so the canonical *quoted* form
|
|
648
|
+
// (`shrk "refactor the auth module"`) — which the shell delivers as ONE argv
|
|
649
|
+
// element — is counted by word, exactly like the unquoted multi-token form.
|
|
650
|
+
// Without this, the documented quoted form was a single token (length 1) and
|
|
651
|
+
// fell through to the did-you-mean matcher instead of routing to `recommend`.
|
|
652
|
+
const clean = tokens
|
|
653
|
+
.filter((t) => t.length > 0 && !t.startsWith('-'))
|
|
654
|
+
.flatMap((t) => t.trim().split(/\s+/))
|
|
655
|
+
.filter((w) => w.length > 0);
|
|
648
656
|
if (clean.length < 2)
|
|
649
657
|
return false;
|
|
650
658
|
// 3+ tokens is almost always a sentence, not a command — `shrk` only has
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/surface/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/surface/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,uEAAuE;IACvE,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAmLD,oCAAoC;AACpC,eAAO,MAAM,gBAAgB,EAAE,SAAS,eAAe,EAOrD,CAAC;AAEH,gEAAgE;AAChE,wBAAgB,aAAa,CAC3B,YAAY,GAAE,SAAS,eAAe,EAAO,GAC5C,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAQ9B;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,YAAY,GAAE,SAAS,eAAe,EAAO,GAC5C,eAAe,GAAG,SAAS,CAE7B"}
|
package/dist/surface/profiles.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* Profiles are PURE DATA — no logic, no AI. Adding a profile is just
|
|
11
11
|
* adding an entry here (or in a pack manifest).
|
|
12
12
|
*/
|
|
13
|
+
import { COMMAND_CATALOG } from "../commands/command-catalog.js";
|
|
13
14
|
/**
|
|
14
15
|
* `developer` profile. Default for monorepo / app-with-libs shapes.
|
|
15
16
|
* Hides nothing — pack authors / power users see the full extended
|
|
@@ -108,20 +109,64 @@ const CI_PROFILE = {
|
|
|
108
109
|
],
|
|
109
110
|
};
|
|
110
111
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
112
|
+
* Generic machinery categories that are noise for an inline coding agent:
|
|
113
|
+
* CI / release gates, pack maintenance & signing, bundle replay, provenance,
|
|
114
|
+
* report generation, schema / governance / ingestion / lifecycle / polyglot /
|
|
115
|
+
* integration tooling. Commands stay fully CALLABLE — the agent profile just
|
|
116
|
+
* filters them from the agent-facing listing.
|
|
117
|
+
*/
|
|
118
|
+
const AGENT_HIDDEN_CATEGORIES = new Set([
|
|
119
|
+
'release',
|
|
120
|
+
'ci',
|
|
121
|
+
'bundles',
|
|
122
|
+
'bundle',
|
|
123
|
+
'packs',
|
|
124
|
+
'pack-author',
|
|
125
|
+
'provenance',
|
|
126
|
+
'reports',
|
|
127
|
+
'schemas',
|
|
128
|
+
'governance',
|
|
129
|
+
'ingestion',
|
|
130
|
+
'lifecycle',
|
|
131
|
+
'export',
|
|
132
|
+
'polyglot',
|
|
133
|
+
'integrations',
|
|
134
|
+
]);
|
|
135
|
+
/** Read-only discovery verbs kept visible even though their category is hidden,
|
|
136
|
+
* so an agent can still inspect packs. */
|
|
137
|
+
const AGENT_KEEP_VISIBLE = new Set(['packs list', 'packs doctor']);
|
|
138
|
+
/** Interactive / write-source verbs hidden from the agent surface. */
|
|
139
|
+
const AGENT_INTERACTIVE_HIDDEN = [
|
|
140
|
+
'dev',
|
|
141
|
+
'dev start',
|
|
142
|
+
'dev status',
|
|
143
|
+
'dev report',
|
|
144
|
+
'orchestrate',
|
|
145
|
+
'ask',
|
|
146
|
+
];
|
|
147
|
+
/**
|
|
148
|
+
* Derive the hidden command list from machinery categories MECHANICALLY from the
|
|
149
|
+
* catalogue, so it never drifts as commands are added/removed.
|
|
150
|
+
*/
|
|
151
|
+
function deriveHiddenByCategory(hiddenCats, keep) {
|
|
152
|
+
return COMMAND_CATALOG.filter((e) => hiddenCats.has(e.category) && !keep.has(e.command))
|
|
153
|
+
.map((e) => e.command)
|
|
154
|
+
.sort();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* `agent` profile. Optimized for inline coding-agent / MCP use. Hides
|
|
158
|
+
* interactive verbs AND CI/release/pack-maintenance machinery; favors JSON-pipe
|
|
159
|
+
* read surfaces. Every hidden command remains callable (hide != disable).
|
|
113
160
|
*/
|
|
114
161
|
const AGENT_PROFILE = {
|
|
115
162
|
id: 'agent',
|
|
116
|
-
description: 'Agent / MCP-friendly default. Hides interactive verbs; favors JSON-pipe surfaces.',
|
|
163
|
+
description: 'Agent / MCP-friendly default. Hides interactive verbs + CI/release/pack-maintenance machinery from the listing (commands stay callable); favors JSON-pipe read surfaces.',
|
|
117
164
|
source: 'builtin',
|
|
118
165
|
hidden: [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
'orchestrate',
|
|
124
|
-
'ask',
|
|
166
|
+
...new Set([
|
|
167
|
+
...AGENT_INTERACTIVE_HIDDEN,
|
|
168
|
+
...deriveHiddenByCategory(AGENT_HIDDEN_CATEGORIES, AGENT_KEEP_VISIBLE),
|
|
169
|
+
]),
|
|
125
170
|
],
|
|
126
171
|
};
|
|
127
172
|
/** Catalog of built-in profiles. */
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.20",
|
|
4
4
|
"description": "SharkCraft CLI (`shrk`): structured project intelligence for AI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
|
-
"types": "./dist/index.d.
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
@@ -47,38 +47,38 @@
|
|
|
47
47
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/compress": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/config": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
54
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
55
|
-
"@shrkcrft/context": "^0.1.0-alpha.
|
|
56
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
57
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
58
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
59
|
-
"@shrkcrft/plugin-api": "^0.1.0-alpha.
|
|
60
|
-
"@shrkcrft/dashboard": "^0.1.0-alpha.
|
|
61
|
-
"@shrkcrft/dashboard-api": "^0.1.0-alpha.
|
|
62
|
-
"@shrkcrft/pipelines": "^0.1.0-alpha.
|
|
63
|
-
"@shrkcrft/presets": "^0.1.0-alpha.
|
|
64
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
65
|
-
"@shrkcrft/graph": "^0.1.0-alpha.
|
|
66
|
-
"@shrkcrft/rule-graph": "^0.1.0-alpha.
|
|
67
|
-
"@shrkcrft/structural-search": "^0.1.0-alpha.
|
|
68
|
-
"@shrkcrft/impact-engine": "^0.1.0-alpha.
|
|
69
|
-
"@shrkcrft/context-planner": "^0.1.0-alpha.
|
|
70
|
-
"@shrkcrft/architecture-guard": "^0.1.0-alpha.
|
|
71
|
-
"@shrkcrft/framework-scanners": "^0.1.0-alpha.
|
|
72
|
-
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.
|
|
73
|
-
"@shrkcrft/quality-gates": "^0.1.0-alpha.
|
|
74
|
-
"@shrkcrft/migrate": "^0.1.0-alpha.
|
|
75
|
-
"@shrkcrft/generator": "^0.1.0-alpha.
|
|
76
|
-
"@shrkcrft/importer": "^0.1.0-alpha.
|
|
77
|
-
"@shrkcrft/inspector": "^0.1.0-alpha.
|
|
78
|
-
"@shrkcrft/ai": "^0.1.0-alpha.
|
|
79
|
-
"@shrkcrft/embeddings": "^0.1.0-alpha.
|
|
80
|
-
"@shrkcrft/shared": "^0.1.0-alpha.
|
|
81
|
-
"@shrkcrft/mcp-server": "^0.1.0-alpha.
|
|
50
|
+
"@shrkcrft/core": "^0.1.0-alpha.20",
|
|
51
|
+
"@shrkcrft/compress": "^0.1.0-alpha.20",
|
|
52
|
+
"@shrkcrft/config": "^0.1.0-alpha.20",
|
|
53
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.20",
|
|
54
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.20",
|
|
55
|
+
"@shrkcrft/context": "^0.1.0-alpha.20",
|
|
56
|
+
"@shrkcrft/rules": "^0.1.0-alpha.20",
|
|
57
|
+
"@shrkcrft/paths": "^0.1.0-alpha.20",
|
|
58
|
+
"@shrkcrft/templates": "^0.1.0-alpha.20",
|
|
59
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.20",
|
|
60
|
+
"@shrkcrft/dashboard": "^0.1.0-alpha.20",
|
|
61
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.20",
|
|
62
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.20",
|
|
63
|
+
"@shrkcrft/presets": "^0.1.0-alpha.20",
|
|
64
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.20",
|
|
65
|
+
"@shrkcrft/graph": "^0.1.0-alpha.20",
|
|
66
|
+
"@shrkcrft/rule-graph": "^0.1.0-alpha.20",
|
|
67
|
+
"@shrkcrft/structural-search": "^0.1.0-alpha.20",
|
|
68
|
+
"@shrkcrft/impact-engine": "^0.1.0-alpha.20",
|
|
69
|
+
"@shrkcrft/context-planner": "^0.1.0-alpha.20",
|
|
70
|
+
"@shrkcrft/architecture-guard": "^0.1.0-alpha.20",
|
|
71
|
+
"@shrkcrft/framework-scanners": "^0.1.0-alpha.20",
|
|
72
|
+
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.20",
|
|
73
|
+
"@shrkcrft/quality-gates": "^0.1.0-alpha.20",
|
|
74
|
+
"@shrkcrft/migrate": "^0.1.0-alpha.20",
|
|
75
|
+
"@shrkcrft/generator": "^0.1.0-alpha.20",
|
|
76
|
+
"@shrkcrft/importer": "^0.1.0-alpha.20",
|
|
77
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.20",
|
|
78
|
+
"@shrkcrft/ai": "^0.1.0-alpha.20",
|
|
79
|
+
"@shrkcrft/embeddings": "^0.1.0-alpha.20",
|
|
80
|
+
"@shrkcrft/shared": "^0.1.0-alpha.20",
|
|
81
|
+
"@shrkcrft/mcp-server": "^0.1.0-alpha.20",
|
|
82
82
|
"@huggingface/transformers": "^3.7.5"
|
|
83
83
|
},
|
|
84
84
|
"publishConfig": {
|