@shrkcrft/cli 0.1.0-alpha.23 → 0.1.0-alpha.25
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/changelog-data.d.ts +25 -0
- package/dist/commands/changelog-data.d.ts.map +1 -0
- package/dist/commands/changelog-data.js +70 -0
- package/dist/commands/changelog.command.d.ts +3 -0
- package/dist/commands/changelog.command.d.ts.map +1 -0
- package/dist/commands/changelog.command.js +100 -0
- package/dist/commands/changes.command.d.ts.map +1 -1
- package/dist/commands/changes.command.js +4 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +182 -17
- package/dist/commands/command-catalog.d.ts +11 -0
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +99 -0
- package/dist/commands/compress.command.d.ts.map +1 -1
- package/dist/commands/compress.command.js +15 -1
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +49 -14
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +31 -19
- package/dist/commands/finish.command.d.ts +3 -0
- package/dist/commands/finish.command.d.ts.map +1 -0
- package/dist/commands/finish.command.js +70 -0
- package/dist/commands/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +6 -1
- package/dist/commands/gen.command.d.ts.map +1 -1
- package/dist/commands/gen.command.js +65 -9
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +56 -25
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +20 -2
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +17 -22
- package/dist/commands/policy-lint.command.d.ts.map +1 -1
- package/dist/commands/policy-lint.command.js +46 -8
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +71 -13
- package/dist/commands/reuse.command.d.ts.map +1 -1
- package/dist/commands/reuse.command.js +80 -14
- package/dist/commands/smart-context.command.d.ts.map +1 -1
- package/dist/commands/smart-context.command.js +34 -42
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +33 -16
- package/dist/commands/trace.command.d.ts.map +1 -1
- package/dist/commands/trace.command.js +73 -3
- package/dist/commands/wiring.command.d.ts +12 -0
- package/dist/commands/wiring.command.d.ts.map +1 -0
- package/dist/commands/wiring.command.js +384 -0
- package/dist/diff/collect-changed-paths.d.ts +5 -3
- package/dist/diff/collect-changed-paths.d.ts.map +1 -1
- package/dist/diff/collect-changed-paths.js +73 -36
- package/dist/diff/deleted-orphans.d.ts +42 -0
- package/dist/diff/deleted-orphans.d.ts.map +1 -0
- package/dist/diff/deleted-orphans.js +46 -0
- package/dist/finish/run-finish.d.ts +62 -0
- package/dist/finish/run-finish.d.ts.map +1 -0
- package/dist/finish/run-finish.js +239 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -0
- package/dist/validation/typecheck-emitted.d.ts +36 -0
- package/dist/validation/typecheck-emitted.d.ts.map +1 -0
- package/dist/validation/typecheck-emitted.js +109 -0
- package/package.json +33 -33
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type IChangedScopeOptions } from '@shrkcrft/inspector';
|
|
2
|
+
export declare const FINISH_SCHEMA: "sharkcraft.finish/v1";
|
|
3
|
+
/** Outcome of one sub-gate. `skipped` = nothing to evaluate (loud, never silent green). */
|
|
4
|
+
export type FinishGateStatus = 'pass' | 'fail' | 'skipped';
|
|
5
|
+
/** One failing/relevant item, with file:line where the engine provides it. */
|
|
6
|
+
export interface IFinishItem {
|
|
7
|
+
readonly file?: string;
|
|
8
|
+
readonly line?: number;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
}
|
|
11
|
+
export interface IFinishGate {
|
|
12
|
+
readonly name: 'boundaries' | 'imports' | 'wiring' | 'policy' | 'orphans';
|
|
13
|
+
readonly status: FinishGateStatus;
|
|
14
|
+
/** One-line reason (e.g. why skipped, or the error/warning counts). */
|
|
15
|
+
readonly detail: string;
|
|
16
|
+
readonly errors: number;
|
|
17
|
+
readonly warnings: number;
|
|
18
|
+
/** Failing/notable items (capped by the renderer, full in JSON). */
|
|
19
|
+
readonly items: readonly IFinishItem[];
|
|
20
|
+
}
|
|
21
|
+
export interface IFinishImpact {
|
|
22
|
+
readonly ran: boolean;
|
|
23
|
+
readonly risk?: string;
|
|
24
|
+
readonly directDependents?: number;
|
|
25
|
+
readonly transitiveDependents?: number;
|
|
26
|
+
/** Why the summary could not run (no graph index / no changed files). */
|
|
27
|
+
readonly note?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface IFinishReport {
|
|
30
|
+
readonly schema: typeof FINISH_SCHEMA;
|
|
31
|
+
readonly scope: {
|
|
32
|
+
readonly mode: 'worktree' | 'staged' | 'since' | 'files';
|
|
33
|
+
readonly files: readonly string[];
|
|
34
|
+
readonly fileCount: number;
|
|
35
|
+
};
|
|
36
|
+
readonly gates: readonly IFinishGate[];
|
|
37
|
+
readonly impact: IFinishImpact;
|
|
38
|
+
/** `fail` iff any gate failed OR the config could not load; else `pass`. */
|
|
39
|
+
readonly verdict: 'pass' | 'fail';
|
|
40
|
+
/** Total warning-severity findings across gates (non-blocking). */
|
|
41
|
+
readonly warnings: number;
|
|
42
|
+
/** Set when sharkcraft.config.ts could not be loaded — forces a `fail`. */
|
|
43
|
+
readonly configError?: string;
|
|
44
|
+
readonly summary: string;
|
|
45
|
+
readonly nextAction: string;
|
|
46
|
+
}
|
|
47
|
+
export interface IRunFinishInput {
|
|
48
|
+
readonly cwd: string;
|
|
49
|
+
readonly mode: 'worktree' | 'staged' | 'since' | 'files';
|
|
50
|
+
readonly scope: IChangedScopeOptions;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The composite "is this changeset safe to finish?" orchestrator. Runs every
|
|
54
|
+
* deterministic CHANGED-ONLY gate inline — boundaries + import-hygiene + wiring
|
|
55
|
+
* + policy + deleted-orphans — plus a best-effort impact summary, and folds
|
|
56
|
+
* them into ONE pass/fail. This is the single trustworthy "done?" call an
|
|
57
|
+
* autonomous agent needs and can't reliably assemble by hand (only shrk can run
|
|
58
|
+
* the alias-resolved layer/wiring gates). Honors the `0-rules → skipped`
|
|
59
|
+
* semantics so a no-op sub-check is reported, never silently passed. Read-only.
|
|
60
|
+
*/
|
|
61
|
+
export declare function runFinishGates(input: IRunFinishInput): Promise<IFinishReport>;
|
|
62
|
+
//# sourceMappingURL=run-finish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-finish.d.ts","sourceRoot":"","sources":["../../src/finish/run-finish.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAa7B,eAAO,MAAM,aAAa,EAAG,sBAA+B,CAAC;AAE7D,2FAA2F;AAC3F,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3D,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1E,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,aAAa,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;QACzD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;QAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;IACzD,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;CACtC;AAYD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,CAkHnF"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { buildImportHygieneReport, filterViolationsToChangedScope, inspectSharkcraft, resolveChangedFiles, resolveProjectConfig, } from '@shrkcrft/inspector';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import * as nodePath from 'node:path';
|
|
4
|
+
import { evaluateBoundaries, loadTsconfigPaths, runPolicyLint, runWiring, scanImports, } from '@shrkcrft/boundaries';
|
|
5
|
+
import { computeDeletedOrphans } from "../diff/deleted-orphans.js";
|
|
6
|
+
export const FINISH_SCHEMA = 'sharkcraft.finish/v1';
|
|
7
|
+
/** Map the changed-scope onto the orphan check's diff inputs. */
|
|
8
|
+
function orphanOptsFor(input) {
|
|
9
|
+
if (input.mode === 'files')
|
|
10
|
+
return undefined; // a file list has no diff to read deletions from
|
|
11
|
+
if (input.mode === 'staged')
|
|
12
|
+
return { staged: true };
|
|
13
|
+
if (input.mode === 'since' && input.scope.since)
|
|
14
|
+
return { since: input.scope.since };
|
|
15
|
+
// Worktree mode: diff deletions vs HEAD so the orphan gate's "deleted" set
|
|
16
|
+
// matches the working-tree scope the other gates use (not the whole branch).
|
|
17
|
+
return { since: 'HEAD' };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The composite "is this changeset safe to finish?" orchestrator. Runs every
|
|
21
|
+
* deterministic CHANGED-ONLY gate inline — boundaries + import-hygiene + wiring
|
|
22
|
+
* + policy + deleted-orphans — plus a best-effort impact summary, and folds
|
|
23
|
+
* them into ONE pass/fail. This is the single trustworthy "done?" call an
|
|
24
|
+
* autonomous agent needs and can't reliably assemble by hand (only shrk can run
|
|
25
|
+
* the alias-resolved layer/wiring gates). Honors the `0-rules → skipped`
|
|
26
|
+
* semantics so a no-op sub-check is reported, never silently passed. Read-only.
|
|
27
|
+
*/
|
|
28
|
+
export async function runFinishGates(input) {
|
|
29
|
+
const { cwd } = input;
|
|
30
|
+
const changed = resolveChangedFiles(input.scope);
|
|
31
|
+
const changedFiles = changed.files;
|
|
32
|
+
const gates = [];
|
|
33
|
+
// ── boundaries (changed-only) ────────────────────────────────────────
|
|
34
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
35
|
+
const boundaryRules = inspection.boundaryRegistry.list();
|
|
36
|
+
if (boundaryRules.length === 0) {
|
|
37
|
+
gates.push(skip('boundaries', 'no boundary rules configured'));
|
|
38
|
+
}
|
|
39
|
+
else if (changedFiles.length === 0) {
|
|
40
|
+
gates.push(skip('boundaries', 'no files in changed scope'));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const scan = scanImports({ projectRoot: cwd });
|
|
44
|
+
const tsconfigPaths = loadTsconfigPaths(cwd);
|
|
45
|
+
const evalResult = evaluateBoundaries(scan, boundaryRules, {
|
|
46
|
+
...(tsconfigPaths.aliases.size > 0 ? { tsconfigPaths } : {}),
|
|
47
|
+
});
|
|
48
|
+
const filtered = filterViolationsToChangedScope(evalResult.violations, input.scope);
|
|
49
|
+
const errors = filtered.includedViolations.filter((v) => v.severity === 'error');
|
|
50
|
+
const warnings = filtered.includedViolations.filter((v) => v.severity === 'warning');
|
|
51
|
+
gates.push({
|
|
52
|
+
name: 'boundaries',
|
|
53
|
+
status: errors.length > 0 ? 'fail' : 'pass',
|
|
54
|
+
detail: `${errors.length} error(s), ${warnings.length} warning(s) across ${changedFiles.length} changed file(s)`,
|
|
55
|
+
errors: errors.length,
|
|
56
|
+
warnings: warnings.length,
|
|
57
|
+
items: [...errors, ...warnings].map((v) => ({
|
|
58
|
+
file: v.file,
|
|
59
|
+
line: v.line,
|
|
60
|
+
message: `[${v.severity}] ${v.ruleId}: ${v.message}`,
|
|
61
|
+
})),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// ── import hygiene (changed-only) ────────────────────────────────────
|
|
65
|
+
if (changedFiles.length === 0) {
|
|
66
|
+
gates.push(skip('imports', 'no files in changed scope'));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const report = buildImportHygieneReport(cwd, { files: changedFiles });
|
|
70
|
+
const errors = report.counts?.['error'] ?? (report.verdict === 'errors' ? report.findings.length : 0);
|
|
71
|
+
const warnings = report.counts?.['warning'] ?? (report.verdict === 'warnings' ? report.findings.length : 0);
|
|
72
|
+
gates.push({
|
|
73
|
+
name: 'imports',
|
|
74
|
+
status: report.verdict === 'errors' ? 'fail' : 'pass',
|
|
75
|
+
detail: `verdict=${report.verdict} (${report.findings.length} finding(s))`,
|
|
76
|
+
errors,
|
|
77
|
+
warnings,
|
|
78
|
+
items: report.findings.map((f) => ({
|
|
79
|
+
file: f.file,
|
|
80
|
+
line: f.line,
|
|
81
|
+
message: `${f.kind}: ${f.suggestedFix || f.reason || f.snippet}`.trim(),
|
|
82
|
+
})),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// ── wiring + policy (changed-only, from resolved config) ─────────────
|
|
86
|
+
const loaded = await resolveProjectConfig(cwd);
|
|
87
|
+
let configError;
|
|
88
|
+
if (!loaded.ok) {
|
|
89
|
+
// A MALFORMED config in a real sharkcraft project is a fail (the wiring/
|
|
90
|
+
// policy gates can't be trusted). The mere ABSENCE of a sharkcraft/ folder
|
|
91
|
+
// is not — those gates simply don't apply, so skip them without failing.
|
|
92
|
+
const isSharkcraftProject = existsSync(nodePath.join(cwd, 'sharkcraft'));
|
|
93
|
+
if (isSharkcraftProject)
|
|
94
|
+
configError = loaded.error.message;
|
|
95
|
+
const detail = isSharkcraftProject
|
|
96
|
+
? `config did not load: ${loaded.error.message}`
|
|
97
|
+
: 'no sharkcraft config (gate not applicable)';
|
|
98
|
+
gates.push(skip('wiring', detail));
|
|
99
|
+
gates.push(skip('policy', detail));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
gates.push(wiringGate(cwd, loaded.value.config.wiringRules ?? [], changedFiles), policyGate(cwd, loaded.value.config.policyRules ?? [], changedFiles));
|
|
103
|
+
}
|
|
104
|
+
// ── deleted-orphans (write-safety) ───────────────────────────────────
|
|
105
|
+
gates.push(await orphansGate(input));
|
|
106
|
+
// ── impact summary (informational, best-effort) ──────────────────────
|
|
107
|
+
const impact = await impactSummary(cwd, changedFiles);
|
|
108
|
+
// ── fold into one verdict ────────────────────────────────────────────
|
|
109
|
+
const failed = gates.filter((g) => g.status === 'fail');
|
|
110
|
+
const warnings = gates.reduce((n, g) => n + g.warnings, 0);
|
|
111
|
+
const verdict = failed.length > 0 || configError ? 'fail' : 'pass';
|
|
112
|
+
const skipped = gates.filter((g) => g.status === 'skipped').map((g) => g.name);
|
|
113
|
+
const summary = verdict === 'fail'
|
|
114
|
+
? `Not safe to finish: ${configError ? 'config failed to load; ' : ''}${failed.map((g) => `${g.name} (${g.errors} error(s))`).join(', ') || 'see gates'}.`
|
|
115
|
+
: changedFiles.length === 0 && input.mode !== 'files'
|
|
116
|
+
? 'No files in the changed scope — nothing to gate.'
|
|
117
|
+
: `Safe to finish: every applicable gate passed${warnings > 0 ? ` (${warnings} non-blocking warning(s))` : ''}${skipped.length > 0 ? `; skipped: ${skipped.join(', ')}` : ''}.`;
|
|
118
|
+
const nextAction = verdict === 'fail'
|
|
119
|
+
? 'Fix every failing gate item (each carries file:line), then re-run `shrk finish`.'
|
|
120
|
+
: 'Safe to declare done.';
|
|
121
|
+
return {
|
|
122
|
+
schema: FINISH_SCHEMA,
|
|
123
|
+
scope: { mode: input.mode, files: changedFiles, fileCount: changedFiles.length },
|
|
124
|
+
gates,
|
|
125
|
+
impact,
|
|
126
|
+
verdict,
|
|
127
|
+
warnings,
|
|
128
|
+
...(configError ? { configError } : {}),
|
|
129
|
+
summary,
|
|
130
|
+
nextAction,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function skip(name, detail) {
|
|
134
|
+
return { name, status: 'skipped', detail, errors: 0, warnings: 0, items: [] };
|
|
135
|
+
}
|
|
136
|
+
function wiringGate(cwd, rules, changedFiles) {
|
|
137
|
+
if (rules.length === 0)
|
|
138
|
+
return skip('wiring', 'no wiring rules configured');
|
|
139
|
+
const report = runWiring(cwd, rules, { changedOnly: true, changedFiles });
|
|
140
|
+
if (report.evaluated === 0) {
|
|
141
|
+
return skip('wiring', `${report.rules.length} rule(s) configured but none matched the changed scope`);
|
|
142
|
+
}
|
|
143
|
+
const errors = report.violations.filter((v) => v.severity === 'error');
|
|
144
|
+
const warnings = report.violations.filter((v) => v.severity === 'warning');
|
|
145
|
+
// A misconfigured rule (bad regex / no capture group) yields a diagnostic +
|
|
146
|
+
// rule-level error but NO violation — it must FAIL the gate, never read as a
|
|
147
|
+
// silent green ("loud, never silent green").
|
|
148
|
+
const diag = report.diagnostics;
|
|
149
|
+
return {
|
|
150
|
+
name: 'wiring',
|
|
151
|
+
status: report.verdict === 'errors' || diag.length > 0 ? 'fail' : 'pass',
|
|
152
|
+
detail: `${report.evaluated}/${report.rules.length} rule(s) evaluated — ${errors.length} error(s), ${warnings.length} warning(s)${diag.length > 0 ? `, ${diag.length} misconfigured` : ''}`,
|
|
153
|
+
errors: errors.length + diag.length,
|
|
154
|
+
warnings: warnings.length,
|
|
155
|
+
items: [
|
|
156
|
+
...report.violations.map((v) => ({
|
|
157
|
+
file: v.file,
|
|
158
|
+
line: v.line,
|
|
159
|
+
message: `[${v.severity}] ${v.ruleId}: "${v.token}" ${v.direction === 'registered-missing' ? 'registered but not declared' : 'declared but not registered'}`,
|
|
160
|
+
})),
|
|
161
|
+
...diag.map((d) => ({ message: `misconfigured rule: ${d}` })),
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function policyGate(cwd, rules, changedFiles) {
|
|
166
|
+
if (rules.length === 0)
|
|
167
|
+
return skip('policy', 'no policy rules configured');
|
|
168
|
+
const report = runPolicyLint(cwd, rules, { changedOnly: true, changedFiles });
|
|
169
|
+
if (report.evaluated === 0) {
|
|
170
|
+
return skip('policy', `${report.rules.length} rule(s) configured but none matched the changed scope`);
|
|
171
|
+
}
|
|
172
|
+
const errors = report.findings.filter((f) => f.severity === 'error');
|
|
173
|
+
const warnings = report.findings.filter((f) => f.severity === 'warning');
|
|
174
|
+
const diag = report.diagnostics;
|
|
175
|
+
return {
|
|
176
|
+
name: 'policy',
|
|
177
|
+
status: report.verdict === 'errors' || diag.length > 0 ? 'fail' : 'pass',
|
|
178
|
+
detail: `${report.evaluated}/${report.rules.length} rule(s) evaluated — ${errors.length} error(s), ${warnings.length} warning(s)${diag.length > 0 ? `, ${diag.length} misconfigured` : ''}`,
|
|
179
|
+
errors: errors.length + diag.length,
|
|
180
|
+
warnings: warnings.length,
|
|
181
|
+
items: [
|
|
182
|
+
...report.findings.map((f) => ({
|
|
183
|
+
file: f.file,
|
|
184
|
+
line: f.line,
|
|
185
|
+
message: `[${f.severity}] ${f.ruleId}: ${f.message ?? ''}`.trim(),
|
|
186
|
+
})),
|
|
187
|
+
...diag.map((d) => ({ message: `misconfigured rule: ${d}` })),
|
|
188
|
+
],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async function orphansGate(input) {
|
|
192
|
+
const opts = orphanOptsFor(input);
|
|
193
|
+
if (!opts)
|
|
194
|
+
return skip('orphans', 'explicit --files scope has no diff to read deletions from');
|
|
195
|
+
const scan = await computeDeletedOrphans(input.cwd, opts);
|
|
196
|
+
if (!scan.ok) {
|
|
197
|
+
return skip('orphans', scan.reason === 'graph-missing'
|
|
198
|
+
? 'code-graph index missing — run `shrk graph index` to enable the orphan check'
|
|
199
|
+
: `diff unavailable: ${scan.error ?? 'unknown'}`);
|
|
200
|
+
}
|
|
201
|
+
if (scan.deleted.length === 0)
|
|
202
|
+
return skip('orphans', `nothing deleted (vs ${scan.ref})`);
|
|
203
|
+
const orphans = scan.report?.orphans ?? [];
|
|
204
|
+
return {
|
|
205
|
+
name: 'orphans',
|
|
206
|
+
status: orphans.length > 0 ? 'fail' : 'pass',
|
|
207
|
+
detail: `${scan.deleted.length} deleted file(s) (vs ${scan.ref}) — ${orphans.length} surviving importer(s)`,
|
|
208
|
+
errors: orphans.length,
|
|
209
|
+
warnings: 0,
|
|
210
|
+
items: orphans.map((o) => ({
|
|
211
|
+
file: o.path ?? o.id,
|
|
212
|
+
...(typeof o.line === 'number' ? { line: o.line } : {}),
|
|
213
|
+
message: o.via === 'reference' && o.symbol
|
|
214
|
+
? `references \`${o.symbol}\` from deleted ${o.deletedFile}`
|
|
215
|
+
: `imports deleted ${o.deletedFile}`,
|
|
216
|
+
})),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
async function impactSummary(cwd, changedFiles) {
|
|
220
|
+
if (changedFiles.length === 0)
|
|
221
|
+
return { ran: false, note: 'no changed files' };
|
|
222
|
+
try {
|
|
223
|
+
const { GraphStore } = await import('@shrkcrft/graph');
|
|
224
|
+
if (!new GraphStore(cwd).exists()) {
|
|
225
|
+
return { ran: false, note: 'code-graph index missing — run `shrk graph index`' };
|
|
226
|
+
}
|
|
227
|
+
const { analyzeGraphImpact } = await import('@shrkcrft/impact-engine');
|
|
228
|
+
const analysis = analyzeGraphImpact({ kind: 'files', files: [...changedFiles] }, { projectRoot: cwd, maxDepth: 5, limit: 200 });
|
|
229
|
+
return {
|
|
230
|
+
ran: true,
|
|
231
|
+
risk: analysis.risk,
|
|
232
|
+
directDependents: analysis.directDependents.length,
|
|
233
|
+
transitiveDependents: analysis.transitiveDependents.length,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
catch (e) {
|
|
237
|
+
return { ran: false, note: `impact summary unavailable: ${e instanceof Error ? e.message : String(e)}` };
|
|
238
|
+
}
|
|
239
|
+
}
|
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;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AA6X/B,wBAAgB,aAAa,IAAI,eAAe,CAiY/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;AAqID;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAoDxE"}
|
package/dist/main.js
CHANGED
|
@@ -22,6 +22,7 @@ import { presetsListCommand, presetsGetCommand, presetsExplainCommand, presetsRe
|
|
|
22
22
|
import { taskCommand } from "./commands/task.command.js";
|
|
23
23
|
import { preflightCommand } from "./commands/preflight.command.js";
|
|
24
24
|
import { checkCommand } from "./commands/check.command.js";
|
|
25
|
+
import { finishCommand } from "./commands/finish.command.js";
|
|
25
26
|
import { diffCheckCommand } from "./commands/diff-check.command.js";
|
|
26
27
|
import { driftCommand } from "./commands/drift.command.js";
|
|
27
28
|
import { graphCommand } from "./commands/graph.command.js";
|
|
@@ -33,6 +34,7 @@ import { frameworkCommand } from "./commands/framework.command.js";
|
|
|
33
34
|
import { apiDiffCommand } from "./commands/api-diff.command.js";
|
|
34
35
|
import { gateCommand } from "./commands/gate.command.js";
|
|
35
36
|
import { policyLintCommand } from "./commands/policy-lint.command.js";
|
|
37
|
+
import { wiringCommand } from "./commands/wiring.command.js";
|
|
36
38
|
import { reuseCommand } from "./commands/reuse.command.js";
|
|
37
39
|
import { migrateCommand } from "./commands/migrate.command.js";
|
|
38
40
|
import { coverageCommand } from "./commands/coverage.command.js";
|
|
@@ -71,6 +73,7 @@ import { movePlanCommand } from "./commands/move-plan.command.js";
|
|
|
71
73
|
import { watchCommand, watchListCommand, watchPruneCommand, watchStopCommand } from "./commands/watch.command.js";
|
|
72
74
|
import { mcpCommand } from "./commands/mcp.command.js";
|
|
73
75
|
import { versionCommand } from "./commands/version.command.js";
|
|
76
|
+
import { changelogCommand } from "./commands/changelog.command.js";
|
|
74
77
|
import { makeHelpCommand } from "./commands/help.command.js";
|
|
75
78
|
import { qualityCommand } from "./commands/quality.command.js";
|
|
76
79
|
import { ciCommand } from "./commands/ci.command.js";
|
|
@@ -189,6 +192,7 @@ export function buildRegistry() {
|
|
|
189
192
|
registry.register(explainCommand);
|
|
190
193
|
registry.register(checkCommand);
|
|
191
194
|
registry.register(diffCheckCommand);
|
|
195
|
+
registry.register(finishCommand);
|
|
192
196
|
// changed-only preflight orchestrator.
|
|
193
197
|
registry.register(preflightCommand);
|
|
194
198
|
registry.register(driftCommand);
|
|
@@ -201,6 +205,7 @@ export function buildRegistry() {
|
|
|
201
205
|
registry.register(apiDiffCommand);
|
|
202
206
|
registry.register(gateCommand);
|
|
203
207
|
registry.register(policyLintCommand);
|
|
208
|
+
registry.register(wiringCommand);
|
|
204
209
|
registry.register(reuseCommand);
|
|
205
210
|
registry.register(migrateCommand);
|
|
206
211
|
registry.register(coverageCommand);
|
|
@@ -245,6 +250,7 @@ export function buildRegistry() {
|
|
|
245
250
|
registry.registerSubcommand('watch', watchPruneCommand);
|
|
246
251
|
registry.register(mcpCommand);
|
|
247
252
|
registry.register(versionCommand);
|
|
253
|
+
registry.register(changelogCommand);
|
|
248
254
|
registry.register(qualityCommand);
|
|
249
255
|
registry.register(ciCommand);
|
|
250
256
|
registry.register(eslintCommand);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** A file the generator would emit, with its rendered (in-memory) contents. */
|
|
2
|
+
export interface IEmittedFile {
|
|
3
|
+
/** Absolute path the file would land at. */
|
|
4
|
+
absPath: string;
|
|
5
|
+
/** Rendered body (never written to disk by the typecheck). */
|
|
6
|
+
contents: string;
|
|
7
|
+
}
|
|
8
|
+
/** A single typecheck error located in an emitted file. */
|
|
9
|
+
export interface IEmittedTypecheckError {
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
column: number;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface IEmittedTypecheckResult {
|
|
16
|
+
/** False when there were no TS/TSX files to check (e.g. a docs-only template). */
|
|
17
|
+
ran: boolean;
|
|
18
|
+
errors: readonly IEmittedTypecheckError[];
|
|
19
|
+
/** Human note (why it didn't run, or which tsconfig it used). */
|
|
20
|
+
note?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Typecheck a set of EMITTED (not-yet-written) files against the project's
|
|
24
|
+
* detected tsconfig, without touching disk. Builds a `ts.Program` whose root
|
|
25
|
+
* names are the emitted files, over a compiler host that overlays the rendered
|
|
26
|
+
* bodies for those paths and reads everything else (imports, lib) from disk — so
|
|
27
|
+
* a scaffold that references a real project symbol resolves, and a template bug
|
|
28
|
+
* (bad syntax, a dangling import, a type mismatch) surfaces BEFORE apply instead
|
|
29
|
+
* of at the human's next build.
|
|
30
|
+
*
|
|
31
|
+
* Only diagnostics located IN the emitted files are reported; pre-existing
|
|
32
|
+
* errors elsewhere in the project are ignored (this is a generation gate, not a
|
|
33
|
+
* whole-repo typecheck).
|
|
34
|
+
*/
|
|
35
|
+
export declare function typecheckEmittedFiles(projectRoot: string, files: readonly IEmittedFile[]): IEmittedTypecheckResult;
|
|
36
|
+
//# sourceMappingURL=typecheck-emitted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typecheck-emitted.d.ts","sourceRoot":"","sources":["../../src/validation/typecheck-emitted.ts"],"names":[],"mappings":"AAIA,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,2DAA2D;AAC3D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAC1C,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,YAAY,EAAE,GAC7B,uBAAuB,CAmFzB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
const TSCONFIG_NAMES = ['tsconfig.json', 'tsconfig.base.json'];
|
|
5
|
+
function findTsconfig(projectRoot) {
|
|
6
|
+
for (const name of TSCONFIG_NAMES) {
|
|
7
|
+
const p = resolve(projectRoot, name);
|
|
8
|
+
if (existsSync(p))
|
|
9
|
+
return p;
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Typecheck a set of EMITTED (not-yet-written) files against the project's
|
|
15
|
+
* detected tsconfig, without touching disk. Builds a `ts.Program` whose root
|
|
16
|
+
* names are the emitted files, over a compiler host that overlays the rendered
|
|
17
|
+
* bodies for those paths and reads everything else (imports, lib) from disk — so
|
|
18
|
+
* a scaffold that references a real project symbol resolves, and a template bug
|
|
19
|
+
* (bad syntax, a dangling import, a type mismatch) surfaces BEFORE apply instead
|
|
20
|
+
* of at the human's next build.
|
|
21
|
+
*
|
|
22
|
+
* Only diagnostics located IN the emitted files are reported; pre-existing
|
|
23
|
+
* errors elsewhere in the project are ignored (this is a generation gate, not a
|
|
24
|
+
* whole-repo typecheck).
|
|
25
|
+
*/
|
|
26
|
+
export function typecheckEmittedFiles(projectRoot, files) {
|
|
27
|
+
const tsFiles = files.filter((f) => /\.tsx?$/.test(f.absPath));
|
|
28
|
+
if (tsFiles.length === 0) {
|
|
29
|
+
return { ran: false, errors: [], note: 'no TS/TSX files in the emit set' };
|
|
30
|
+
}
|
|
31
|
+
let options = {
|
|
32
|
+
target: ts.ScriptTarget.ES2022,
|
|
33
|
+
module: ts.ModuleKind.ESNext,
|
|
34
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
35
|
+
strict: true,
|
|
36
|
+
esModuleInterop: true,
|
|
37
|
+
};
|
|
38
|
+
const tsconfigPath = findTsconfig(projectRoot);
|
|
39
|
+
if (tsconfigPath) {
|
|
40
|
+
const read = ts.readConfigFile(tsconfigPath, (p) => {
|
|
41
|
+
try {
|
|
42
|
+
return readFileSync(p, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (!read.error) {
|
|
49
|
+
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, dirname(tsconfigPath));
|
|
50
|
+
options = parsed.options;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Force a non-emitting, lib-skipping check regardless of the project's config.
|
|
54
|
+
options.noEmit = true;
|
|
55
|
+
options.skipLibCheck = true;
|
|
56
|
+
options.incremental = false;
|
|
57
|
+
delete options.composite;
|
|
58
|
+
delete options.outDir;
|
|
59
|
+
delete options.declaration;
|
|
60
|
+
const overlay = new Map(tsFiles.map((f) => [resolve(f.absPath), f.contents]));
|
|
61
|
+
const host = ts.createCompilerHost(options, true);
|
|
62
|
+
const origGetSourceFile = host.getSourceFile.bind(host);
|
|
63
|
+
const origReadFile = host.readFile.bind(host);
|
|
64
|
+
const origFileExists = host.fileExists.bind(host);
|
|
65
|
+
host.readFile = (fileName) => {
|
|
66
|
+
const k = resolve(fileName);
|
|
67
|
+
return overlay.has(k) ? overlay.get(k) : origReadFile(fileName);
|
|
68
|
+
};
|
|
69
|
+
host.fileExists = (fileName) => overlay.has(resolve(fileName)) || origFileExists(fileName);
|
|
70
|
+
host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreate) => {
|
|
71
|
+
const k = resolve(fileName);
|
|
72
|
+
const body = overlay.get(k);
|
|
73
|
+
if (body !== undefined) {
|
|
74
|
+
return ts.createSourceFile(fileName, body, languageVersionOrOptions, true);
|
|
75
|
+
}
|
|
76
|
+
return origGetSourceFile(fileName, languageVersionOrOptions, onError, shouldCreate);
|
|
77
|
+
};
|
|
78
|
+
const rootNames = tsFiles.map((f) => resolve(f.absPath));
|
|
79
|
+
const program = ts.createProgram({ rootNames, options, host });
|
|
80
|
+
const errors = [];
|
|
81
|
+
for (const rn of rootNames) {
|
|
82
|
+
const sf = program.getSourceFile(rn);
|
|
83
|
+
if (!sf)
|
|
84
|
+
continue;
|
|
85
|
+
const diags = [...program.getSyntacticDiagnostics(sf), ...program.getSemanticDiagnostics(sf)];
|
|
86
|
+
for (const d of diags) {
|
|
87
|
+
if (d.category !== ts.DiagnosticCategory.Error)
|
|
88
|
+
continue;
|
|
89
|
+
let line = 0;
|
|
90
|
+
let column = 0;
|
|
91
|
+
if (d.file && typeof d.start === 'number') {
|
|
92
|
+
const lc = d.file.getLineAndCharacterOfPosition(d.start);
|
|
93
|
+
line = lc.line + 1;
|
|
94
|
+
column = lc.character + 1;
|
|
95
|
+
}
|
|
96
|
+
errors.push({
|
|
97
|
+
file: resolve(d.file?.fileName ?? rn),
|
|
98
|
+
line,
|
|
99
|
+
column,
|
|
100
|
+
message: ts.flattenDiagnosticMessageText(d.messageText, '\n'),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
ran: true,
|
|
106
|
+
errors,
|
|
107
|
+
...(tsconfigPath ? { note: `checked against ${tsconfigPath}` } : { note: 'no tsconfig found — used defaults' }),
|
|
108
|
+
};
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.25",
|
|
4
4
|
"description": "SharkCraft CLI (`shrk`): structured project intelligence for AI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -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.25",
|
|
51
|
+
"@shrkcrft/compress": "^0.1.0-alpha.25",
|
|
52
|
+
"@shrkcrft/config": "^0.1.0-alpha.25",
|
|
53
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.25",
|
|
54
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.25",
|
|
55
|
+
"@shrkcrft/context": "^0.1.0-alpha.25",
|
|
56
|
+
"@shrkcrft/rules": "^0.1.0-alpha.25",
|
|
57
|
+
"@shrkcrft/paths": "^0.1.0-alpha.25",
|
|
58
|
+
"@shrkcrft/templates": "^0.1.0-alpha.25",
|
|
59
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.25",
|
|
60
|
+
"@shrkcrft/dashboard": "^0.1.0-alpha.25",
|
|
61
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.25",
|
|
62
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.25",
|
|
63
|
+
"@shrkcrft/presets": "^0.1.0-alpha.25",
|
|
64
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.25",
|
|
65
|
+
"@shrkcrft/graph": "^0.1.0-alpha.25",
|
|
66
|
+
"@shrkcrft/rule-graph": "^0.1.0-alpha.25",
|
|
67
|
+
"@shrkcrft/structural-search": "^0.1.0-alpha.25",
|
|
68
|
+
"@shrkcrft/impact-engine": "^0.1.0-alpha.25",
|
|
69
|
+
"@shrkcrft/context-planner": "^0.1.0-alpha.25",
|
|
70
|
+
"@shrkcrft/architecture-guard": "^0.1.0-alpha.25",
|
|
71
|
+
"@shrkcrft/framework-scanners": "^0.1.0-alpha.25",
|
|
72
|
+
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.25",
|
|
73
|
+
"@shrkcrft/quality-gates": "^0.1.0-alpha.25",
|
|
74
|
+
"@shrkcrft/migrate": "^0.1.0-alpha.25",
|
|
75
|
+
"@shrkcrft/generator": "^0.1.0-alpha.25",
|
|
76
|
+
"@shrkcrft/importer": "^0.1.0-alpha.25",
|
|
77
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.25",
|
|
78
|
+
"@shrkcrft/ai": "^0.1.0-alpha.25",
|
|
79
|
+
"@shrkcrft/embeddings": "^0.1.0-alpha.25",
|
|
80
|
+
"@shrkcrft/shared": "^0.1.0-alpha.25",
|
|
81
|
+
"@shrkcrft/mcp-server": "^0.1.0-alpha.25",
|
|
82
82
|
"@huggingface/transformers": "^3.7.5"
|
|
83
83
|
},
|
|
84
84
|
"publishConfig": {
|