@shrkcrft/cli 0.1.0-alpha.2 → 0.1.0-alpha.21
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/audit/knowledge-audit-llm.d.ts +19 -0
- package/dist/audit/knowledge-audit-llm.d.ts.map +1 -0
- package/dist/audit/knowledge-audit-llm.js +164 -0
- package/dist/audit/knowledge-audit.d.ts +61 -0
- package/dist/audit/knowledge-audit.d.ts.map +1 -0
- package/dist/audit/knowledge-audit.js +203 -0
- package/dist/audit/knowledge-fix-plan-llm.d.ts +11 -0
- package/dist/audit/knowledge-fix-plan-llm.d.ts.map +1 -0
- package/dist/audit/knowledge-fix-plan-llm.js +141 -0
- package/dist/audit/knowledge-fix-plan.d.ts +41 -0
- package/dist/audit/knowledge-fix-plan.d.ts.map +1 -0
- package/dist/audit/knowledge-fix-plan.js +125 -0
- package/dist/audit/pipeline-audit-llm.d.ts +11 -0
- package/dist/audit/pipeline-audit-llm.d.ts.map +1 -0
- package/dist/audit/pipeline-audit-llm.js +134 -0
- package/dist/audit/pipeline-audit.d.ts +69 -0
- package/dist/audit/pipeline-audit.d.ts.map +1 -0
- package/dist/audit/pipeline-audit.js +166 -0
- package/dist/audit/templates-audit-llm.d.ts +19 -0
- package/dist/audit/templates-audit-llm.d.ts.map +1 -0
- package/dist/audit/templates-audit-llm.js +207 -0
- package/dist/audit/templates-audit.d.ts +63 -0
- package/dist/audit/templates-audit.d.ts.map +1 -0
- package/dist/audit/templates-audit.js +171 -0
- package/dist/audit/templates-fix-plan-llm.d.ts +19 -0
- package/dist/audit/templates-fix-plan-llm.d.ts.map +1 -0
- package/dist/audit/templates-fix-plan-llm.js +162 -0
- package/dist/audit/templates-fix-plan.d.ts +37 -0
- package/dist/audit/templates-fix-plan.d.ts.map +1 -0
- package/dist/audit/templates-fix-plan.js +174 -0
- package/dist/command-registry.d.ts +28 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +91 -1
- package/dist/commands/ai-status.command.d.ts +19 -0
- package/dist/commands/ai-status.command.d.ts.map +1 -0
- package/dist/commands/ai-status.command.js +94 -0
- package/dist/commands/api-diff.command.d.ts +11 -0
- package/dist/commands/api-diff.command.d.ts.map +1 -0
- package/dist/commands/api-diff.command.js +144 -0
- package/dist/commands/apply.command.d.ts.map +1 -1
- package/dist/commands/apply.command.js +10 -2
- package/dist/commands/arch.command.d.ts +9 -0
- package/dist/commands/arch.command.d.ts.map +1 -0
- package/dist/commands/arch.command.js +186 -0
- package/dist/commands/ask.command.d.ts.map +1 -1
- package/dist/commands/ask.command.js +10 -9
- package/dist/commands/cache-align.command.d.ts +12 -0
- package/dist/commands/cache-align.command.d.ts.map +1 -0
- package/dist/commands/cache-align.command.js +78 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +26 -2
- package/dist/commands/code-intel.command.d.ts +18 -0
- package/dist/commands/code-intel.command.d.ts.map +1 -0
- package/dist/commands/code-intel.command.js +146 -0
- package/dist/commands/codemod.command.d.ts.map +1 -1
- package/dist/commands/codemod.command.js +27 -6
- package/dist/commands/command-catalog.d.ts +15 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +407 -34
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/completion.command.d.ts +10 -0
- package/dist/commands/completion.command.d.ts.map +1 -0
- package/dist/commands/completion.command.js +121 -0
- package/dist/commands/compress.command.d.ts +8 -0
- package/dist/commands/compress.command.d.ts.map +1 -0
- package/dist/commands/compress.command.js +147 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +89 -23
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +121 -1
- package/dist/commands/contract-gate.command.d.ts.map +1 -1
- package/dist/commands/contract-gate.command.js +5 -1
- package/dist/commands/delegate.command.d.ts +65 -0
- package/dist/commands/delegate.command.d.ts.map +1 -0
- package/dist/commands/delegate.command.js +657 -0
- package/dist/commands/deps-audit.command.d.ts +23 -0
- package/dist/commands/deps-audit.command.d.ts.map +1 -0
- package/dist/commands/deps-audit.command.js +270 -0
- package/dist/commands/dev.command.d.ts.map +1 -1
- package/dist/commands/dev.command.js +5 -2
- package/dist/commands/diff-check.command.d.ts +30 -0
- package/dist/commands/diff-check.command.d.ts.map +1 -0
- package/dist/commands/diff-check.command.js +210 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +162 -10
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/framework.command.d.ts +12 -0
- package/dist/commands/framework.command.d.ts.map +1 -0
- package/dist/commands/framework.command.js +180 -0
- package/dist/commands/gate.command.d.ts +15 -0
- package/dist/commands/gate.command.d.ts.map +1 -0
- package/dist/commands/gate.command.js +300 -0
- package/dist/commands/gen.command.d.ts.map +1 -1
- package/dist/commands/gen.command.js +13 -1
- package/dist/commands/graph-code-subverbs.d.ts +33 -0
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
- package/dist/commands/graph-code-subverbs.js +1385 -0
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +31 -2
- package/dist/commands/help.command.d.ts +4 -3
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +86 -18
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +171 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/ingest.command.d.ts.map +1 -1
- package/dist/commands/ingest.command.js +5 -1
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +174 -7
- package/dist/commands/knowledge-author.command.d.ts.map +1 -1
- package/dist/commands/knowledge-author.command.js +9 -0
- package/dist/commands/knowledge-propose.command.d.ts.map +1 -1
- package/dist/commands/knowledge-propose.command.js +4 -2
- package/dist/commands/knowledge.command.d.ts.map +1 -1
- package/dist/commands/knowledge.command.js +26 -3
- package/dist/commands/migrate.command.d.ts +13 -0
- package/dist/commands/migrate.command.d.ts.map +1 -0
- package/dist/commands/migrate.command.js +152 -0
- package/dist/commands/move-plan.command.d.ts +23 -0
- package/dist/commands/move-plan.command.d.ts.map +1 -0
- package/dist/commands/move-plan.command.js +360 -0
- package/dist/commands/packs-new.d.ts +1 -1
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +5 -36
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +2 -10
- package/dist/commands/plan-context.command.d.ts +11 -0
- package/dist/commands/plan-context.command.d.ts.map +1 -0
- package/dist/commands/plan-context.command.js +85 -0
- package/dist/commands/preflight.command.d.ts.map +1 -1
- package/dist/commands/preflight.command.js +15 -0
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/recommend.command.d.ts +6 -0
- package/dist/commands/recommend.command.d.ts.map +1 -1
- package/dist/commands/recommend.command.js +119 -5
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/rule-graph-subverbs.d.ts +3 -0
- package/dist/commands/rule-graph-subverbs.d.ts.map +1 -0
- package/dist/commands/rule-graph-subverbs.js +132 -0
- package/dist/commands/rules.command.d.ts.map +1 -1
- package/dist/commands/rules.command.js +20 -3
- package/dist/commands/scaffold-validate.command.d.ts +22 -0
- package/dist/commands/scaffold-validate.command.d.ts.map +1 -0
- package/dist/commands/scaffold-validate.command.js +215 -0
- package/dist/commands/search-structural.command.d.ts +18 -0
- package/dist/commands/search-structural.command.d.ts.map +1 -0
- package/dist/commands/search-structural.command.js +376 -0
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/smart-context.command.d.ts +67 -0
- package/dist/commands/smart-context.command.d.ts.map +1 -0
- package/dist/commands/smart-context.command.js +4728 -0
- package/dist/commands/spike.command.d.ts +22 -0
- package/dist/commands/spike.command.d.ts.map +1 -0
- package/dist/commands/spike.command.js +235 -0
- package/dist/commands/surface.command.d.ts +1 -0
- package/dist/commands/surface.command.d.ts.map +1 -1
- package/dist/commands/surface.command.js +10 -3
- package/dist/commands/task-context.command.d.ts.map +1 -1
- package/dist/commands/task-context.command.js +5 -17
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +8 -2
- package/dist/commands/template-quality.command.d.ts.map +1 -1
- package/dist/commands/template-quality.command.js +39 -3
- package/dist/commands/templates.command.d.ts.map +1 -1
- package/dist/commands/templates.command.js +37 -2
- package/dist/commands/tests.command.d.ts.map +1 -1
- package/dist/commands/tests.command.js +13 -2
- package/dist/commands/watch.command.d.ts +26 -0
- package/dist/commands/watch.command.d.ts.map +1 -0
- package/dist/commands/watch.command.js +456 -0
- package/dist/dashboard/code-intelligence-data.d.ts +33 -0
- package/dist/dashboard/code-intelligence-data.d.ts.map +1 -0
- package/dist/dashboard/code-intelligence-data.js +329 -0
- package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
- package/dist/dashboard/dashboard-api-server.js +256 -2
- package/dist/dashboard/knowledge-ask.d.ts +4 -0
- package/dist/dashboard/knowledge-ask.d.ts.map +1 -0
- package/dist/dashboard/knowledge-ask.js +112 -0
- package/dist/env/load-dotenv.d.ts +15 -0
- package/dist/env/load-dotenv.d.ts.map +1 -0
- package/dist/env/load-dotenv.js +70 -0
- package/dist/export/claude-commands-export.d.ts +60 -0
- package/dist/export/claude-commands-export.d.ts.map +1 -0
- package/dist/export/claude-commands-export.js +276 -0
- package/dist/export/export-formats.d.ts +1 -1
- package/dist/export/export-formats.d.ts.map +1 -1
- package/dist/export/export-formats.js +139 -12
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/init/init-templates.d.ts.map +1 -1
- package/dist/init/init-templates.js +133 -113
- package/dist/init/paths-advisory.d.ts +20 -0
- package/dist/init/paths-advisory.d.ts.map +1 -0
- package/dist/init/paths-advisory.js +88 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +331 -17
- package/dist/output/ccr-store-config.d.ts +18 -0
- package/dist/output/ccr-store-config.d.ts.map +1 -0
- package/dist/output/ccr-store-config.js +41 -0
- package/dist/output/format-output.d.ts.map +1 -1
- package/dist/output/format-output.js +6 -1
- package/dist/output/output-compression.d.ts +15 -0
- package/dist/output/output-compression.d.ts.map +1 -0
- package/dist/output/output-compression.js +60 -0
- package/dist/output/resolve-compress-type.d.ts +22 -0
- package/dist/output/resolve-compress-type.d.ts.map +1 -0
- package/dist/output/resolve-compress-type.js +21 -0
- package/dist/output/watch-loop.d.ts +9 -1
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +13 -3
- package/dist/schemas/json-schemas.d.ts +384 -36
- package/dist/schemas/json-schemas.d.ts.map +1 -1
- package/dist/schemas/json-schemas.js +247 -36
- package/dist/surface/profiles.d.ts.map +1 -1
- package/dist/surface/profiles.js +54 -10
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +23 -11
- package/dist/validation/run-validation-loop.d.ts.map +1 -1
- package/dist/validation/run-validation-loop.js +5 -1
- package/package.json +35 -21
- package/dist/commands/plugin.command.d.ts +0 -11
- package/dist/commands/plugin.command.d.ts.map +0 -1
- package/dist/commands/plugin.command.js +0 -394
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { flagBool, flagString
|
|
1
|
+
import { flagBool, flagString } from "../command-registry.js";
|
|
2
2
|
import { asJson, header } from "../output/format-output.js";
|
|
3
|
-
import { COMMAND_CATALOG, CommandLifecycle,
|
|
4
|
-
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText
|
|
3
|
+
import { buildCommandSafetyMatrix, COMMAND_CATALOG, CommandLifecycle, commandLifecycle, CommandSurface, commandSurface, commandTaskRole, defaultShowInHelp, R46_OVERLAY, renderCommandSafetyMatrixMarkdown, SafetyLevel } from "./command-catalog.js";
|
|
4
|
+
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText } from '@shrkcrft/inspector';
|
|
5
5
|
export function makeCommandsCommand(registry) {
|
|
6
6
|
return {
|
|
7
7
|
name: 'commands',
|
|
@@ -589,7 +589,7 @@ export function buildCommandsUxReport() {
|
|
|
589
589
|
// issue is clearly structural (none of these currently rise to error).
|
|
590
590
|
for (const e of COMMAND_CATALOG) {
|
|
591
591
|
const surface = commandSurface(e);
|
|
592
|
-
// (a) primary commands should declare an audience (so
|
|
592
|
+
// (a) primary commands should declare an audience (so consumers can see
|
|
593
593
|
// who the command is for at a glance).
|
|
594
594
|
if (surface === CommandSurface.Primary && (!e.intendedAudience || e.intendedAudience.length === 0)) {
|
|
595
595
|
issues.push({
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
+
/**
|
|
3
|
+
* `shrk completion <bash|zsh|fish>` — print a sourcable completion
|
|
4
|
+
* script. The list of verbs is generated from the registered
|
|
5
|
+
* `COMMAND_CATALOG` so completion can't drift from the runtime
|
|
6
|
+
* surface. Subverbs for the high-traffic groups (graph, arch,
|
|
7
|
+
* impact, gate, context, search-structural) are hand-curated.
|
|
8
|
+
*/
|
|
9
|
+
export declare const completionCommand: ICommandHandler;
|
|
10
|
+
//# sourceMappingURL=completion.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.command.d.ts","sourceRoot":"","sources":["../../src/commands/completion.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAIhC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAqC/B,CAAC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { flagBool, flagString, } from "../command-registry.js";
|
|
2
|
+
import { asJson } from "../output/format-output.js";
|
|
3
|
+
import { COMMAND_CATALOG } from "./command-catalog.js";
|
|
4
|
+
/**
|
|
5
|
+
* `shrk completion <bash|zsh|fish>` — print a sourcable completion
|
|
6
|
+
* script. The list of verbs is generated from the registered
|
|
7
|
+
* `COMMAND_CATALOG` so completion can't drift from the runtime
|
|
8
|
+
* surface. Subverbs for the high-traffic groups (graph, arch,
|
|
9
|
+
* impact, gate, context, search-structural) are hand-curated.
|
|
10
|
+
*/
|
|
11
|
+
export const completionCommand = {
|
|
12
|
+
name: 'completion',
|
|
13
|
+
description: 'Print a sourcable shell-completion script for the `shrk` CLI. Pipe into your shell rc: `shrk completion bash >> ~/.bashrc`.',
|
|
14
|
+
usage: 'shrk completion <bash|zsh|fish> [--json]',
|
|
15
|
+
async run(args) {
|
|
16
|
+
const shell = (args.positional[0] ?? flagString(args, 'shell') ?? 'bash').toLowerCase();
|
|
17
|
+
const wantJson = flagBool(args, 'json');
|
|
18
|
+
const verbs = collectTopLevelVerbs();
|
|
19
|
+
if (wantJson) {
|
|
20
|
+
process.stdout.write(asJson({
|
|
21
|
+
schema: 'sharkcraft.cli-completion/v1',
|
|
22
|
+
shell,
|
|
23
|
+
verbs,
|
|
24
|
+
subverbs: SUBVERBS,
|
|
25
|
+
}) + '\n');
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
switch (shell) {
|
|
29
|
+
case 'bash':
|
|
30
|
+
process.stdout.write(renderBash(verbs));
|
|
31
|
+
return 0;
|
|
32
|
+
case 'zsh':
|
|
33
|
+
process.stdout.write(renderZsh(verbs));
|
|
34
|
+
return 0;
|
|
35
|
+
case 'fish':
|
|
36
|
+
process.stdout.write(renderFish(verbs));
|
|
37
|
+
return 0;
|
|
38
|
+
default:
|
|
39
|
+
process.stderr.write(`Unknown shell "${shell}". Use bash | zsh | fish.\n`);
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Subverbs the high-traffic verbs accept. Hand-curated because the
|
|
46
|
+
* runtime catalog represents them as a single CLI surface; we don't
|
|
47
|
+
* want to parse the dispatch chain at completion time.
|
|
48
|
+
*/
|
|
49
|
+
const SUBVERBS = Object.freeze({
|
|
50
|
+
graph: ['index', 'status', 'search', 'context', 'impact', 'callers', 'cycles', 'unresolved', 'deps', 'why', 'export'],
|
|
51
|
+
arch: ['check', 'baseline'],
|
|
52
|
+
impact: ['tests', 'graph', 'baseline'],
|
|
53
|
+
gate: ['scaffold-ci', 'scaffold-hook'],
|
|
54
|
+
context: ['build', 'refresh', 'status', 'benchmark'],
|
|
55
|
+
'search-structural': ['registry'],
|
|
56
|
+
doctor: ['suppress', 'suppressions', 'acknowledge', 'acknowledgements', 'watch'],
|
|
57
|
+
});
|
|
58
|
+
function collectTopLevelVerbs() {
|
|
59
|
+
const set = new Set();
|
|
60
|
+
for (const e of COMMAND_CATALOG) {
|
|
61
|
+
// `command` may carry an argument hint like 'fix preview' — keep
|
|
62
|
+
// only the first token so completion works at the top level.
|
|
63
|
+
const head = e.command.split(/\s+/)[0];
|
|
64
|
+
if (head.length > 0)
|
|
65
|
+
set.add(head);
|
|
66
|
+
}
|
|
67
|
+
return [...set].sort();
|
|
68
|
+
}
|
|
69
|
+
function renderBash(verbs) {
|
|
70
|
+
const verbList = verbs.join(' ');
|
|
71
|
+
const subverbCases = Object.entries(SUBVERBS)
|
|
72
|
+
.map(([verb, subs]) => ` ${verb}) COMPREPLY=($(compgen -W "${subs.join(' ')}" -- "$cur")); return 0;;`)
|
|
73
|
+
.join('\n');
|
|
74
|
+
return `# shrk bash completion. Source from ~/.bashrc:
|
|
75
|
+
# eval "$(shrk completion bash)"
|
|
76
|
+
_shrk_complete() {
|
|
77
|
+
local cur prev words cword
|
|
78
|
+
_init_completion || return
|
|
79
|
+
if [ "$cword" -eq 1 ]; then
|
|
80
|
+
COMPREPLY=($(compgen -W "${verbList}" -- "$cur"))
|
|
81
|
+
return 0
|
|
82
|
+
fi
|
|
83
|
+
case "\${words[1]}" in
|
|
84
|
+
${subverbCases}
|
|
85
|
+
esac
|
|
86
|
+
COMPREPLY=()
|
|
87
|
+
}
|
|
88
|
+
complete -F _shrk_complete shrk
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
function renderZsh(verbs) {
|
|
92
|
+
const verbList = verbs.join(' ');
|
|
93
|
+
const subverbCases = Object.entries(SUBVERBS)
|
|
94
|
+
.map(([verb, subs]) => ` ${verb}) compadd -- ${subs.join(' ')};;`)
|
|
95
|
+
.join('\n');
|
|
96
|
+
return `# shrk zsh completion. Source from ~/.zshrc:
|
|
97
|
+
# eval "$(shrk completion zsh)"
|
|
98
|
+
_shrk() {
|
|
99
|
+
if [[ \${#words} -eq 2 ]]; then
|
|
100
|
+
compadd -- ${verbList}
|
|
101
|
+
return
|
|
102
|
+
fi
|
|
103
|
+
case "\${words[2]}" in
|
|
104
|
+
${subverbCases}
|
|
105
|
+
esac
|
|
106
|
+
}
|
|
107
|
+
compdef _shrk shrk
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
function renderFish(verbs) {
|
|
111
|
+
const lines = [
|
|
112
|
+
'# shrk fish completion. Source from ~/.config/fish/completions/shrk.fish:',
|
|
113
|
+
'# shrk completion fish > ~/.config/fish/completions/shrk.fish',
|
|
114
|
+
'complete -e -c shrk',
|
|
115
|
+
`complete -c shrk -n '__fish_use_subcommand' -a '${verbs.join(' ')}'`,
|
|
116
|
+
];
|
|
117
|
+
for (const [verb, subs] of Object.entries(SUBVERBS)) {
|
|
118
|
+
lines.push(`complete -c shrk -n '__fish_seen_subcommand_from ${verb}' -a '${subs.join(' ')}'`);
|
|
119
|
+
}
|
|
120
|
+
return lines.join('\n') + '\n';
|
|
121
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
+
export declare const compressCommand: ICommandHandler;
|
|
3
|
+
/**
|
|
4
|
+
* `shrk expand` — the retrieve half of CCR. Print the full original that
|
|
5
|
+
* `shrk compress` cached for a `<<ccr:KEY>>` key.
|
|
6
|
+
*/
|
|
7
|
+
export declare const expandCommand: ICommandHandler;
|
|
8
|
+
//# sourceMappingURL=compress.command.d.ts.map
|
|
@@ -0,0 +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;AAgChC,eAAO,MAAM,eAAe,EAAE,eA8F7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,eA4B3B,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
3
|
+
import { compressContent, ECompressionStrategy, EContentType, } from '@shrkcrft/compress';
|
|
4
|
+
import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-registry.js";
|
|
5
|
+
import { asJson } from "../output/format-output.js";
|
|
6
|
+
import { ccrDir, openCcrStore } from "../output/ccr-store-config.js";
|
|
7
|
+
const CONTENT_TYPES = new Set(Object.values(EContentType));
|
|
8
|
+
// Below this size a passthrough no-op isn't worth a warning (tiny snippets
|
|
9
|
+
// legitimately have nothing to compress). Above it, a silent `−0%` re-emit is
|
|
10
|
+
// the opposite of the tool's purpose — nudge the user toward `--type`.
|
|
11
|
+
const PASSTHROUGH_HINT_MIN_BYTES = 128;
|
|
12
|
+
function readInput(args) {
|
|
13
|
+
const positional = args.positional[0];
|
|
14
|
+
const useStdin = flagBool(args, 'stdin') || positional === undefined || positional === '-';
|
|
15
|
+
if (useStdin)
|
|
16
|
+
return readFileSync(0, 'utf8');
|
|
17
|
+
return readFileSync(positional, 'utf8');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* `shrk compress` — deterministically compress a blob (file or stdin) before
|
|
21
|
+
* it re-enters an agent prompt. Same information, fewer tokens. Lossy passes
|
|
22
|
+
* cache the original under `.sharkcraft/ccr/` so `shrk expand <key>` can get
|
|
23
|
+
* it back. The compressed text goes to stdout (pipeable); the savings summary
|
|
24
|
+
* goes to stderr unless `--json` is set.
|
|
25
|
+
*/
|
|
26
|
+
const COMPRESS_BOOLEAN_FLAGS = new Set([
|
|
27
|
+
'stdin',
|
|
28
|
+
'lossless',
|
|
29
|
+
'no-cache',
|
|
30
|
+
'json',
|
|
31
|
+
]);
|
|
32
|
+
export const compressCommand = {
|
|
33
|
+
name: 'compress',
|
|
34
|
+
description: 'Compress a blob (file or stdin) deterministically to cut tokens — JSON→table, logs/search/diffs→signal. Reversible via `shrk expand`.',
|
|
35
|
+
usage: 'shrk [--cwd <dir>] compress [<file>|-] [--stdin] [--type <content-type>] [--query <text>] [--max <n>] [--lossless] [--no-cache] [--json]',
|
|
36
|
+
booleanFlags: COMPRESS_BOOLEAN_FLAGS,
|
|
37
|
+
run(args) {
|
|
38
|
+
const cwd = resolveCwd(args);
|
|
39
|
+
let content;
|
|
40
|
+
try {
|
|
41
|
+
content = readInput(args);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
process.stderr.write(`compress: cannot read input — ${e.message}\n`);
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
if (content.length === 0) {
|
|
48
|
+
process.stderr.write('compress: empty input.\n');
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
const opts = {};
|
|
52
|
+
if (!flagBool(args, 'no-cache'))
|
|
53
|
+
opts.store = openCcrStore(cwd);
|
|
54
|
+
const query = flagString(args, 'query');
|
|
55
|
+
if (query)
|
|
56
|
+
opts.query = query;
|
|
57
|
+
const max = flagNumber(args, 'max');
|
|
58
|
+
if (max !== undefined && max > 0)
|
|
59
|
+
opts.maxItems = Math.floor(max);
|
|
60
|
+
if (flagBool(args, 'lossless'))
|
|
61
|
+
opts.lossless = true;
|
|
62
|
+
const type = flagString(args, 'type');
|
|
63
|
+
if (type && CONTENT_TYPES.has(type))
|
|
64
|
+
opts.contentType = type;
|
|
65
|
+
const result = compressContent(content, opts);
|
|
66
|
+
const pct = Math.round(result.savings.ratio * 100);
|
|
67
|
+
// A lossy result with no cached original (i.e. --no-cache) can't be undone
|
|
68
|
+
// by `shrk expand`. Warn so the dropped detail isn't lost silently.
|
|
69
|
+
if (result.lossy && !result.ccrKey) {
|
|
70
|
+
process.stderr.write('warning: compressed lossily but the original was NOT cached (--no-cache) — ' +
|
|
71
|
+
'detail is unrecoverable; omit --no-cache to keep it retrievable via `shrk expand`.\n');
|
|
72
|
+
}
|
|
73
|
+
const queryApplied = query !== undefined && query.length > 0;
|
|
74
|
+
if (flagBool(args, 'json')) {
|
|
75
|
+
// tokens are a deterministic ESTIMATE (chars/divisor heuristic), not a
|
|
76
|
+
// real BPE count — flagged so callers don't treat savedRatio as exact.
|
|
77
|
+
const base = {
|
|
78
|
+
contentType: result.contentType,
|
|
79
|
+
strategy: result.strategy,
|
|
80
|
+
lossy: result.lossy,
|
|
81
|
+
tokensBefore: result.savings.before,
|
|
82
|
+
tokensAfter: result.savings.after,
|
|
83
|
+
tokensSaved: result.savings.saved,
|
|
84
|
+
savedRatio: result.savings.ratio,
|
|
85
|
+
tokensAreEstimated: true,
|
|
86
|
+
queryApplied,
|
|
87
|
+
ccrKey: result.ccrKey ?? null,
|
|
88
|
+
note: result.note,
|
|
89
|
+
};
|
|
90
|
+
// Net-loss guard: on a passthrough/no-win blob the engine returns the
|
|
91
|
+
// VERBATIM original as `compressed`. Echoing it back inside the JSON
|
|
92
|
+
// envelope (plus scaffold) costs more tokens than the input. Signal
|
|
93
|
+
// passthrough and omit the duplicated content — the caller still has it.
|
|
94
|
+
const noWin = result.strategy === ECompressionStrategy.Passthrough || result.savings.saved <= 0;
|
|
95
|
+
const payload = noWin
|
|
96
|
+
? { ...base, passthrough: true, inputBytes: Buffer.byteLength(content, 'utf8') }
|
|
97
|
+
: { ...base, compressed: result.compressed };
|
|
98
|
+
process.stdout.write(asJson(payload) + '\n');
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
process.stdout.write(result.compressed + '\n');
|
|
102
|
+
const cached = result.ccrKey ? ` · original cached as ${result.ccrKey} (shrk expand ${result.ccrKey})` : '';
|
|
103
|
+
process.stderr.write(`${result.strategy}: ~${result.savings.before} → ~${result.savings.after} tokens (−${pct}%, est.)${cached}\n`);
|
|
104
|
+
// Token-economy guard: when auto-detect declines to compress a non-trivial
|
|
105
|
+
// input, a silent `−0%` re-emit looks like success. Nudge toward `--type`
|
|
106
|
+
// (stdout stays the verbatim blob; exit code unchanged).
|
|
107
|
+
const inputBytes = Buffer.byteLength(content, 'utf8');
|
|
108
|
+
if (result.strategy === ECompressionStrategy.Passthrough &&
|
|
109
|
+
inputBytes >= PASSTHROUGH_HINT_MIN_BYTES &&
|
|
110
|
+
!flagBool(args, 'lossless')) {
|
|
111
|
+
process.stderr.write(`hint: nothing was compressed — auto-detect classified this as ${result.contentType} and found no win. ` +
|
|
112
|
+
'Try `--type <content-type>` to force a strategy (json, git-diff, search-results, build-log, source-code, markdown).\n');
|
|
113
|
+
}
|
|
114
|
+
return 0;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* `shrk expand` — the retrieve half of CCR. Print the full original that
|
|
119
|
+
* `shrk compress` cached for a `<<ccr:KEY>>` key.
|
|
120
|
+
*/
|
|
121
|
+
export const expandCommand = {
|
|
122
|
+
name: 'expand',
|
|
123
|
+
description: 'Retrieve the full original a `shrk compress` run cached, by its `<<ccr:KEY>>` key.',
|
|
124
|
+
usage: 'shrk [--cwd <dir>] expand <key> [--json]',
|
|
125
|
+
run(args) {
|
|
126
|
+
const cwd = resolveCwd(args);
|
|
127
|
+
const key = (args.positional[0] ?? '').trim();
|
|
128
|
+
if (key.length === 0) {
|
|
129
|
+
process.stderr.write('expand: a CCR key is required (e.g. `shrk expand a1b2c3d4e5f60718`).\n');
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
const store = openCcrStore(cwd);
|
|
133
|
+
const entry = store.get(key);
|
|
134
|
+
if (!entry) {
|
|
135
|
+
process.stderr.write(`expand: no cached original for key "${key}" under ${ccrDir(cwd)}.\n`);
|
|
136
|
+
return 1;
|
|
137
|
+
}
|
|
138
|
+
if (flagBool(args, 'json')) {
|
|
139
|
+
process.stdout.write(asJson({ key: entry.key, bytes: entry.bytes, content: entry.content }) + '\n');
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
// Write the cached original VERBATIM — appending a newline broke byte-for-byte
|
|
143
|
+
// round-trip (`compress … ; expand` must reproduce the input exactly).
|
|
144
|
+
process.stdout.write(entry.content);
|
|
145
|
+
return 0;
|
|
146
|
+
},
|
|
147
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"AA8BA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAiGhC,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAoDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAwFpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAoErC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmCtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAwBpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAiClC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA4BrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA8BrC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0DpC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0LpC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import * as nodePath from 'node:path';
|
|
3
3
|
import { AdoptionCheckpointStatus, buildConstructAdoptionDiff, buildConstructAdoptionPlan, buildSearchIndex, ConstructAdoptionCategory, evaluateAdoptionCheckpoint, hashDiffBody, inferConstructs, InferredConstructConfidence, inspectSharkcraft, loadConstructs, loadPlaybooks, readAdoptionCheckpoint, readConstructAdoptionStatus, recordAdoptionCheckpoint, renderConstructAdoptionDiff, renderConstructAdoptionMarkdown, renderConstructDraftsModule, searchIndex, SearchKind, traceConstruct, writeConstructAdoption, } from '@shrkcrft/inspector';
|
|
4
|
+
import { GraphQueryApi, GraphStore } from '@shrkcrft/graph';
|
|
4
5
|
import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-registry.js";
|
|
5
6
|
import { asJson, header } from "../output/format-output.js";
|
|
6
7
|
async function loadAll(args) {
|
|
@@ -9,6 +10,64 @@ async function loadAll(args) {
|
|
|
9
10
|
const constructs = await loadConstructs(inspection);
|
|
10
11
|
return { constructs, inspection };
|
|
11
12
|
}
|
|
13
|
+
const GLOB_MAGIC = /[*?[\]{}]/;
|
|
14
|
+
function globToRegExp(glob) {
|
|
15
|
+
// Compile a minimal file glob (`**`, `*`, `?`) to an anchored RegExp. Mark the
|
|
16
|
+
// wildcards with control-char placeholders BEFORE regex-escaping the rest, so
|
|
17
|
+
// the escape pass and the wildcard expansion can never clobber each other (an
|
|
18
|
+
// earlier space-sentinel version was corrupted by editor whitespace handling).
|
|
19
|
+
const DSTAR_SLASH = '\u0000';
|
|
20
|
+
const DSTAR = '\u0001';
|
|
21
|
+
const STAR = '\u0002';
|
|
22
|
+
const QMARK = '\u0003';
|
|
23
|
+
const marked = glob
|
|
24
|
+
.replace(/\*\*\//g, DSTAR_SLASH)
|
|
25
|
+
.replace(/\*\*/g, DSTAR)
|
|
26
|
+
.replace(/\*/g, STAR)
|
|
27
|
+
.replace(/\?/g, QMARK);
|
|
28
|
+
const pattern = marked
|
|
29
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
30
|
+
.replaceAll(DSTAR_SLASH, '(?:.*/)?')
|
|
31
|
+
.replaceAll(DSTAR, '.*')
|
|
32
|
+
.replaceAll(STAR, '[^/]*')
|
|
33
|
+
.replaceAll(QMARK, '[^/]');
|
|
34
|
+
return new RegExp(`^${pattern}$`);
|
|
35
|
+
}
|
|
36
|
+
function enrichTraceWithGraph(declaredFiles, declaredNames, cwd) {
|
|
37
|
+
if (!new GraphStore(cwd).exists()) {
|
|
38
|
+
return { graphState: 'missing', resolvedFiles: [], unresolvedGlobs: [], undeclaredSymbols: [] };
|
|
39
|
+
}
|
|
40
|
+
const api = GraphQueryApi.fromStore(cwd);
|
|
41
|
+
const allPaths = [...api.allFiles()].map((n) => n.path).filter((p) => !!p);
|
|
42
|
+
const resolved = new Set();
|
|
43
|
+
const unresolvedGlobs = [];
|
|
44
|
+
for (const entry of declaredFiles) {
|
|
45
|
+
if (GLOB_MAGIC.test(entry)) {
|
|
46
|
+
const re = globToRegExp(entry);
|
|
47
|
+
const matches = allPaths.filter((p) => re.test(p));
|
|
48
|
+
if (matches.length === 0)
|
|
49
|
+
unresolvedGlobs.push(entry);
|
|
50
|
+
for (const m of matches)
|
|
51
|
+
resolved.add(m);
|
|
52
|
+
}
|
|
53
|
+
else if (api.findFile(entry)) {
|
|
54
|
+
resolved.add(entry);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const undeclared = new Set();
|
|
58
|
+
for (const path of resolved) {
|
|
59
|
+
for (const sym of api.symbolsIn(`file:${path}`)) {
|
|
60
|
+
if (sym.label && !declaredNames.has(sym.label))
|
|
61
|
+
undeclared.add(sym.label);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
graphState: 'fresh',
|
|
66
|
+
resolvedFiles: [...resolved].sort(),
|
|
67
|
+
unresolvedGlobs,
|
|
68
|
+
undeclaredSymbols: [...undeclared].sort(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
12
71
|
export const constructsListCommand = {
|
|
13
72
|
name: 'list',
|
|
14
73
|
description: 'List registered constructs.',
|
|
@@ -91,7 +150,7 @@ export const constructsGetCommand = {
|
|
|
91
150
|
};
|
|
92
151
|
export const constructsTraceCommand = {
|
|
93
152
|
name: 'trace',
|
|
94
|
-
description: 'Trace
|
|
153
|
+
description: 'Trace a construct\'s declared files / publicApi / events / tokens, verified against the code graph (expands file globs, flags globs that match nothing, lists undeclared symbols defined in those files). --deep adds related / test pointers.',
|
|
95
154
|
usage: 'shrk constructs trace <id> [--deep] [--json]',
|
|
96
155
|
async run(args) {
|
|
97
156
|
const id = args.positional[0];
|
|
@@ -107,6 +166,10 @@ export const constructsTraceCommand = {
|
|
|
107
166
|
}
|
|
108
167
|
const trace = traceConstruct(c);
|
|
109
168
|
const deep = flagBool(args, 'deep');
|
|
169
|
+
// Verify the hand-declared inventory against the code graph (additive — does
|
|
170
|
+
// not change the declared files/tokens the other subverbs rely on).
|
|
171
|
+
const declaredNames = new Set([...trace.publicApi, ...trace.tokens, ...trace.events]);
|
|
172
|
+
const graph = enrichTraceWithGraph(trace.files, declaredNames, resolveCwd(args));
|
|
110
173
|
const relatedAll = [
|
|
111
174
|
...(c.relatedKnowledge ?? []),
|
|
112
175
|
...(c.relatedRules ?? []),
|
|
@@ -118,11 +181,11 @@ export const constructsTraceCommand = {
|
|
|
118
181
|
? {
|
|
119
182
|
related: relatedAll,
|
|
120
183
|
tags: c.tags ?? [],
|
|
121
|
-
registryHints: c.tags?.filter((t) => /(registry|
|
|
184
|
+
registryHints: c.tags?.filter((t) => /(registry|barrel)/i.test(t)) ?? [],
|
|
122
185
|
}
|
|
123
186
|
: undefined;
|
|
124
187
|
if (flagBool(args, 'json')) {
|
|
125
|
-
process.stdout.write(asJson({ ...trace, ...(deepBlock ? { deep: deepBlock } : {}) }) + '\n');
|
|
188
|
+
process.stdout.write(asJson({ ...trace, graph, ...(deepBlock ? { deep: deepBlock } : {}) }) + '\n');
|
|
126
189
|
return 0;
|
|
127
190
|
}
|
|
128
191
|
process.stdout.write(header(`Trace: ${id}`));
|
|
@@ -145,6 +208,26 @@ export const constructsTraceCommand = {
|
|
|
145
208
|
for (const w of trace.warnings)
|
|
146
209
|
process.stdout.write(` ! ${w}\n`);
|
|
147
210
|
}
|
|
211
|
+
// Graph-verified view: this is the part that makes the declared inventory
|
|
212
|
+
// trustworthy rather than a hand-typed partial map.
|
|
213
|
+
if (graph.graphState === 'missing') {
|
|
214
|
+
process.stdout.write('\n(declared inventory only — run `shrk graph index` for a graph-verified inventory)\n');
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
if (graph.unresolvedGlobs.length > 0) {
|
|
218
|
+
process.stdout.write('Unresolved file globs (matched 0 files in the graph):\n');
|
|
219
|
+
for (const g of graph.unresolvedGlobs)
|
|
220
|
+
process.stdout.write(` ! ${g}\n`);
|
|
221
|
+
}
|
|
222
|
+
if (graph.undeclaredSymbols.length > 0) {
|
|
223
|
+
process.stdout.write(`Graph found ${graph.undeclaredSymbols.length} symbol(s) defined in these files but NOT declared on the construct:\n`);
|
|
224
|
+
for (const s of graph.undeclaredSymbols.slice(0, 30))
|
|
225
|
+
process.stdout.write(` + ${s}\n`);
|
|
226
|
+
if (graph.undeclaredSymbols.length > 30) {
|
|
227
|
+
process.stdout.write(` … (${graph.undeclaredSymbols.length - 30} more)\n`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
148
231
|
if (deepBlock) {
|
|
149
232
|
process.stdout.write('\nDeep:\n');
|
|
150
233
|
if (deepBlock.related.length > 0)
|
|
@@ -175,28 +258,11 @@ export const constructsImpactCommand = {
|
|
|
175
258
|
}
|
|
176
259
|
const trace = traceConstruct(c);
|
|
177
260
|
/**
|
|
178
|
-
* Registry touch-points are inferred
|
|
179
|
-
*
|
|
180
|
-
*
|
|
261
|
+
* Registry touch-points are not inferred — pack-contributed
|
|
262
|
+
* touch-point hints can be added in the future via the convention
|
|
263
|
+
* registry.
|
|
181
264
|
*/
|
|
182
265
|
const registryTouchPoints = [];
|
|
183
|
-
try {
|
|
184
|
-
const { listPluginLifecycleProfiles } = await import('@shrkcrft/inspector');
|
|
185
|
-
const profiles = await listPluginLifecycleProfiles(inspection);
|
|
186
|
-
for (const entry of profiles) {
|
|
187
|
-
const p = entry.profile;
|
|
188
|
-
if (c.tags?.some((t) => /plugin-key|key-table/i.test(t)) && p.keyTable) {
|
|
189
|
-
registryTouchPoints.push(p.keyTable.path);
|
|
190
|
-
}
|
|
191
|
-
if (c.tags?.some((t) => /barrel|public-api/i.test(t)) && p.barrels) {
|
|
192
|
-
for (const b of p.barrels)
|
|
193
|
-
registryTouchPoints.push(b.path);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
// Best-effort enrichment; absence of profiles just means no touch-points.
|
|
199
|
-
}
|
|
200
266
|
const verificationCommands = [
|
|
201
267
|
'shrk check boundaries --changed-only',
|
|
202
268
|
'shrk doctor',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.command.d.ts","sourceRoot":"","sources":["../../src/commands/context.command.ts"],"names":[],"mappings":"
|
|
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,eAyI5B,CAAC"}
|
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
import { entrypointBanner, inspectSharkcraft } from '@shrkcrft/inspector';
|
|
2
2
|
import { buildContext } from '@shrkcrft/context';
|
|
3
|
+
import { loadIntentBenchmark, runIntentBenchmark, STARTER_INTENT_BENCHMARK, writeBenchmarkRun, } from '@shrkcrft/context-planner';
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import * as nodePath from 'node:path';
|
|
3
6
|
import { buildUniversalSearch, explainTaskRouting, recommendCommands, renderOverviewText, buildProjectOverview, } from '@shrkcrft/inspector';
|
|
4
7
|
import { flagBool, flagNumber, flagString, flagList, resolveCwd, } from "../command-registry.js";
|
|
5
8
|
import { asJson, header } from "../output/format-output.js";
|
|
9
|
+
/**
|
|
10
|
+
* Minimal JSON shape for agent / skill consumption — the context-side mirror
|
|
11
|
+
* of `shrk task --compact`. Drops the heavy `body` and `request` echo and
|
|
12
|
+
* carries the section map + structured action hints (so the agent reads
|
|
13
|
+
* forbiddenActions / verificationCommands / preferredFlow directly instead of
|
|
14
|
+
* regexing the markdown body). The schema marker is distinct so consumers can
|
|
15
|
+
* tell the shapes apart at a glance.
|
|
16
|
+
*/
|
|
17
|
+
function minimalContext(task, result, commands) {
|
|
18
|
+
return {
|
|
19
|
+
schema: 'sharkcraft.context/v1-compact',
|
|
20
|
+
task,
|
|
21
|
+
tokens: { used: result.totalTokens, max: result.maxTokens },
|
|
22
|
+
sections: result.sections.map((s) => ({
|
|
23
|
+
title: s.title,
|
|
24
|
+
tokens: s.tokens,
|
|
25
|
+
...(s.truncated ? { truncated: true } : {}),
|
|
26
|
+
})),
|
|
27
|
+
omittedSections: result.omittedSections,
|
|
28
|
+
actionHints: result.actionHints,
|
|
29
|
+
topCommands: (commands?.recommendations ?? []).slice(0, 5).map((r) => r.command),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
6
32
|
export const contextCommand = {
|
|
7
33
|
name: 'context',
|
|
8
34
|
description: 'Build relevant AI-ready context for a task (token-budgeted). Subcommands: build / refresh / status.',
|
|
9
|
-
usage: 'shrk context [build|refresh|status] --task "<task>" [--max-tokens 3000] [--framework x] [--area y] [--json]',
|
|
35
|
+
usage: 'shrk context [build|refresh|status] --task "<task>" [--max-tokens 3000] [--framework x] [--area y] [--json] [--compact] [--full]',
|
|
10
36
|
async run(args) {
|
|
11
37
|
// Dispatch subcommands (build / refresh / status) based on first positional.
|
|
12
38
|
const sub = args.positional[0];
|
|
@@ -19,6 +45,10 @@ export const contextCommand = {
|
|
|
19
45
|
return contextRefreshCommand.run(sliced);
|
|
20
46
|
return contextStatusCommand.run(sliced);
|
|
21
47
|
}
|
|
48
|
+
if (sub === 'benchmark') {
|
|
49
|
+
const sliced = { ...args, positional: args.positional.slice(1) };
|
|
50
|
+
return runContextBenchmark(sliced);
|
|
51
|
+
}
|
|
22
52
|
const task = flagString(args, 'task');
|
|
23
53
|
if (!task) {
|
|
24
54
|
process.stderr.write('Missing --task\n');
|
|
@@ -72,6 +102,14 @@ export const contextCommand = {
|
|
|
72
102
|
// ignore — fall back to legacy context only.
|
|
73
103
|
}
|
|
74
104
|
if (flagBool(args, 'json') || flagBool(args, 'machine-json')) {
|
|
105
|
+
// `--compact` emits a minimal, structured agent shape (no long body /
|
|
106
|
+
// request echo) — the context-side mirror of `shrk task --compact`.
|
|
107
|
+
// Carries the load-bearing action hints as structured data so the agent
|
|
108
|
+
// never has to parse the markdown body. Full shape stays the default.
|
|
109
|
+
if (flagBool(args, 'compact')) {
|
|
110
|
+
process.stdout.write(asJson(minimalContext(task, result, commandRecommendations)) + '\n');
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
75
113
|
process.stdout.write(asJson({
|
|
76
114
|
...result,
|
|
77
115
|
commands: commandRecommendations,
|
|
@@ -118,3 +156,85 @@ export const contextCommand = {
|
|
|
118
156
|
return 0;
|
|
119
157
|
},
|
|
120
158
|
};
|
|
159
|
+
async function runContextBenchmark(args) {
|
|
160
|
+
const cwd = resolveCwd(args);
|
|
161
|
+
const wantJson = flagBool(args, 'json');
|
|
162
|
+
// `shrk context benchmark seed` writes a starter fixture to
|
|
163
|
+
// sharkcraft/intent-benchmark.json. Useful first step for adopting
|
|
164
|
+
// the surface — fixture is opinionated but small and easy to prune.
|
|
165
|
+
if (args.positional[0] === 'seed') {
|
|
166
|
+
return runContextBenchmarkSeed(cwd, args);
|
|
167
|
+
}
|
|
168
|
+
const noPersist = flagBool(args, 'no-persist');
|
|
169
|
+
const benchmark = loadIntentBenchmark(cwd);
|
|
170
|
+
if (!benchmark) {
|
|
171
|
+
const msg = `No benchmark at sharkcraft/intent-benchmark.json. Create one with schema "sharkcraft.intent-benchmark/v1" and a "cases" array of { task, expected } entries.\n`;
|
|
172
|
+
if (wantJson) {
|
|
173
|
+
process.stdout.write(asJson({ ok: false, error: 'benchmark-missing' }) + '\n');
|
|
174
|
+
return 1;
|
|
175
|
+
}
|
|
176
|
+
process.stderr.write(msg);
|
|
177
|
+
return 1;
|
|
178
|
+
}
|
|
179
|
+
const run = runIntentBenchmark(benchmark);
|
|
180
|
+
if (!noPersist) {
|
|
181
|
+
try {
|
|
182
|
+
writeBenchmarkRun(cwd, run);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// best-effort
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (wantJson) {
|
|
189
|
+
process.stdout.write(asJson(run) + '\n');
|
|
190
|
+
return run.failed === 0 ? 0 : 1;
|
|
191
|
+
}
|
|
192
|
+
process.stdout.write(header('Intent classifier benchmark'));
|
|
193
|
+
process.stdout.write(` total ${run.total}\n`);
|
|
194
|
+
process.stdout.write(` passed ${run.passed}\n`);
|
|
195
|
+
process.stdout.write(` failed ${run.failed}\n`);
|
|
196
|
+
process.stdout.write(` accuracy ${Math.round(run.accuracy * 1000) / 10}%\n`);
|
|
197
|
+
const failures = run.cases.filter((c) => !c.passed);
|
|
198
|
+
if (failures.length > 0) {
|
|
199
|
+
process.stdout.write('\nFailures:\n');
|
|
200
|
+
for (const c of failures.slice(0, 20)) {
|
|
201
|
+
process.stdout.write(` ✗ task="${truncateTask(c.task)}" expected=${c.expected} actual=${c.actual}\n`);
|
|
202
|
+
}
|
|
203
|
+
if (failures.length > 20) {
|
|
204
|
+
process.stdout.write(` … (${failures.length - 20} more)\n`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return run.failed === 0 ? 0 : 1;
|
|
208
|
+
}
|
|
209
|
+
function truncateTask(s) {
|
|
210
|
+
if (s.length <= 60)
|
|
211
|
+
return s;
|
|
212
|
+
return s.slice(0, 57) + '…';
|
|
213
|
+
}
|
|
214
|
+
function runContextBenchmarkSeed(cwd, args) {
|
|
215
|
+
const wantJson = flagBool(args, 'json');
|
|
216
|
+
const force = flagBool(args, 'force');
|
|
217
|
+
const target = nodePath.join(cwd, 'sharkcraft', 'intent-benchmark.json');
|
|
218
|
+
if (existsSync(target) && !force) {
|
|
219
|
+
const msg = `${target} already exists. Use --force to overwrite.\n`;
|
|
220
|
+
if (wantJson) {
|
|
221
|
+
process.stdout.write(asJson({ ok: false, error: 'exists', path: target }) + '\n');
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
process.stderr.write(msg);
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
mkdirSync(nodePath.dirname(target), { recursive: true });
|
|
228
|
+
writeFileSync(target, JSON.stringify(STARTER_INTENT_BENCHMARK, null, 2), 'utf8');
|
|
229
|
+
if (wantJson) {
|
|
230
|
+
process.stdout.write(asJson({
|
|
231
|
+
ok: true,
|
|
232
|
+
wrote: target,
|
|
233
|
+
cases: STARTER_INTENT_BENCHMARK.cases.length,
|
|
234
|
+
}) + '\n');
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
process.stdout.write(`Seeded ${STARTER_INTENT_BENCHMARK.cases.length} starter intent case(s) → ${target}\n`);
|
|
238
|
+
process.stdout.write('Run `shrk context benchmark` to record accuracy.\n');
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/contract-gate.command.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAWhC,eAAO,MAAM,oBAAoB,EAAE,eAqDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA6EpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"contract-gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/contract-gate.command.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAWhC,eAAO,MAAM,oBAAoB,EAAE,eAqDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA6EpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAiEnC,CAAC"}
|