@shrkcrft/cli 0.1.0-alpha.22 → 0.1.0-alpha.23
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 +9 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +15 -0
- package/dist/commands/ai-status.command.d.ts.map +1 -1
- package/dist/commands/ai-status.command.js +10 -0
- package/dist/commands/apply.command.d.ts.map +1 -1
- package/dist/commands/apply.command.js +9 -2
- package/dist/commands/ask.command.d.ts.map +1 -1
- package/dist/commands/ask.command.js +2 -1
- package/dist/commands/changes.command.d.ts.map +1 -1
- package/dist/commands/changes.command.js +14 -4
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +30 -5
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +200 -0
- package/dist/commands/commands.command.d.ts +15 -0
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +162 -3
- package/dist/commands/compress.command.d.ts.map +1 -1
- package/dist/commands/compress.command.js +39 -4
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +3 -1
- package/dist/commands/daily.commands.d.ts.map +1 -1
- package/dist/commands/daily.commands.js +48 -5
- package/dist/commands/diff-check.command.d.ts.map +1 -1
- package/dist/commands/diff-check.command.js +6 -2
- package/dist/commands/feedback.command.d.ts.map +1 -1
- package/dist/commands/feedback.command.js +4 -0
- package/dist/commands/framework.command.d.ts.map +1 -1
- package/dist/commands/framework.command.js +20 -3
- package/dist/commands/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +98 -13
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +183 -68
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +6 -0
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +91 -1
- package/dist/commands/knowledge.command.d.ts.map +1 -1
- package/dist/commands/knowledge.command.js +21 -1
- package/dist/commands/onboard.command.d.ts.map +1 -1
- package/dist/commands/onboard.command.js +11 -2
- package/dist/commands/orchestrate.command.d.ts.map +1 -1
- package/dist/commands/orchestrate.command.js +6 -1
- package/dist/commands/pack-author.command.d.ts.map +1 -1
- package/dist/commands/pack-author.command.js +13 -1
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +95 -17
- package/dist/commands/paths.command.d.ts.map +1 -1
- package/dist/commands/paths.command.js +8 -1
- package/dist/commands/pipelines.command.d.ts.map +1 -1
- package/dist/commands/pipelines.command.js +2 -1
- package/dist/commands/plan-context.command.d.ts.map +1 -1
- package/dist/commands/plan-context.command.js +6 -3
- package/dist/commands/plan-simulate.command.js +1 -1
- package/dist/commands/policy-lint.command.d.ts.map +1 -1
- package/dist/commands/policy-lint.command.js +20 -7
- package/dist/commands/recommend.command.d.ts.map +1 -1
- package/dist/commands/recommend.command.js +10 -2
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +117 -9
- package/dist/commands/report.command.js +1 -1
- package/dist/commands/reuse.command.d.ts.map +1 -1
- package/dist/commands/reuse.command.js +17 -5
- package/dist/commands/review.command.d.ts.map +1 -1
- package/dist/commands/review.command.js +20 -2
- package/dist/commands/rule-graph-subverbs.d.ts.map +1 -1
- package/dist/commands/rule-graph-subverbs.js +31 -4
- package/dist/commands/search-structural.command.d.ts.map +1 -1
- package/dist/commands/search-structural.command.js +2 -2
- package/dist/commands/search.command.d.ts.map +1 -1
- package/dist/commands/search.command.js +19 -1
- package/dist/commands/simulate.command.d.ts.map +1 -1
- package/dist/commands/simulate.command.js +6 -1
- package/dist/commands/smart-context.command.d.ts.map +1 -1
- package/dist/commands/smart-context.command.js +87 -4
- package/dist/commands/spec.command.d.ts.map +1 -1
- package/dist/commands/spec.command.js +73 -13
- package/dist/commands/task-context.command.d.ts.map +1 -1
- package/dist/commands/task-context.command.js +26 -2
- package/dist/commands/test.command.d.ts.map +1 -1
- package/dist/commands/test.command.js +17 -0
- package/dist/commands/trace.command.d.ts.map +1 -1
- package/dist/commands/trace.command.js +14 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +15 -1
- package/dist/status/freshness.d.ts +30 -0
- package/dist/status/freshness.d.ts.map +1 -0
- package/dist/status/freshness.js +81 -0
- package/package.json +33 -33
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { flagBool, flagString } from "../command-registry.js";
|
|
1
|
+
import { flagBool, flagString, resolveCwd } from "../command-registry.js";
|
|
2
2
|
import { asJson, header } from "../output/format-output.js";
|
|
3
|
+
import { BUILTIN_PROFILES, getProfile } from "../surface/profiles.js";
|
|
3
4
|
import { buildCommandSafetyMatrix, COMMAND_CATALOG, CommandLifecycle, commandLifecycle, CommandSurface, commandSurface, commandTaskRole, defaultShowInHelp, R46_OVERLAY, renderCommandSafetyMatrixMarkdown, SafetyLevel } from "./command-catalog.js";
|
|
4
5
|
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText } from '@shrkcrft/inspector';
|
|
5
6
|
export function makeCommandsCommand(registry) {
|
|
6
7
|
return {
|
|
7
8
|
name: 'commands',
|
|
8
|
-
description: 'Browse the command catalog. Default view is compact (primary + common); pass --all for the full catalog. Subcommands: primary | advanced | deprecated | hidden | retirement-plan | docs-check | surface | machine | legacy | overlaps | taxonomy | matrix | tree | search | suggest | explain | entrypoints | doctor | ux-check.',
|
|
9
|
-
usage: 'shrk commands [primary|advanced|deprecated|hidden|retirement-plan|docs-check|surface <s>|machine|legacy|overlaps|taxonomy|matrix|tree|search <q>|suggest <p>|explain <cmd>|entrypoints|doctor|ux-check] [--all] [--safety <level>] [--category <name>] [--json]',
|
|
9
|
+
description: 'Browse the command catalog. Default view is compact (primary + common); pass --all for the full catalog, or --profile <id> (e.g. agent) for the surface a profile sees. Subcommands: primary | advanced | deprecated | hidden | retirement-plan | docs-check | surface | profile | machine | legacy | overlaps | taxonomy | matrix | tree | search | suggest | explain | entrypoints | doctor | ux-check.',
|
|
10
|
+
usage: 'shrk commands [primary|advanced|deprecated|hidden|retirement-plan|docs-check|surface <s>|profile [<id>]|machine|legacy|overlaps|taxonomy|matrix|tree|search <q>|suggest <p>|explain <cmd>|entrypoints|doctor|ux-check] [--all] [--profile <id>] [--safety <level>] [--category <name>] [--json]',
|
|
10
11
|
async run(args) {
|
|
11
12
|
const sub = args.positional[0];
|
|
12
13
|
if (sub === 'doctor') {
|
|
@@ -95,6 +96,12 @@ export function makeCommandsCommand(registry) {
|
|
|
95
96
|
if (sub === 'surface') {
|
|
96
97
|
return runCommandsSurface(args);
|
|
97
98
|
}
|
|
99
|
+
// `shrk commands profile [<id>]` — list surface profiles, or render the
|
|
100
|
+
// catalog as one profile sees it (the curated view, e.g. `agent`).
|
|
101
|
+
if (sub === 'profile') {
|
|
102
|
+
const id = args.positional[1];
|
|
103
|
+
return id ? runCommandsProfile(args, id) : runCommandsProfileList(args);
|
|
104
|
+
}
|
|
98
105
|
if (sub === 'machine') {
|
|
99
106
|
return runCommandsMachine(args);
|
|
100
107
|
}
|
|
@@ -120,8 +127,34 @@ export function makeCommandsCommand(registry) {
|
|
|
120
127
|
if (sub === 'docs-check') {
|
|
121
128
|
return runCommandsDocsCheck(args);
|
|
122
129
|
}
|
|
130
|
+
// `--profile <id>` renders the catalog curated for a surface profile
|
|
131
|
+
// (e.g. `--profile agent` hides CI/release/pack-maintenance machinery an
|
|
132
|
+
// inline agent doesn't need). Commands stay callable; this is a listing
|
|
133
|
+
// filter, not a disable.
|
|
134
|
+
const profileFilter = flagString(args, 'profile');
|
|
135
|
+
if (profileFilter) {
|
|
136
|
+
return runCommandsProfile(args, profileFilter);
|
|
137
|
+
}
|
|
123
138
|
const safetyFilter = flagString(args, 'safety');
|
|
124
139
|
const categoryFilter = flagString(args, 'category');
|
|
140
|
+
// Validate the filter values against real allowlists — a typo (e.g.
|
|
141
|
+
// `--safety read` or `--category typo`) previously matched nothing and
|
|
142
|
+
// returned "commands (0)" with exit 0, which reads like an empty result
|
|
143
|
+
// rather than a mistake. Reject with the valid set + exit 2 instead.
|
|
144
|
+
if (safetyFilter !== undefined) {
|
|
145
|
+
const validSafety = new Set(Object.values(SafetyLevel));
|
|
146
|
+
if (!validSafety.has(safetyFilter)) {
|
|
147
|
+
process.stderr.write(`Unknown --safety "${safetyFilter}". Valid: ${[...validSafety].sort().join(', ')}\n`);
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (categoryFilter !== undefined) {
|
|
152
|
+
const validCategories = new Set(COMMAND_CATALOG.map((e) => e.category));
|
|
153
|
+
if (!validCategories.has(categoryFilter)) {
|
|
154
|
+
process.stderr.write(`Unknown --category "${categoryFilter}". Valid: ${[...validCategories].sort().join(', ')}\n`);
|
|
155
|
+
return 2;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
125
158
|
const wantsAll = flagBool(args, 'all');
|
|
126
159
|
let entries = COMMAND_CATALOG;
|
|
127
160
|
if (safetyFilter) {
|
|
@@ -186,6 +219,97 @@ function runCommandsSurface(args) {
|
|
|
186
219
|
}
|
|
187
220
|
return 0;
|
|
188
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Pure: render the catalog as a surface profile sees it. Every command the
|
|
224
|
+
* profile lists in `hidden` is filtered out of `entries` (commands stay
|
|
225
|
+
* callable — this is a listing filter, not a disable). Returns undefined when
|
|
226
|
+
* the profile id is unknown. Exported for tests.
|
|
227
|
+
*/
|
|
228
|
+
export function buildCommandsProfileView(profileId, packProfiles = []) {
|
|
229
|
+
const profile = getProfile(profileId, packProfiles);
|
|
230
|
+
if (!profile)
|
|
231
|
+
return undefined;
|
|
232
|
+
const hidden = new Set(profile.hidden ?? []);
|
|
233
|
+
const entries = COMMAND_CATALOG.filter((e) => !hidden.has(e.command));
|
|
234
|
+
return { profile, entries, hidden: [...hidden].sort(), catalogTotal: COMMAND_CATALOG.length };
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* `shrk commands --profile <id>` / `shrk commands profile <id>` renders the
|
|
238
|
+
* catalog curated for a surface profile (e.g. `agent` hides
|
|
239
|
+
* CI/release/pack-maintenance machinery an inline agent doesn't need) without
|
|
240
|
+
* editing `sharkcraft.config.ts`. Builtin profiles resolve instantly; an
|
|
241
|
+
* unknown id falls back to discovering pack-contributed profiles via the
|
|
242
|
+
* surface context (best-effort — needs a workspace).
|
|
243
|
+
*/
|
|
244
|
+
async function runCommandsProfile(args, profileId) {
|
|
245
|
+
let view = buildCommandsProfileView(profileId);
|
|
246
|
+
let validIds = BUILTIN_PROFILES.map((p) => p.id);
|
|
247
|
+
if (!view) {
|
|
248
|
+
try {
|
|
249
|
+
const { loadSurfaceContext } = await import("../surface/load-surface-context.js");
|
|
250
|
+
const ctx = await loadSurfaceContext({ cwd: resolveCwd(args) });
|
|
251
|
+
validIds = ctx.availableProfiles.map((p) => p.id);
|
|
252
|
+
view = buildCommandsProfileView(profileId, ctx.availableProfiles);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Pack discovery failed (e.g. outside a project) — builtin-only.
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (!view) {
|
|
259
|
+
process.stderr.write(`Unknown profile "${profileId}". Valid: ${[...validIds].sort().join(', ')}\n`);
|
|
260
|
+
return 2;
|
|
261
|
+
}
|
|
262
|
+
const { profile, entries, hidden, catalogTotal } = view;
|
|
263
|
+
if (flagBool(args, 'json')) {
|
|
264
|
+
process.stdout.write(asJson({
|
|
265
|
+
profile: profile.id,
|
|
266
|
+
description: profile.description,
|
|
267
|
+
source: profile.source,
|
|
268
|
+
total: entries.length,
|
|
269
|
+
catalogTotal,
|
|
270
|
+
hiddenCount: hidden.length,
|
|
271
|
+
hidden,
|
|
272
|
+
entries,
|
|
273
|
+
}) + '\n');
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
process.stdout.write(header(`Commands — profile=${profile.id} (${entries.length} of ${catalogTotal} visible)`));
|
|
277
|
+
process.stdout.write(` ${profile.description}\n`);
|
|
278
|
+
if (hidden.length > 0) {
|
|
279
|
+
process.stdout.write(` (${hidden.length} command(s) hidden by this profile — still callable)\n`);
|
|
280
|
+
}
|
|
281
|
+
const grouped = new Map();
|
|
282
|
+
for (const e of entries) {
|
|
283
|
+
const arr = grouped.get(e.category) ?? [];
|
|
284
|
+
arr.push(e);
|
|
285
|
+
grouped.set(e.category, arr);
|
|
286
|
+
}
|
|
287
|
+
for (const [cat, items] of [...grouped.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
288
|
+
process.stdout.write(`\n## ${cat}\n`);
|
|
289
|
+
for (const e of items.sort((a, b) => a.command.localeCompare(b.command))) {
|
|
290
|
+
process.stdout.write(` ${safetyTag(e.safetyLevel)} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
/** `shrk commands profile` (no id) lists the available surface profiles. */
|
|
296
|
+
function runCommandsProfileList(args) {
|
|
297
|
+
const rows = BUILTIN_PROFILES.map((p) => ({
|
|
298
|
+
id: p.id,
|
|
299
|
+
description: p.description,
|
|
300
|
+
hides: (p.hidden ?? []).length,
|
|
301
|
+
}));
|
|
302
|
+
if (flagBool(args, 'json')) {
|
|
303
|
+
process.stdout.write(asJson({ total: rows.length, profiles: rows }) + '\n');
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
process.stdout.write(header(`Surface profiles (${rows.length})`));
|
|
307
|
+
for (const r of rows) {
|
|
308
|
+
process.stdout.write(` ${r.id.padEnd(12)} hides=${String(r.hides).padEnd(4)} ${r.description}\n`);
|
|
309
|
+
}
|
|
310
|
+
process.stdout.write(`\nUsage: shrk commands profile <id> | shrk commands --profile <id> (render the curated view)\n`);
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
189
313
|
/** `shrk commands machine` lists machine-oriented commands. */
|
|
190
314
|
function runCommandsMachine(args) {
|
|
191
315
|
const matches = COMMAND_CATALOG.filter((e) => commandSurface(e) === CommandSurface.Machine || e.machineOnly === true);
|
|
@@ -487,6 +611,10 @@ export const commandsCommand = {
|
|
|
487
611
|
// Keep the new views available even via the back-compat entry.
|
|
488
612
|
if (sub === 'surface')
|
|
489
613
|
return runCommandsSurface(args);
|
|
614
|
+
if (sub === 'profile') {
|
|
615
|
+
const id = args.positional[1];
|
|
616
|
+
return id ? runCommandsProfile(args, id) : runCommandsProfileList(args);
|
|
617
|
+
}
|
|
490
618
|
if (sub === 'machine')
|
|
491
619
|
return runCommandsMachine(args);
|
|
492
620
|
if (sub === 'legacy')
|
|
@@ -503,6 +631,10 @@ export const commandsCommand = {
|
|
|
503
631
|
return runCommandsRetirementPlan(args);
|
|
504
632
|
if (sub === 'docs-check')
|
|
505
633
|
return await runCommandsDocsCheck(args);
|
|
634
|
+
const profileFilter = flagString(args, 'profile');
|
|
635
|
+
if (profileFilter) {
|
|
636
|
+
return runCommandsProfile(args, profileFilter);
|
|
637
|
+
}
|
|
506
638
|
const safetyFilter = flagString(args, 'safety');
|
|
507
639
|
const categoryFilter = flagString(args, 'category');
|
|
508
640
|
let entries = COMMAND_CATALOG;
|
|
@@ -882,6 +1014,33 @@ export function buildCommandsDoctorReport(registry) {
|
|
|
882
1014
|
});
|
|
883
1015
|
}
|
|
884
1016
|
}
|
|
1017
|
+
// 8. registerSubcommand-only GROUPS without a catalog entry.
|
|
1018
|
+
// Check #7 above only sees depth-1 nodes that carry a handler
|
|
1019
|
+
// (registry.list()). Groups registered purely via registerSubcommand
|
|
1020
|
+
// (e.g. paths / pipelines / checks / audit / ownership) are handler-less
|
|
1021
|
+
// group nodes — they resolve live yet never appear in list(), so the
|
|
1022
|
+
// doctor reported "No issues" while those groups had zero catalog
|
|
1023
|
+
// coverage. Walk listGroups() and flag any group no catalog entry
|
|
1024
|
+
// covers. Pure alias groups (listGroupAliases) are skipped — their
|
|
1025
|
+
// canonical target carries the entry.
|
|
1026
|
+
const aliasGroups = new Set(registry.listGroupAliases().keys());
|
|
1027
|
+
const catalogTopWords = new Set();
|
|
1028
|
+
for (const e of COMMAND_CATALOG) {
|
|
1029
|
+
const top = e.command.split(/\s+/)[0];
|
|
1030
|
+
if (top)
|
|
1031
|
+
catalogTopWords.add(top);
|
|
1032
|
+
}
|
|
1033
|
+
for (const g of registry.listGroups()) {
|
|
1034
|
+
if (aliasGroups.has(g))
|
|
1035
|
+
continue;
|
|
1036
|
+
if (!catalogTopWords.has(g)) {
|
|
1037
|
+
issues.push({
|
|
1038
|
+
code: 'missing-catalog-entry',
|
|
1039
|
+
message: `command group "${g}" is registered (registerSubcommand) but no catalog entry covers it`,
|
|
1040
|
+
severity: 'error',
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
885
1044
|
}
|
|
886
1045
|
const errors = issues.filter((i) => i.severity === 'error').length;
|
|
887
1046
|
const warnings = issues.filter((i) => i.severity === 'warning').length;
|
|
@@ -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;AAqEhC,eAAO,MAAM,eAAe,EAAE,eAoG7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,eA4B3B,CAAC"}
|
|
@@ -5,6 +5,35 @@ 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
|
+
// `--type` accepts the EContentType wire strings plus ergonomic aliases. `code`
|
|
9
|
+
// is an alias for `source-code`: it routes to the structure-preserving code
|
|
10
|
+
// outline (ECompressionStrategy.Code), NOT the markdown line-omission a bare
|
|
11
|
+
// `code` used to silently fall through to under auto-detect.
|
|
12
|
+
const TYPE_ALIASES = {
|
|
13
|
+
code: EContentType.SourceCode,
|
|
14
|
+
};
|
|
15
|
+
// The full set of accepted `--type` tokens (content-type wire strings +
|
|
16
|
+
// aliases), sorted and rendered once so the rejection message and the
|
|
17
|
+
// passthrough hint advertise exactly what `resolveContentType` accepts.
|
|
18
|
+
const VALID_TYPE_TOKENS = [...CONTENT_TYPES, ...Object.keys(TYPE_ALIASES)].sort().join(', ');
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a raw `--type` value into a forced {@link EContentType}. Unlike the
|
|
21
|
+
* old `CONTENT_TYPES.has` check — which silently dropped unknown values and let
|
|
22
|
+
* the phantom `code` fall through to auto-detect (markdown line-omission) — an
|
|
23
|
+
* unrecognized non-empty value yields an `error` so the caller can reject with a
|
|
24
|
+
* non-zero exit, and `code` is mapped to the real source-code strategy. A
|
|
25
|
+
* missing/empty value is a no-op (auto-detect).
|
|
26
|
+
*/
|
|
27
|
+
function resolveContentType(raw) {
|
|
28
|
+
if (raw === undefined || raw === '')
|
|
29
|
+
return {};
|
|
30
|
+
const aliased = TYPE_ALIASES[raw];
|
|
31
|
+
if (aliased)
|
|
32
|
+
return { type: aliased };
|
|
33
|
+
if (CONTENT_TYPES.has(raw))
|
|
34
|
+
return { type: raw };
|
|
35
|
+
return { error: `compress: unknown --type "${raw}". Valid types: ${VALID_TYPE_TOKENS}.` };
|
|
36
|
+
}
|
|
8
37
|
// Below this size a passthrough no-op isn't worth a warning (tiny snippets
|
|
9
38
|
// legitimately have nothing to compress). Above it, a silent `−0%` re-emit is
|
|
10
39
|
// the opposite of the tool's purpose — nudge the user toward `--type`.
|
|
@@ -36,6 +65,13 @@ export const compressCommand = {
|
|
|
36
65
|
booleanFlags: COMPRESS_BOOLEAN_FLAGS,
|
|
37
66
|
run(args) {
|
|
38
67
|
const cwd = resolveCwd(args);
|
|
68
|
+
// Validate `--type` up front: an unknown value is a user error, not a
|
|
69
|
+
// silent fall-through to auto-detect — fail fast before reading input.
|
|
70
|
+
const resolvedType = resolveContentType(flagString(args, 'type'));
|
|
71
|
+
if (resolvedType.error) {
|
|
72
|
+
process.stderr.write(resolvedType.error + '\n');
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
39
75
|
let content;
|
|
40
76
|
try {
|
|
41
77
|
content = readInput(args);
|
|
@@ -59,9 +95,8 @@ export const compressCommand = {
|
|
|
59
95
|
opts.maxItems = Math.floor(max);
|
|
60
96
|
if (flagBool(args, 'lossless'))
|
|
61
97
|
opts.lossless = true;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
opts.contentType = type;
|
|
98
|
+
if (resolvedType.type)
|
|
99
|
+
opts.contentType = resolvedType.type;
|
|
65
100
|
const result = compressContent(content, opts);
|
|
66
101
|
const pct = Math.round(result.savings.ratio * 100);
|
|
67
102
|
// A lossy result with no cached original (i.e. --no-cache) can't be undone
|
|
@@ -109,7 +144,7 @@ export const compressCommand = {
|
|
|
109
144
|
inputBytes >= PASSTHROUGH_HINT_MIN_BYTES &&
|
|
110
145
|
!flagBool(args, 'lossless')) {
|
|
111
146
|
process.stderr.write(`hint: nothing was compressed — auto-detect classified this as ${result.contentType} and found no win. ` +
|
|
112
|
-
|
|
147
|
+
`Try \`--type <content-type>\` to force a strategy (${VALID_TYPE_TOKENS}).\n`);
|
|
113
148
|
}
|
|
114
149
|
return 0;
|
|
115
150
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.command.d.ts","sourceRoot":"","sources":["../../src/commands/context.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAgChC,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"context.command.d.ts","sourceRoot":"","sources":["../../src/commands/context.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAgChC,eAAO,MAAM,cAAc,EAAE,eA2I5B,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { entrypointBanner, inspectSharkcraft } from '@shrkcrft/inspector';
|
|
1
|
+
import { contextTuningBoostFor, entrypointBanner, inspectSharkcraft } from '@shrkcrft/inspector';
|
|
2
2
|
import { buildContext } from '@shrkcrft/context';
|
|
3
3
|
import { loadIntentBenchmark, runIntentBenchmark, STARTER_INTENT_BENCHMARK, writeBenchmarkRun, } from '@shrkcrft/context-planner';
|
|
4
4
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
@@ -67,6 +67,7 @@ export const contextCommand = {
|
|
|
67
67
|
const includeCommands = flagBool(args, 'include-commands');
|
|
68
68
|
const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
|
|
69
69
|
const overview = buildProjectOverview(inspection.workspace, inspection.config?.projectName);
|
|
70
|
+
const contextBoost = contextTuningBoostFor(inspection, task);
|
|
70
71
|
const result = buildContext(inspection.knowledgeEntries, {
|
|
71
72
|
task,
|
|
72
73
|
framework,
|
|
@@ -81,6 +82,7 @@ export const contextCommand = {
|
|
|
81
82
|
includeDocs,
|
|
82
83
|
includeCommands,
|
|
83
84
|
projectOverview: renderOverviewText(overview),
|
|
85
|
+
...(contextBoost ? { boostFor: contextBoost } : {}),
|
|
84
86
|
});
|
|
85
87
|
// Surface top commands prominently before the long context body.
|
|
86
88
|
// Auto-promote commands-first for action-like tasks (rename / add /
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daily.commands.d.ts","sourceRoot":"","sources":["../../src/commands/daily.commands.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAMhC,eAAO,MAAM,WAAW,EAAE,eAsFzB,CAAC;AAcF,eAAO,MAAM,WAAW,EAAE,eAoGzB,CAAC;AAKF,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"daily.commands.d.ts","sourceRoot":"","sources":["../../src/commands/daily.commands.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAMhC,eAAO,MAAM,WAAW,EAAE,eAsFzB,CAAC;AAcF,eAAO,MAAM,WAAW,EAAE,eAoGzB,CAAC;AAKF,eAAO,MAAM,cAAc,EAAE,eAyG5B,CAAC"}
|
|
@@ -186,14 +186,33 @@ export const explainCommand = {
|
|
|
186
186
|
const top = inspection.knowledgeEntries
|
|
187
187
|
.filter((e) => matches(topic, e.id, e.title, e.content, e.tags.join(' ')))
|
|
188
188
|
.slice(0, maxEntries);
|
|
189
|
+
// Surface the matched items themselves, not just counts. `explain`
|
|
190
|
+
// otherwise duplicates `shrk search`'s job while hiding what matched.
|
|
191
|
+
const relevantRules = packet.relevantRules.map((r) => ({
|
|
192
|
+
id: r.id,
|
|
193
|
+
title: r.title,
|
|
194
|
+
priority: r.priority,
|
|
195
|
+
}));
|
|
196
|
+
const relevantPaths = packet.relevantPaths.map((p) => ({
|
|
197
|
+
id: p.id,
|
|
198
|
+
title: p.title,
|
|
199
|
+
priority: p.priority,
|
|
200
|
+
}));
|
|
201
|
+
const relevantTemplates = packet.relevantTemplates.map((t) => ({
|
|
202
|
+
id: t.id,
|
|
203
|
+
name: t.name,
|
|
204
|
+
}));
|
|
189
205
|
if (flagBool(args, 'json')) {
|
|
190
206
|
process.stdout.write(asJson({
|
|
191
207
|
topic,
|
|
192
208
|
summary: {
|
|
193
|
-
relevantRules:
|
|
194
|
-
relevantPaths:
|
|
195
|
-
relevantTemplates:
|
|
209
|
+
relevantRules: relevantRules.length,
|
|
210
|
+
relevantPaths: relevantPaths.length,
|
|
211
|
+
relevantTemplates: relevantTemplates.length,
|
|
196
212
|
},
|
|
213
|
+
relevantRules,
|
|
214
|
+
relevantPaths,
|
|
215
|
+
relevantTemplates,
|
|
197
216
|
entries: top.map((e) => ({
|
|
198
217
|
id: e.id,
|
|
199
218
|
title: e.title,
|
|
@@ -205,11 +224,35 @@ export const explainCommand = {
|
|
|
205
224
|
return 0;
|
|
206
225
|
}
|
|
207
226
|
process.stdout.write(header(`explain: ${topic}`));
|
|
208
|
-
process.stdout.write(kv('matches', `rules=${
|
|
227
|
+
process.stdout.write(kv('matches', `rules=${relevantRules.length} paths=${relevantPaths.length} templates=${relevantTemplates.length}`) + '\n\n');
|
|
228
|
+
if (relevantRules.length > 0) {
|
|
229
|
+
process.stdout.write('Rules:\n');
|
|
230
|
+
for (const r of relevantRules) {
|
|
231
|
+
process.stdout.write(` • [${r.priority}] ${r.id} — ${r.title}\n`);
|
|
232
|
+
}
|
|
233
|
+
process.stdout.write('\n');
|
|
234
|
+
}
|
|
235
|
+
if (relevantPaths.length > 0) {
|
|
236
|
+
process.stdout.write('Paths:\n');
|
|
237
|
+
for (const p of relevantPaths) {
|
|
238
|
+
process.stdout.write(` • [${p.priority}] ${p.id} — ${p.title}\n`);
|
|
239
|
+
}
|
|
240
|
+
process.stdout.write('\n');
|
|
241
|
+
}
|
|
242
|
+
if (relevantTemplates.length > 0) {
|
|
243
|
+
process.stdout.write('Templates:\n');
|
|
244
|
+
for (const t of relevantTemplates) {
|
|
245
|
+
process.stdout.write(` • ${t.id} — ${t.name}\n`);
|
|
246
|
+
}
|
|
247
|
+
process.stdout.write('\n');
|
|
248
|
+
}
|
|
209
249
|
if (top.length === 0) {
|
|
210
|
-
|
|
250
|
+
if (relevantRules.length + relevantPaths.length + relevantTemplates.length === 0) {
|
|
251
|
+
process.stdout.write('(no matching knowledge entries)\n');
|
|
252
|
+
}
|
|
211
253
|
return 0;
|
|
212
254
|
}
|
|
255
|
+
process.stdout.write('Knowledge:\n');
|
|
213
256
|
for (const e of top) {
|
|
214
257
|
process.stdout.write(`• [${e.priority}] ${e.id} — ${e.title}\n`);
|
|
215
258
|
const body = e.content
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-check.command.d.ts","sourceRoot":"","sources":["../../src/commands/diff-check.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAcH,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"diff-check.command.d.ts","sourceRoot":"","sources":["../../src/commands/diff-check.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAcH,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA6GhC,eAAO,MAAM,gBAAgB,EAAE,eAkI9B,CAAC"}
|
|
@@ -34,9 +34,12 @@ function resolveScope(args, cwd) {
|
|
|
34
34
|
const staged = flagBool(args, 'staged');
|
|
35
35
|
const since = flagString(args, 'since');
|
|
36
36
|
const filesRaw = flagString(args, 'files');
|
|
37
|
+
// Files come from `--files a,b` or as bare positional args
|
|
38
|
+
// (`shrk diff-check a.ts b.ts`). Positionals were previously ignored, which
|
|
39
|
+
// silently widened the scope back to the full worktree.
|
|
37
40
|
const files = filesRaw
|
|
38
41
|
? filesRaw.split(',').map((s) => s.trim()).filter((s) => s.length > 0)
|
|
39
|
-
:
|
|
42
|
+
: args.positional.filter((s) => s.length > 0);
|
|
40
43
|
if (files.length > 0) {
|
|
41
44
|
return { mode: 'files', options: { projectRoot: cwd, files } };
|
|
42
45
|
}
|
|
@@ -97,7 +100,8 @@ function deriveVerdict(env) {
|
|
|
97
100
|
export const diffCheckCommand = {
|
|
98
101
|
name: 'diff-check',
|
|
99
102
|
description: 'Self-check the current git diff against this project\'s boundary + import-hygiene rules. Single-call composite of `shrk check boundaries --changed-only` + `shrk check imports --changed-only`, with one verdict and one nextAction line. Designed for AI agents to run after editing — pass --json for the structured envelope.',
|
|
100
|
-
usage: 'shrk [--cwd <dir>] diff-check [
|
|
103
|
+
usage: 'shrk [--cwd <dir>] diff-check [files... | --files a.ts,b.ts | --staged | --since <ref>] [--json]',
|
|
104
|
+
booleanFlags: new Set(['json', 'staged']),
|
|
101
105
|
async run(args) {
|
|
102
106
|
const cwd = resolveCwd(args);
|
|
103
107
|
const wantJson = flagBool(args, 'json');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feedback.command.d.ts","sourceRoot":"","sources":["../../src/commands/feedback.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"feedback.command.d.ts","sourceRoot":"","sources":["../../src/commands/feedback.command.ts"],"names":[],"mappings":"AAiBA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAiBhC,eAAO,MAAM,qBAAqB,EAAE,eAiCnC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eA0CtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAyDpC,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,eAwB7C,CAAC;AAIF,eAAO,MAAM,wBAAwB,EAAE,eAqBtC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eAoDxC,CAAC;AAGF,eAAO,MAAM,sBAAsB,EAAE,eAqBpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eA6BjC,CAAC"}
|
|
@@ -10,6 +10,7 @@ import * as nodePath from 'node:path';
|
|
|
10
10
|
import { FeedbackBucket, ingestFeedbackFile, inspectSharkcraft, loadFeedbackRules, renderFeedbackBacklog, } from '@shrkcrft/inspector';
|
|
11
11
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
12
12
|
import { asJson, header } from "../output/format-output.js";
|
|
13
|
+
import { feedbackRulesDoctorHints, renderFailureHints } from "../output/failure-hints.js";
|
|
13
14
|
function ingestPositional(args) {
|
|
14
15
|
return args.positional[0];
|
|
15
16
|
}
|
|
@@ -256,6 +257,9 @@ export const feedbackRulesDoctorCommand = {
|
|
|
256
257
|
process.stdout.write(` ERROR ${e.id}: ${e.message}\n`);
|
|
257
258
|
for (const w of warnings)
|
|
258
259
|
process.stdout.write(` WARN ${w.id}: ${w.message}\n`);
|
|
260
|
+
if (errors.length > 0) {
|
|
261
|
+
process.stdout.write(renderFailureHints(feedbackRulesDoctorHints()));
|
|
262
|
+
}
|
|
259
263
|
return errors.length > 0 ? 1 : 0;
|
|
260
264
|
},
|
|
261
265
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework.command.d.ts","sourceRoot":"","sources":["../../src/commands/framework.command.ts"],"names":[],"mappings":"AAOA,OAAO,
|
|
1
|
+
{"version":3,"file":"framework.command.d.ts","sourceRoot":"","sources":["../../src/commands/framework.command.ts"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAIhC;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAe9B,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { buildRegistryWithPacks, defaultRegistry, FrameworkQueryApi, runExtractors, } from '@shrkcrft/framework-scanners';
|
|
2
2
|
import { inspectSharkcraft } from '@shrkcrft/inspector';
|
|
3
|
-
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
3
|
+
import { flagBool, flagPositiveInt, flagString, resolveCwd, } from "../command-registry.js";
|
|
4
4
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
5
|
+
import { computeMtimeFreshness } from "../status/freshness.js";
|
|
5
6
|
/**
|
|
6
7
|
* `shrk framework` — run / inspect the framework-aware extractors.
|
|
7
8
|
*
|
|
@@ -109,8 +110,20 @@ async function runStatus(args) {
|
|
|
109
110
|
}
|
|
110
111
|
const api = FrameworkQueryApi.fromStore(cwd);
|
|
111
112
|
const m = api.manifest();
|
|
113
|
+
// Honest freshness: the framework store is stale once a source file changed
|
|
114
|
+
// after it was built. Mirror the `state + lastBuiltAt + drift` shape that
|
|
115
|
+
// `graph status` exposes.
|
|
116
|
+
const fresh = computeMtimeFreshness(cwd, m.lastBuiltAt);
|
|
112
117
|
if (wantJson) {
|
|
113
|
-
process.stdout.write(asJson({
|
|
118
|
+
process.stdout.write(asJson({
|
|
119
|
+
ok: true,
|
|
120
|
+
state: fresh.state,
|
|
121
|
+
lastBuiltAt: m.lastBuiltAt,
|
|
122
|
+
lastChangedAt: fresh.lastChangedAt,
|
|
123
|
+
behindMs: fresh.behindMs,
|
|
124
|
+
...(fresh.state === 'stale' ? { nextCommand: 'shrk framework index' } : {}),
|
|
125
|
+
manifest: m,
|
|
126
|
+
}) + '\n');
|
|
114
127
|
return 0;
|
|
115
128
|
}
|
|
116
129
|
process.stdout.write(header('Framework status'));
|
|
@@ -120,6 +133,10 @@ async function runStatus(args) {
|
|
|
120
133
|
process.stdout.write(kv(` ${k}`, String(v)) + '\n');
|
|
121
134
|
}
|
|
122
135
|
process.stdout.write(kv('last built', m.lastBuiltAt) + '\n');
|
|
136
|
+
process.stdout.write(kv('state', fresh.state) + '\n');
|
|
137
|
+
if (fresh.state === 'stale') {
|
|
138
|
+
process.stdout.write(`! stale — source changed since last build${fresh.lastChangedAt ? ` (last change ${fresh.lastChangedAt})` : ''}; re-run \`shrk framework index\`\n`);
|
|
139
|
+
}
|
|
123
140
|
return 0;
|
|
124
141
|
}
|
|
125
142
|
async function runList(args) {
|
|
@@ -134,7 +151,7 @@ async function runList(args) {
|
|
|
134
151
|
const framework = flagString(args, 'framework');
|
|
135
152
|
const subtype = flagString(args, 'subtype');
|
|
136
153
|
const file = flagString(args, 'file');
|
|
137
|
-
const limit =
|
|
154
|
+
const limit = flagPositiveInt(args, 'limit', 50);
|
|
138
155
|
const entities = api.list({
|
|
139
156
|
...(framework ? { framework } : {}),
|
|
140
157
|
...(subtype ? { subtype } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/gate.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/gate.command.ts"],"names":[],"mappings":"AAaA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,eAiMzB,CAAC"}
|