@shrkcrft/cli 0.1.0-alpha.24 → 0.1.0-alpha.26
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/command-registry.d.ts +10 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +16 -0
- 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 +94 -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 +134 -19
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +8 -0
- package/dist/commands/compress.command.d.ts.map +1 -1
- package/dist/commands/compress.command.js +46 -2
- 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/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +63 -3
- 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 +14 -2
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +68 -1
- package/dist/commands/policy-lint.command.d.ts.map +1 -1
- package/dist/commands/policy-lint.command.js +46 -8
- package/dist/commands/registry-resolve.d.ts +41 -0
- package/dist/commands/registry-resolve.d.ts.map +1 -0
- package/dist/commands/registry-resolve.js +89 -0
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +86 -13
- package/dist/commands/reuse.command.d.ts +20 -0
- package/dist/commands/reuse.command.d.ts.map +1 -1
- package/dist/commands/reuse.command.js +156 -20
- package/dist/commands/smart-context.command.d.ts.map +1 -1
- package/dist/commands/smart-context.command.js +20 -5
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +33 -16
- package/dist/exit-codes.d.ts +49 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +61 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +26 -1
- 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
|
@@ -20,33 +20,87 @@ function tokenize(s) {
|
|
|
20
20
|
function scorePrimitive(p, tokens) {
|
|
21
21
|
// Substring match (so intent "debounce" matches symbol `useDebounce`); the
|
|
22
22
|
// 3-char minimum above keeps it from over-matching on tiny fragments.
|
|
23
|
+
const symbolLower = p.symbol.toLowerCase();
|
|
23
24
|
const hay = [p.symbol, ...(p.roles ?? []), ...(p.keywords ?? []), p.description ?? '']
|
|
24
25
|
.join(' ')
|
|
25
26
|
.toLowerCase();
|
|
26
27
|
let s = 0;
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
const matched = [];
|
|
29
|
+
let symbolHit = false;
|
|
30
|
+
for (const t of tokens) {
|
|
31
|
+
if (hay.includes(t)) {
|
|
29
32
|
s += 1;
|
|
33
|
+
matched.push(t);
|
|
34
|
+
if (symbolLower.includes(t))
|
|
35
|
+
symbolHit = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
30
38
|
// A role the intent mentions is a strong signal; re-weight role hits.
|
|
31
39
|
for (const role of p.roles ?? []) {
|
|
32
40
|
const rl = role.toLowerCase();
|
|
33
41
|
if (rl.length >= 3 && tokens.some((t) => rl.includes(t)))
|
|
34
42
|
s += 0.5;
|
|
35
43
|
}
|
|
36
|
-
return s;
|
|
44
|
+
return { score: s, matched, symbolHit };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Confidence floor: a keyword collision is not a match. A hit is only "confident"
|
|
48
|
+
* when it matched the symbol name itself, OR matched ≥2 distinct query tokens, OR
|
|
49
|
+
* the query was a single token and that token hit. A single generic keyword hit on
|
|
50
|
+
* a multi-token intent (the "nearest collision on an unrelated entry" failure mode)
|
|
51
|
+
* is a weak match — surfaced as a did-you-mean, never as a confident answer.
|
|
52
|
+
*/
|
|
53
|
+
function isConfidentMatch(detail, queryTokenCount) {
|
|
54
|
+
if (detail.matched.length === 0)
|
|
55
|
+
return false;
|
|
56
|
+
if (detail.symbolHit)
|
|
57
|
+
return true;
|
|
58
|
+
if (detail.matched.length >= 2)
|
|
59
|
+
return true;
|
|
60
|
+
return queryTokenCount <= 1;
|
|
37
61
|
}
|
|
38
62
|
const INDEX_RE = /(^|\/)index\.[cm]?[jt]sx?$/;
|
|
63
|
+
/**
|
|
64
|
+
* Rank ALL primitives by the matcher's own score (descending; ties broken by
|
|
65
|
+
* symbol name so the order is deterministic), then return the top-`k` as scored
|
|
66
|
+
* did-you-mean suggestions. Pure — no graph, no IO — so it is directly
|
|
67
|
+
* unit-testable. When every candidate scores 0 (a nonsense intent that shares no
|
|
68
|
+
* term) the result is the alphabetically-first `k` primitives, each with
|
|
69
|
+
* `score: 0`; the caller states "no candidate shares any term" in that case
|
|
70
|
+
* rather than dumping the whole catalog.
|
|
71
|
+
*/
|
|
72
|
+
export function rankReuseSuggestions(primitives, tokens, k) {
|
|
73
|
+
const cap = Math.max(1, Math.floor(k));
|
|
74
|
+
return primitives
|
|
75
|
+
.map((p) => ({ p, detail: scorePrimitive(p, tokens) }))
|
|
76
|
+
.sort((a, b) => b.detail.score - a.detail.score || a.p.symbol.localeCompare(b.p.symbol))
|
|
77
|
+
.slice(0, cap)
|
|
78
|
+
.map(({ p, detail }) => ({
|
|
79
|
+
symbol: p.symbol,
|
|
80
|
+
score: detail.score,
|
|
81
|
+
confidence: tokens.length === 0 ? 0 : detail.matched.length / tokens.length,
|
|
82
|
+
matched: detail.matched,
|
|
83
|
+
roles: p.roles,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
39
86
|
export const reuseCommand = {
|
|
40
87
|
name: 'reuse',
|
|
41
88
|
description: 'Intent → the canonical primitive to reuse. Matches your intent against configured reusePrimitives[], then resolves the symbol in the code graph to its declaration, public import path, sibling exports, and real consumer files to copy. Deterministic; no AI.',
|
|
42
|
-
usage: 'shrk reuse "<what I want to build>" [--limit N] [--json]',
|
|
89
|
+
usage: 'shrk reuse "<what I want to build>" [--limit N] [--all] [--json]',
|
|
90
|
+
booleanFlags: new Set(['json', 'all']),
|
|
43
91
|
async run(args) {
|
|
44
92
|
const cwd = resolveCwd(args);
|
|
45
93
|
const wantJson = flagBool(args, 'json');
|
|
46
|
-
const
|
|
94
|
+
const wantAll = flagBool(args, 'all');
|
|
95
|
+
// `--limit N` caps both the confident results (historic default 3) and the
|
|
96
|
+
// did-you-mean suggestion list. When omitted, suggestions default to 5 (a
|
|
97
|
+
// couple more than results — the point of a did-you-mean is a short menu).
|
|
98
|
+
const limitFlag = flagNumber(args, 'limit');
|
|
99
|
+
const limit = limitFlag ?? 3;
|
|
100
|
+
const suggestK = limitFlag ?? 5;
|
|
47
101
|
const intent = args.positional.join(' ').trim();
|
|
48
102
|
if (!intent) {
|
|
49
|
-
process.stderr.write('Usage: shrk reuse "<what I want to build>" [--limit N] [--json]\n');
|
|
103
|
+
process.stderr.write('Usage: shrk reuse "<what I want to build>" [--limit N] [--all] [--json]\n');
|
|
50
104
|
return 2;
|
|
51
105
|
}
|
|
52
106
|
const loaded = await resolveProjectConfig(cwd);
|
|
@@ -82,28 +136,104 @@ export const reuseCommand = {
|
|
|
82
136
|
return 0;
|
|
83
137
|
}
|
|
84
138
|
const tokens = tokenize(intent);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
.
|
|
88
|
-
.
|
|
89
|
-
.
|
|
139
|
+
const confidenceOf = (matched) => tokens.length === 0 ? 0 : matched / tokens.length;
|
|
140
|
+
const scored = primitives
|
|
141
|
+
.map((p) => ({ p, detail: scorePrimitive(p, tokens) }))
|
|
142
|
+
.filter((x) => x.detail.score > 0)
|
|
143
|
+
.sort((a, b) => b.detail.score - a.detail.score || a.p.symbol.localeCompare(b.p.symbol));
|
|
144
|
+
const confident = scored.filter((x) => isConfidentMatch(x.detail, tokens.length));
|
|
145
|
+
const ranked = confident.slice(0, Math.max(1, limit));
|
|
90
146
|
const store = new GraphStore(cwd);
|
|
91
147
|
const api = store.exists() ? GraphQueryApi.fromStore(cwd) : null;
|
|
148
|
+
// Zero keyword overlap: nothing matched at all. Rather than dump the entire
|
|
149
|
+
// declared catalog (dozens of lines an agent must re-read), rank ALL
|
|
150
|
+
// candidates and surface the nearest top-K by name — every score is 0 here,
|
|
151
|
+
// so this is an alphabetized short menu, stated as such. The full catalog is
|
|
152
|
+
// available only behind an explicit `--all`.
|
|
153
|
+
if (scored.length === 0) {
|
|
154
|
+
const suggestions = rankReuseSuggestions(primitives, tokens, suggestK);
|
|
155
|
+
const roles = [...new Set(primitives.flatMap((p) => p.roles))].sort();
|
|
156
|
+
if (wantJson) {
|
|
157
|
+
process.stdout.write(asJson({
|
|
158
|
+
schema: 'sharkcraft.reuse/v1',
|
|
159
|
+
intent,
|
|
160
|
+
confident: false,
|
|
161
|
+
results: [],
|
|
162
|
+
suggestions,
|
|
163
|
+
...(wantAll ? { availableRoles: roles } : {}),
|
|
164
|
+
...planeJson,
|
|
165
|
+
}) + '\n');
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
169
|
+
if (wantAll) {
|
|
170
|
+
process.stdout.write(' No primitive matched — no candidate shares any term — showing full catalog:\n');
|
|
171
|
+
for (const r of roles.slice(0, 40))
|
|
172
|
+
process.stdout.write(` • ${r}\n`);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
process.stdout.write(' No strong match — no candidate shares any term with the intent.\n' +
|
|
176
|
+
' Nearest primitives (pass --all for the full catalog):\n');
|
|
177
|
+
for (const s of suggestions) {
|
|
178
|
+
process.stdout.write(` • ${s.symbol} (score ${s.score}; roles: ${s.roles.join(', ') || '—'})\n`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
writePlaneNotes();
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
// Weak overlap only (a single generic keyword collision on an unrelated
|
|
185
|
+
// entry): below the confidence floor. A miss must look like a miss — never
|
|
186
|
+
// return the nearest collision as a confident answer. Offer did-you-mean.
|
|
92
187
|
if (ranked.length === 0) {
|
|
188
|
+
// Rank the weakly-overlapping candidates (score > 0) and cap at K — never
|
|
189
|
+
// the whole catalog. `suggestions` and the legacy `didYouMean` alias carry
|
|
190
|
+
// the same scored rows; `--all` additionally dumps every declared role.
|
|
191
|
+
const suggestions = scored.slice(0, Math.max(1, suggestK)).map((x) => ({
|
|
192
|
+
symbol: x.p.symbol,
|
|
193
|
+
score: x.detail.score,
|
|
194
|
+
confidence: confidenceOf(x.detail.matched.length),
|
|
195
|
+
matched: x.detail.matched,
|
|
196
|
+
roles: x.p.roles,
|
|
197
|
+
}));
|
|
93
198
|
const roles = [...new Set(primitives.flatMap((p) => p.roles))].sort();
|
|
94
199
|
if (wantJson) {
|
|
95
|
-
process.stdout.write(asJson({
|
|
200
|
+
process.stdout.write(asJson({
|
|
201
|
+
schema: 'sharkcraft.reuse/v1',
|
|
202
|
+
intent,
|
|
203
|
+
confident: false,
|
|
204
|
+
results: [],
|
|
205
|
+
suggestions,
|
|
206
|
+
didYouMean: suggestions,
|
|
207
|
+
...(wantAll ? { availableRoles: roles } : {}),
|
|
208
|
+
...planeJson,
|
|
209
|
+
}) + '\n');
|
|
96
210
|
return 0;
|
|
97
211
|
}
|
|
98
212
|
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
99
|
-
process.stdout.write(' No
|
|
100
|
-
|
|
101
|
-
|
|
213
|
+
process.stdout.write(' No confident match — the intent only weakly overlaps existing primitives.\n' +
|
|
214
|
+
' Did you mean (weak, verify before reusing):\n');
|
|
215
|
+
for (const s of suggestions) {
|
|
216
|
+
process.stdout.write(` • ${s.symbol} (score ${s.score}, ${Math.round(s.confidence * 100)}% of intent; matched: ${s.matched.join(', ') || '—'})\n`);
|
|
217
|
+
}
|
|
218
|
+
if (wantAll) {
|
|
219
|
+
process.stdout.write(' Full catalog (all declared roles):\n');
|
|
220
|
+
for (const r of roles.slice(0, 40))
|
|
221
|
+
process.stdout.write(` • ${r}\n`);
|
|
222
|
+
}
|
|
102
223
|
writePlaneNotes();
|
|
103
224
|
return 0;
|
|
104
225
|
}
|
|
105
|
-
const results = ranked.map(({ p,
|
|
106
|
-
const
|
|
226
|
+
const results = ranked.map(({ p, detail }) => {
|
|
227
|
+
const score = detail.score;
|
|
228
|
+
const r = {
|
|
229
|
+
symbol: p.symbol,
|
|
230
|
+
score,
|
|
231
|
+
confidence: confidenceOf(detail.matched.length),
|
|
232
|
+
matched: detail.matched,
|
|
233
|
+
roles: p.roles,
|
|
234
|
+
siblings: [],
|
|
235
|
+
consumers: [],
|
|
236
|
+
};
|
|
107
237
|
if (p.description)
|
|
108
238
|
r.description = p.description;
|
|
109
239
|
if (p.importPath)
|
|
@@ -141,8 +271,9 @@ export const reuseCommand = {
|
|
|
141
271
|
}
|
|
142
272
|
}
|
|
143
273
|
}
|
|
144
|
-
|
|
145
|
-
|
|
274
|
+
const sites = api.referenceSitesOf(sym.id);
|
|
275
|
+
r.consumerTotal = sites.length;
|
|
276
|
+
r.consumers = sites
|
|
146
277
|
.slice(0, 5)
|
|
147
278
|
.map((s) => ({ path: s.node.path ?? s.node.id, ...(s.line ? { line: s.line } : {}) }));
|
|
148
279
|
const alts = pool.slice(1).map((c) => c.path).filter((x) => !!x);
|
|
@@ -174,6 +305,7 @@ export const reuseCommand = {
|
|
|
174
305
|
process.stdout.write(`\n${i}. ${r.symbol}\n`);
|
|
175
306
|
if (r.description)
|
|
176
307
|
process.stdout.write(` ${r.description}\n`);
|
|
308
|
+
process.stdout.write(` match: score ${r.score} (${Math.round(r.confidence * 100)}% of intent; matched: ${r.matched.join(', ') || '—'})\n`);
|
|
177
309
|
if (r.notFound) {
|
|
178
310
|
process.stdout.write(' ⚠ symbol not found in the code graph — verify reusePrimitives[].symbol (typo/rename?) or run `shrk graph index`\n');
|
|
179
311
|
}
|
|
@@ -192,7 +324,11 @@ export const reuseCommand = {
|
|
|
192
324
|
if (r.siblings.length > 0)
|
|
193
325
|
process.stdout.write(` sibling exports: ${r.siblings.join(', ')}\n`);
|
|
194
326
|
if (r.consumers.length > 0) {
|
|
195
|
-
|
|
327
|
+
const total = r.consumerTotal ?? r.consumers.length;
|
|
328
|
+
const label = total > r.consumers.length
|
|
329
|
+
? ` consumers to copy (${total} total, showing ${r.consumers.length}):\n`
|
|
330
|
+
: ` consumers to copy (${total} total):\n`;
|
|
331
|
+
process.stdout.write(label);
|
|
196
332
|
for (const c of r.consumers)
|
|
197
333
|
process.stdout.write(` - ${c.path}${c.line ? ':' + c.line : ''}\n`);
|
|
198
334
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-context.command.d.ts","sourceRoot":"","sources":["../../src/commands/smart-context.command.ts"],"names":[],"mappings":"AA2BA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAmFhC,eAAO,MAAM,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"smart-context.command.d.ts","sourceRoot":"","sources":["../../src/commands/smart-context.command.ts"],"names":[],"mappings":"AA2BA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAmFhC,eAAO,MAAM,mBAAmB,EAAE,eAiQjC,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,4BAA4B,EAAE,eAsF1C,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,uBAAuB,EAAE,eAwBrC,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,EAAE,eAkCrC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iCAAiC,EAAE,eAmH/C,CAAC;AA2JF;;;;;;;GAOG;AACH,eAAO,MAAM,iCAAiC,EAAE,eAoH/C,CAAC;AA2JF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC,EAAE,eAgG/C,CAAC;AAyPF,4EAA4E;AAC5E,eAAO,MAAM,kCAAkC,EAAE,eAuHhD,CAAC;AAMF,iFAAiF;AACjF,eAAO,MAAM,mCAAmC,EAAE,eAsCjD,CAAC;AAqJF,UAAU,eAAe;IACvB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAWzF"}
|
|
@@ -52,11 +52,13 @@ export const smartContextCommand = {
|
|
|
52
52
|
name: 'smart-context',
|
|
53
53
|
booleanFlags: SMART_CONTEXT_BOOLEAN_FLAGS,
|
|
54
54
|
description: 'Build deterministic context and ask an AI provider to synthesise an enriched brief (default), structured plan (--plan), or two-stage development plan (--ai-plan).',
|
|
55
|
-
usage: 'shrk smart-context "<task>" [--plus] [--budget <seconds>] [--plan] [--ai-plan] [--save] [--provider auto|ollama|llamacpp] [--enhance|--no-enhance] [--enhance-passes N] [--instructions <path>] [--no-instructions] [--model <id>] [--max-tokens N] [--stage1-max-tokens N] [--seed-tokens N] [--expansion-tokens N] [--expansion-limit N] [--log-prompt] [--save-conversation[=<path>]] [--dry-run] [--debug] [--json]',
|
|
55
|
+
usage: 'shrk smart-context "<task>" | --task "<task>" [--plus] [--budget <seconds>] [--plan] [--ai-plan] [--save] [--provider auto|ollama|llamacpp] [--enhance|--no-enhance] [--enhance-passes N] [--instructions <path>] [--no-instructions] [--model <id>] [--max-tokens N] [--stage1-max-tokens N] [--seed-tokens N] [--expansion-tokens N] [--expansion-limit N] [--log-prompt] [--save-conversation[=<path>]] [--dry-run] [--debug] [--json]',
|
|
56
56
|
async run(args) {
|
|
57
|
-
|
|
57
|
+
// Accept the documented `--task` form as well as the positional form, so the
|
|
58
|
+
// CLI surface matches the docs (which advertise `--task` broadly).
|
|
59
|
+
const task = (args.positional.join(' ').trim() || flagString(args, 'task') || '').trim();
|
|
58
60
|
if (!task) {
|
|
59
|
-
process.stderr.write('Usage: shrk smart-context "<task>" [--plan] [--ai-plan] [--save]\n');
|
|
61
|
+
process.stderr.write('Usage: shrk smart-context "<task>" [--task "<task>"] [--plan] [--ai-plan] [--save]\n');
|
|
60
62
|
return 2;
|
|
61
63
|
}
|
|
62
64
|
// Isolate the LLM / native-runtime work in a child process. On macOS the
|
|
@@ -165,7 +167,7 @@ export const smartContextCommand = {
|
|
|
165
167
|
(originalContext.length > 0 && enhanced.value.content.trim() === originalContext);
|
|
166
168
|
if (fullyDegraded) {
|
|
167
169
|
if (!opts.json) {
|
|
168
|
-
process.stderr.write('
|
|
170
|
+
process.stderr.write(degradedRetrievalBanner(seed, 'enhancement fully degraded') + '\n');
|
|
169
171
|
}
|
|
170
172
|
const fallbackEnvelope = buildEnvelope({
|
|
171
173
|
task,
|
|
@@ -226,7 +228,7 @@ export const smartContextCommand = {
|
|
|
226
228
|
// exit 1. The agent that asked for fast grounding still gets usable
|
|
227
229
|
// rules / paths / templates / candidate files. The error is advisory on
|
|
228
230
|
// stderr (never stdout, so --json stays valid).
|
|
229
|
-
process.stderr.write('
|
|
231
|
+
process.stderr.write(degradedRetrievalBanner(seed, 'provider unavailable') + '\n');
|
|
230
232
|
const fallbackEnvelope = buildEnvelope({
|
|
231
233
|
task,
|
|
232
234
|
seed,
|
|
@@ -1452,6 +1454,19 @@ export function renderIndexFreshnessWarning(f) {
|
|
|
1452
1454
|
`(${f.stale} changed, ${f.missing} deleted, ${f.untracked} new).${pruned} ` +
|
|
1453
1455
|
'Verify the file suggestions above before editing — run `shrk smart-context --refresh` to rebuild.');
|
|
1454
1456
|
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Loud one-liner for the degraded / provider-unavailable path. The returned
|
|
1459
|
+
* content is the deterministic seed (rules/paths/templates/candidate files), NOT
|
|
1460
|
+
* task-scoped semantic retrieval — so say so, and how far the index is behind,
|
|
1461
|
+
* so a caller never trusts a stale generic dump as if it were curated retrieval.
|
|
1462
|
+
*/
|
|
1463
|
+
function degradedRetrievalBanner(seed, cause) {
|
|
1464
|
+
const behind = seed.indexFreshness?.behind ?? 0;
|
|
1465
|
+
const behindClause = behind > 0 ? `, semantic index ${behind} file(s) behind the working tree` : '';
|
|
1466
|
+
return (`[smart-context] semantic retrieval unavailable (${cause})${behindClause} — ` +
|
|
1467
|
+
'falling back to the deterministic seed (rules/paths/templates/candidate files), NOT task-scoped retrieval. ' +
|
|
1468
|
+
'Run `shrk smart-context --refresh` to rebuild the index.');
|
|
1469
|
+
}
|
|
1455
1470
|
async function buildSmartContextSeed(input) {
|
|
1456
1471
|
const { cwd, task, inspection, options } = input;
|
|
1457
1472
|
const overview = buildProjectOverview(inspection.workspace, inspection.config?.projectName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.command.d.ts","sourceRoot":"","sources":["../../src/commands/task.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"task.command.d.ts","sourceRoot":"","sources":["../../src/commands/task.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAkEhC,eAAO,MAAM,WAAW,EAAE,eAgRzB,CAAC"}
|
|
@@ -3,6 +3,12 @@ import { SpecStatus } from '@shrkcrft/generator';
|
|
|
3
3
|
import { flagBool, flagNumber, flagList, resolveCwd, } from "../command-registry.js";
|
|
4
4
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
5
5
|
import { buildTaskNextReport } from "../task-next/task-next-ranker.js";
|
|
6
|
+
/**
|
|
7
|
+
* Budget for the DEFAULT full human-text packet when no explicit `--max-tokens`
|
|
8
|
+
* is set — large enough to hold every planned context section so orientation
|
|
9
|
+
* isn't silently thinner than the sibling verbs. JSON/terse callers keep 3500.
|
|
10
|
+
*/
|
|
11
|
+
const WIDE_TASK_BUDGET = 100_000;
|
|
6
12
|
function compactTaskPacket(p) {
|
|
7
13
|
return {
|
|
8
14
|
task: p.task,
|
|
@@ -139,14 +145,26 @@ export const taskCommand = {
|
|
|
139
145
|
return 2;
|
|
140
146
|
}
|
|
141
147
|
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
142
|
-
const maxTokens = flagNumber(args, 'max-tokens') ?? 3500;
|
|
143
148
|
const scope = flagList(args, 'scope');
|
|
144
149
|
const explainRanking = flagBool(args, 'explain-ranking') || flagBool(args, 'json');
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
const
|
|
150
|
+
// Orientation renders the full packet by default now (parity with why /
|
|
151
|
+
// reuse / knowledge get / `shrk context`) so the agent's first read isn't
|
|
152
|
+
// thinner than every adjacent command. `--summary`/`--brief` (or
|
|
153
|
+
// `--commands-first`/`--actions-only`) opts back into the terse view.
|
|
154
|
+
const wantsJson = flagBool(args, 'json');
|
|
155
|
+
const terse = flagBool(args, 'summary') ||
|
|
156
|
+
flagBool(args, 'brief') ||
|
|
157
|
+
flagBool(args, 'commands-first') ||
|
|
158
|
+
flagBool(args, 'actions-only');
|
|
159
|
+
// Compact packet (5 rules / 3 templates / 5 hints per field) still backs the
|
|
160
|
+
// default JSON shape and the terse text view; the full text view is uncapped.
|
|
161
|
+
const compact = wantsJson
|
|
162
|
+
? !flagBool(args, 'full') && !flagBool(args, 'verbose')
|
|
163
|
+
: terse;
|
|
164
|
+
// Auto-widen the context budget for the default full human view so no rich
|
|
165
|
+
// section is dropped purely to fit a tight budget; JSON/terse keep 3500.
|
|
166
|
+
const wideView = !wantsJson && !terse;
|
|
167
|
+
const maxTokens = flagNumber(args, 'max-tokens') ?? (wideView ? WIDE_TASK_BUDGET : 3500);
|
|
150
168
|
const packet = buildTaskPacket(inspection, task, {
|
|
151
169
|
maxTokens,
|
|
152
170
|
...(scope.length ? { scope } : {}),
|
|
@@ -185,14 +203,13 @@ export const taskCommand = {
|
|
|
185
203
|
process.stdout.write(kv('detected profiles', packet.detectedProfiles.join(', ') || '(none)') + '\n');
|
|
186
204
|
process.stdout.write(kv('context tokens', `${packet.context.totalTokens} / ${packet.context.maxTokens}`) + '\n');
|
|
187
205
|
process.stdout.write(kv('total token est.', String(packet.tokenEstimate)) + '\n');
|
|
188
|
-
// Commands-first summary at the top so the agent sees the action
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
// `--full` to print the full packet. JSON output is unchanged.
|
|
206
|
+
// Commands-first summary at the top so the agent sees the action path
|
|
207
|
+
// before the long context body. The full packet then prints by default;
|
|
208
|
+
// `--commands-first`/`--actions-only`/`--summary` collapse to just the
|
|
209
|
+
// commands + uncertainty footer.
|
|
193
210
|
const commandsFirst = flagBool(args, 'commands-first');
|
|
194
211
|
const actionsOnly = flagBool(args, 'actions-only');
|
|
195
|
-
const
|
|
212
|
+
const summaryOnly = flagBool(args, 'summary') || flagBool(args, 'brief');
|
|
196
213
|
if (packet.recommendedCliCommands.length > 0) {
|
|
197
214
|
process.stdout.write('\nTop commands (command-first):\n');
|
|
198
215
|
for (const c of packet.recommendedCliCommands.slice(0, 5)) {
|
|
@@ -203,11 +220,11 @@ export const taskCommand = {
|
|
|
203
220
|
process.stdout.write('\nSuggested generation:\n');
|
|
204
221
|
process.stdout.write(` $ ${packet.suggestedGen.dryRunCommand}\n`);
|
|
205
222
|
}
|
|
206
|
-
if (commandsFirst || actionsOnly ||
|
|
207
|
-
if (
|
|
208
|
-
process.stdout.write('\n(
|
|
223
|
+
if (commandsFirst || actionsOnly || summaryOnly) {
|
|
224
|
+
if (summaryOnly && !commandsFirst && !actionsOnly) {
|
|
225
|
+
process.stdout.write('\n(summary mode — omit --summary for the full packet, --json for machine output.)\n');
|
|
209
226
|
}
|
|
210
|
-
// Render uncertainty and stop — caller asked for
|
|
227
|
+
// Render uncertainty and stop — caller asked for terse output.
|
|
211
228
|
process.stdout.write('\n' + renderUncertaintyText(uncertainty) + '\n');
|
|
212
229
|
return 0;
|
|
213
230
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical exit-code contract for every gate / verify / check verb.
|
|
3
|
+
*
|
|
4
|
+
* alpha.24 and alpha.25 made the STDOUT verdicts honest ("not verified",
|
|
5
|
+
* "degraded", "0 rules evaluated", "this is not a pass") but left the exit
|
|
6
|
+
* code returning `0` over those same unverified paths. An agent almost never
|
|
7
|
+
* parses the banner — it chains `shrk <cmd> && <next>` on the *exit code*, so a
|
|
8
|
+
* `0` over a "not verified" result marches straight past the gate. This module
|
|
9
|
+
* is the single source of truth so a chained gate can finally tell apart
|
|
10
|
+
* "passed", "failed", and "never ran".
|
|
11
|
+
*
|
|
12
|
+
* 0 VerifiedPass — checks ran over a NON-EMPTY scope and passed. Never
|
|
13
|
+
* returned when zero units were evaluated.
|
|
14
|
+
* 1 Failure — checks ran and found violations.
|
|
15
|
+
* 2 NotVerified — indeterminate: empty evaluation scope, degraded
|
|
16
|
+
* fallback, short-circuit, timeout, or "refused to run".
|
|
17
|
+
* Distinct from both pass and fail so a chain can branch
|
|
18
|
+
* on it (`|| handle-indeterminate`). This is also the
|
|
19
|
+
* code the CLI already uses for usage errors — both mean
|
|
20
|
+
* "did not produce a verified result".
|
|
21
|
+
*
|
|
22
|
+
* The `gen --typecheck` pre-write gate already refuses-to-nonzero rather than
|
|
23
|
+
* emit an unverified artifact; this generalizes that instinct across the gate
|
|
24
|
+
* surface, adding the third code so "unverified" is distinguishable from
|
|
25
|
+
* "broken".
|
|
26
|
+
*/
|
|
27
|
+
export declare enum ExitCode {
|
|
28
|
+
VerifiedPass = 0,
|
|
29
|
+
Failure = 1,
|
|
30
|
+
NotVerified = 2
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Promote a NotVerified (`2`) exit into a Failure-class nonzero (`1`) when the
|
|
34
|
+
* caller opted into `--strict`. This is the one switch an agent flips to make a
|
|
35
|
+
* hard CI gate treat "unverified" as a failure. Any other code passes through
|
|
36
|
+
* unchanged (a real pass stays `0`, a real failure stays `1`). Applied globally
|
|
37
|
+
* in {@link runCli} after the handler returns, so every gate/verify verb honors
|
|
38
|
+
* `--strict` uniformly without threading the flag through each call site.
|
|
39
|
+
*/
|
|
40
|
+
export declare function promoteForStrict(code: number, strict: boolean): number;
|
|
41
|
+
/**
|
|
42
|
+
* True when the argv carries a global `--strict` (bare or `--strict=<level>`).
|
|
43
|
+
* `--strict` is also an established per-command flag (e.g. `check --strict`,
|
|
44
|
+
* `doctor --strict=warnings`) whose local meaning is preserved — this global
|
|
45
|
+
* layer only adds the NotVerified→Failure promotion on top, and only affects a
|
|
46
|
+
* command that actually returned `2`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function argvHasStrict(argv: readonly string[]): boolean;
|
|
49
|
+
//# sourceMappingURL=exit-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,oBAAY,QAAQ;IAClB,YAAY,IAAI;IAChB,OAAO,IAAI;IACX,WAAW,IAAI;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAGtE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAM9D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical exit-code contract for every gate / verify / check verb.
|
|
3
|
+
*
|
|
4
|
+
* alpha.24 and alpha.25 made the STDOUT verdicts honest ("not verified",
|
|
5
|
+
* "degraded", "0 rules evaluated", "this is not a pass") but left the exit
|
|
6
|
+
* code returning `0` over those same unverified paths. An agent almost never
|
|
7
|
+
* parses the banner — it chains `shrk <cmd> && <next>` on the *exit code*, so a
|
|
8
|
+
* `0` over a "not verified" result marches straight past the gate. This module
|
|
9
|
+
* is the single source of truth so a chained gate can finally tell apart
|
|
10
|
+
* "passed", "failed", and "never ran".
|
|
11
|
+
*
|
|
12
|
+
* 0 VerifiedPass — checks ran over a NON-EMPTY scope and passed. Never
|
|
13
|
+
* returned when zero units were evaluated.
|
|
14
|
+
* 1 Failure — checks ran and found violations.
|
|
15
|
+
* 2 NotVerified — indeterminate: empty evaluation scope, degraded
|
|
16
|
+
* fallback, short-circuit, timeout, or "refused to run".
|
|
17
|
+
* Distinct from both pass and fail so a chain can branch
|
|
18
|
+
* on it (`|| handle-indeterminate`). This is also the
|
|
19
|
+
* code the CLI already uses for usage errors — both mean
|
|
20
|
+
* "did not produce a verified result".
|
|
21
|
+
*
|
|
22
|
+
* The `gen --typecheck` pre-write gate already refuses-to-nonzero rather than
|
|
23
|
+
* emit an unverified artifact; this generalizes that instinct across the gate
|
|
24
|
+
* surface, adding the third code so "unverified" is distinguishable from
|
|
25
|
+
* "broken".
|
|
26
|
+
*/
|
|
27
|
+
export var ExitCode;
|
|
28
|
+
(function (ExitCode) {
|
|
29
|
+
ExitCode[ExitCode["VerifiedPass"] = 0] = "VerifiedPass";
|
|
30
|
+
ExitCode[ExitCode["Failure"] = 1] = "Failure";
|
|
31
|
+
ExitCode[ExitCode["NotVerified"] = 2] = "NotVerified";
|
|
32
|
+
})(ExitCode || (ExitCode = {}));
|
|
33
|
+
/**
|
|
34
|
+
* Promote a NotVerified (`2`) exit into a Failure-class nonzero (`1`) when the
|
|
35
|
+
* caller opted into `--strict`. This is the one switch an agent flips to make a
|
|
36
|
+
* hard CI gate treat "unverified" as a failure. Any other code passes through
|
|
37
|
+
* unchanged (a real pass stays `0`, a real failure stays `1`). Applied globally
|
|
38
|
+
* in {@link runCli} after the handler returns, so every gate/verify verb honors
|
|
39
|
+
* `--strict` uniformly without threading the flag through each call site.
|
|
40
|
+
*/
|
|
41
|
+
export function promoteForStrict(code, strict) {
|
|
42
|
+
if (strict && code === ExitCode.NotVerified)
|
|
43
|
+
return ExitCode.Failure;
|
|
44
|
+
return code;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* True when the argv carries a global `--strict` (bare or `--strict=<level>`).
|
|
48
|
+
* `--strict` is also an established per-command flag (e.g. `check --strict`,
|
|
49
|
+
* `doctor --strict=warnings`) whose local meaning is preserved — this global
|
|
50
|
+
* layer only adds the NotVerified→Failure promotion on top, and only affects a
|
|
51
|
+
* command that actually returned `2`.
|
|
52
|
+
*/
|
|
53
|
+
export function argvHasStrict(argv) {
|
|
54
|
+
for (const t of argv) {
|
|
55
|
+
if (t === '--')
|
|
56
|
+
break;
|
|
57
|
+
if (t === '--strict' || t.startsWith('--strict='))
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
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;AA8X/B,wBAAgB,aAAa,IAAI,eAAe,CAiY/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiCrE;AAqID;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAoDxE"}
|
package/dist/main.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { loadDotenv } from "./env/load-dotenv.js";
|
|
3
3
|
import { CommandRegistry, extractGlobalCompress, extractGlobalCwd, parseArgs, } from "./command-registry.js";
|
|
4
|
+
import { argvHasStrict, promoteForStrict } from "./exit-codes.js";
|
|
4
5
|
import { runCommandWithCompression } from "./output/output-compression.js";
|
|
5
6
|
import { initCommand } from "./commands/init.command.js";
|
|
6
7
|
import { inspectCommand } from "./commands/inspect.command.js";
|
|
@@ -73,6 +74,7 @@ import { movePlanCommand } from "./commands/move-plan.command.js";
|
|
|
73
74
|
import { watchCommand, watchListCommand, watchPruneCommand, watchStopCommand } from "./commands/watch.command.js";
|
|
74
75
|
import { mcpCommand } from "./commands/mcp.command.js";
|
|
75
76
|
import { versionCommand } from "./commands/version.command.js";
|
|
77
|
+
import { changelogCommand } from "./commands/changelog.command.js";
|
|
76
78
|
import { makeHelpCommand } from "./commands/help.command.js";
|
|
77
79
|
import { qualityCommand } from "./commands/quality.command.js";
|
|
78
80
|
import { ciCommand } from "./commands/ci.command.js";
|
|
@@ -249,6 +251,7 @@ export function buildRegistry() {
|
|
|
249
251
|
registry.registerSubcommand('watch', watchPruneCommand);
|
|
250
252
|
registry.register(mcpCommand);
|
|
251
253
|
registry.register(versionCommand);
|
|
254
|
+
registry.register(changelogCommand);
|
|
252
255
|
registry.register(qualityCommand);
|
|
253
256
|
registry.register(ciCommand);
|
|
254
257
|
registry.register(eslintCommand);
|
|
@@ -507,9 +510,15 @@ export function buildRegistry() {
|
|
|
507
510
|
export async function runCli(argv) {
|
|
508
511
|
const usageStart = performance.now();
|
|
509
512
|
const { cwd: probeCwd, rest: probeArgv } = extractGlobalCwd(argv);
|
|
513
|
+
// Global `--strict` promotes a NotVerified (`2`) verdict to a Failure-class
|
|
514
|
+
// nonzero across every gate/verify verb — one switch to make an "unverified"
|
|
515
|
+
// result fail a hard CI gate. A real pass (`0`) or failure (`1`) is untouched,
|
|
516
|
+
// and each command's own `--strict` semantics (e.g. `check --strict`) still
|
|
517
|
+
// apply beneath this (a25 §1.1).
|
|
518
|
+
const strict = argvHasStrict(argv);
|
|
510
519
|
let exitCode = 0;
|
|
511
520
|
try {
|
|
512
|
-
exitCode = await runCliInner(argv);
|
|
521
|
+
exitCode = promoteForStrict(await runCliInner(argv), strict);
|
|
513
522
|
return exitCode;
|
|
514
523
|
}
|
|
515
524
|
finally {
|
|
@@ -921,6 +930,22 @@ if (isMain ||
|
|
|
921
930
|
// test). Commands that re-exec themselves in an isolated child gate on this
|
|
922
931
|
// so unit tests calling `run()` in-process never spawn a subprocess.
|
|
923
932
|
process.env.SHRK_CLI = '1';
|
|
933
|
+
// Global broken-pipe containment. When a downstream reader closes early
|
|
934
|
+
// (`shrk registry <name> list | head`, `… | grep`), Node raises `write EPIPE`
|
|
935
|
+
// on stdout from the async write/flush path — with no `error` listener that
|
|
936
|
+
// becomes an uncaught exception and a nonzero exit, forging a false failure on
|
|
937
|
+
// a happy-path query whose data was fine (a25 §2.2). Swallowing EPIPE here (a
|
|
938
|
+
// no-op listener) turns it back into a benign early-close: the command keeps
|
|
939
|
+
// its REAL exit code, and nothing is written to the dead pipe. Registered once
|
|
940
|
+
// at startup so every verb that streams a list is covered.
|
|
941
|
+
const swallowPipeError = (err) => {
|
|
942
|
+
if (err && err.code === 'EPIPE')
|
|
943
|
+
return;
|
|
944
|
+
// Any other stdio error (ENOSPC, …) is unrecoverable mid-write; there is
|
|
945
|
+
// nothing safe to print, so contain it rather than crash the shutdown path.
|
|
946
|
+
};
|
|
947
|
+
process.stdout.on('error', swallowPipeError);
|
|
948
|
+
process.stderr.on('error', swallowPipeError);
|
|
924
949
|
loadDotenv(process.cwd());
|
|
925
950
|
const argv = process.argv.slice(2);
|
|
926
951
|
const cleanShutdown = async (code) => {
|
|
@@ -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"}
|