simt-dev 0.6.3 → 0.7.1
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/CHANGELOG.md +162 -841
- package/README.md +21 -135
- package/agents/simt-agent.md +84 -0
- package/bin/simt.mjs +19 -55
- package/docs/decisions/ADR-009-skill-layout.md +1 -1
- package/docs/decisions/ADR-014-workspace-is-configuration.md +1 -1
- package/docs/decisions/ADR-086-the-stable-prefix-comes-first-and-the-lock-records-both-digests.md +1 -1
- package/docs/decisions/ADR-099-the-release-verifies-served-bytes-and-the-formula-mirrors-them.md +1 -1
- package/docs/decisions/ADR-106-the-harness-hook-runs-through-a-repo-shim.md +46 -0
- package/docs/decisions/ADR-107-an-install-can-name-one-harness-and-the-skipped-ones-are-named.md +51 -0
- package/docs/decisions/ADR-108-an-adoption-builds-the-index-and-a-command-refreshes-it-on-read.md +59 -0
- package/docs/decisions/ADR-109-simt-dev-is-its-own-consumer-and-the-guards-that-kept-it-from-being-one-are-retired.md +47 -0
- package/docs/decisions/ADR-110-the-lock-file-follows-the-manifest-name-and-the-old-name-is-read-until-the-next-write.md +43 -0
- package/docs/decisions/ADR-111-the-tool-ships-one-agent-rendered-per-harness-and-installs-it-with-init-and-a-command.md +75 -0
- package/docs/decisions/ADR-112-the-registry-is-what-simt-dev-ships-and-a-repo-owns-its-own-skills.md +81 -0
- package/docs/decisions/ADR-113-a-pre-push-that-carries-only-documentation-skips-the-test-gate-and-says-so.md +87 -0
- package/docs/decisions/ADR-114-the-bench-pairs-at-the-task-level-a-missing-cost-is-not-zero-and-an-unasked-cross-group-compare-is-refused.md +74 -0
- package/docs/decisions/ADR-115-the-index-stamps-its-schema-version-migrates-older-databases-in-place-and-serves-newer-ones-from-a-sidecar.md +69 -0
- package/docs/decisions/ADR-116-rust-support-reaches-the-example-path-the-indent-and-the-bench-runner.md +100 -0
- package/docs/decisions/ADR-117-the-darwin-release-builds-on-supported-macos-15-runners-and-a-re-run-is-idempotent.md +81 -0
- package/docs/decisions/ADR-118-the-bench-corpus-is-keyed-on-history-is-append-only-and-is-portable-as-a-sealed-document.md +91 -0
- package/docs/decisions/ADR-119-the-environment-variable-points-into-a-workspace-the-repo-declared.md +90 -0
- package/docs/decisions/ADR-120-a-pre-push-whose-tree-is-already-proven-green-skips-the-test-gate-on-that-evidence.md +96 -0
- package/docs/decisions/ADR-122-the-shims-move-into-the-state-directory-and-the-legacy-directory-removes-itself.md +94 -0
- package/docs/decisions/ADR-123-a-surplus-positional-is-not-refused-because-arity-is-not-in-the-source.md +57 -0
- package/docs/decisions/ADR-124-the-manifest-has-a-schema-in-the-tool-and-its-unknown-keys-stay-the-repositorys.md +64 -0
- package/docs/decisions/ADR-125-a-shared-context-belongs-to-a-read-and-a-writer-reads-directly.md +65 -0
- package/package.json +13 -3
- package/rules/core.md +9 -2
- package/rules/mdc/slice-commit.mdc +57 -4
- package/rules/mdc/test-gate.mdc +2 -0
- package/rules/stacks/android.md +3 -3
- package/rules/stacks/connectiq.md +2 -2
- package/rules/stacks/dart.md +1 -1
- package/rules/stacks/deno.md +1 -1
- package/rules/stacks/dotnet.md +1 -1
- package/rules/stacks/elixir.md +1 -1
- package/rules/stacks/go.md +1 -1
- package/rules/stacks/jvm.md +3 -2
- package/rules/stacks/node.md +2 -2
- package/rules/stacks/python.md +7 -6
- package/rules/stacks/ruby.md +1 -1
- package/rules/stacks/rust.md +1 -1
- package/rules/stacks/swift.md +1 -1
- package/rules/stacks/typescript.md +2 -2
- package/rules/stacks/uv.md +3 -2
- package/skills/simt-commands/SKILL.md +70 -0
- package/src/advice/advice.mjs +7 -3
- package/src/agenthooks/decide.mjs +141 -9
- package/src/agenthooks/opencode.mjs +72 -0
- package/src/agenthooks/prompt.mjs +10 -3
- package/src/agenthooks/render.mjs +186 -19
- package/src/agenthooks/shim.mjs +55 -0
- package/src/agents/render.mjs +277 -0
- package/src/api.mjs +29 -0
- package/src/argv.mjs +37 -3
- package/src/bench/ablate.mjs +31 -14
- package/src/bench/adapters.json +16 -0
- package/src/bench/corpus.mjs +150 -0
- package/src/bench/grade.mjs +23 -49
- package/src/bench/mine.mjs +247 -36
- package/src/bench/probes.mjs +104 -68
- package/src/bench/process.mjs +128 -0
- package/src/bench/report.mjs +260 -84
- package/src/bench/run.mjs +251 -150
- package/src/bench/variants.mjs +112 -40
- package/src/brief/assemble.mjs +44 -3
- package/src/ci/workflow.mjs +46 -14
- package/src/cli.mjs +45 -0
- package/src/commands/agent.mjs +205 -0
- package/src/commands/agenthook.mjs +113 -20
- package/src/commands/bench.mjs +192 -18
- package/src/commands/brief.mjs +5 -4
- package/src/commands/ci.mjs +2 -1
- package/src/commands/compare.mjs +50 -49
- package/src/commands/completions.mjs +2 -6
- package/src/commands/decide.mjs +10 -9
- package/src/commands/distill.mjs +4 -3
- package/src/commands/doctor.mjs +11 -7
- package/src/commands/evidence.mjs +19 -12
- package/src/commands/explain.mjs +0 -1
- package/src/commands/gate.mjs +98 -28
- package/src/commands/graph.mjs +20 -8
- package/src/commands/harness.mjs +3 -2
- package/src/commands/help.mjs +160 -31
- package/src/commands/hooks.mjs +163 -50
- package/src/commands/ignore.mjs +2 -1
- package/src/commands/impact.mjs +8 -9
- package/src/commands/index.mjs +278 -180
- package/src/commands/init.mjs +171 -38
- package/src/commands/lease.mjs +206 -39
- package/src/commands/lessons.mjs +72 -15
- package/src/commands/local.mjs +3 -3
- package/src/commands/map.mjs +47 -27
- package/src/commands/mcp.mjs +0 -1
- package/src/commands/pack.mjs +9 -6
- package/src/commands/plan.mjs +6 -5
- package/src/commands/plugin.mjs +3 -3
- package/src/commands/prbody.mjs +3 -3
- package/src/commands/repoindex.mjs +5 -3
- package/src/commands/review.mjs +2 -2
- package/src/commands/rules.mjs +124 -33
- package/src/commands/shared.mjs +2 -3
- package/src/commands/skills.mjs +82 -45
- package/src/commands/skillscompile.mjs +12 -12
- package/src/commands/skillsinstall.mjs +14 -2
- package/src/commands/slice.mjs +396 -26
- package/src/commands/spec.mjs +151 -0
- package/src/commands/status.mjs +4 -7
- package/src/commands/sync.mjs +50 -33
- package/src/commands/tests.mjs +11 -11
- package/src/commands/tokens.mjs +2 -2
- package/src/commands/undo.mjs +29 -31
- package/src/commands/upgrade.mjs +40 -4
- package/src/commands/why.mjs +19 -12
- package/src/compare/hooksstate.mjs +23 -1
- package/src/compare/learn.mjs +82 -57
- package/src/compare/parallel.mjs +50 -0
- package/src/compare/row.mjs +26 -3
- package/src/completions.mjs +5 -0
- package/src/context.mjs +64 -0
- package/src/decisions/dir.mjs +84 -0
- package/src/decisions/index-doc.mjs +46 -0
- package/src/decisions/index.mjs +109 -11
- package/src/diff.mjs +1 -1
- package/src/distill/distill.mjs +17 -2
- package/src/distill/engine.mjs +5 -1
- package/src/ecosystem/node-runner.mjs +144 -0
- package/src/explain.mjs +18 -6
- package/src/graph/load.mjs +42 -20
- package/src/hooks/capability.mjs +17 -4
- package/src/hooks/dispatcher.mjs +513 -36
- package/src/hooks/gates.mjs +0 -43
- package/src/hooks/resolve.mjs +11 -10
- package/src/hooks/shim.mjs +17 -9
- package/src/identity.mjs +96 -15
- package/src/index/extract.mjs +192 -11
- package/src/index/persist.mjs +307 -47
- package/src/index/store.mjs +263 -60
- package/src/index/tests.mjs +6 -35
- package/src/journal.mjs +372 -84
- package/src/kernel/card.mjs +37 -12
- package/src/kernel/checks.mjs +44 -9
- package/src/kernel/variants.mjs +27 -16
- package/src/lease.mjs +97 -15
- package/src/ledger/index.mjs +120 -25
- package/src/local/client.mjs +4 -6
- package/src/locate.mjs +33 -9
- package/src/manifest/schema.mjs +213 -0
- package/src/mcp/resources.mjs +12 -13
- package/src/mcp/server.mjs +151 -38
- package/src/mcp/tools.mjs +90 -16
- package/src/measure/session.mjs +3 -2
- package/src/memory/decide.mjs +98 -43
- package/src/memory/lessons.mjs +168 -33
- package/src/name.mjs +9 -0
- package/src/node-version.mjs +37 -0
- package/src/output/index.mjs +111 -3
- package/src/packs/manage.mjs +17 -3
- package/src/packs.mjs +20 -2
- package/src/plan/index.mjs +31 -8
- package/src/plan/template.mjs +27 -5
- package/src/plugins.mjs +6 -2
- package/src/prbody.mjs +7 -5
- package/src/projection/baselines.mjs +1 -1
- package/src/projection/disclosure.mjs +2 -2
- package/src/projection/loaders.mjs +41 -1
- package/src/projection/lock.mjs +31 -14
- package/src/projection/manifest.mjs +89 -53
- package/src/projection/markers.mjs +43 -3
- package/src/projection/mdc.mjs +34 -7
- package/src/projection/project.mjs +162 -18
- package/src/projection/rules.mjs +58 -6
- package/src/projection/surfaces.mjs +9 -1
- package/src/repo-root.mjs +88 -0
- package/src/resolve/body.mjs +4 -0
- package/src/resolve/fingerprint.mjs +24 -15
- package/src/resolve/local.mjs +58 -0
- package/src/review/critic.mjs +6 -3
- package/src/secrets.mjs +165 -22
- package/src/state.mjs +76 -0
- package/src/status.mjs +9 -4
- package/src/toolwords.mjs +8 -0
- package/src/tsconfig.mjs +39 -99
- package/src/workspace.mjs +55 -10
- package/templates/plan/tracker.json +1 -1
- package/docs/decisions/README.md +0 -591
package/src/commands/help.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { emit, fail, jsonFailMode } from '../output/index.mjs';
|
|
1
|
+
import { emit, emitJson, fail, jsonFailMode } from '../output/index.mjs';
|
|
2
|
+
import { SPEC, SPEC_PATHS, tierOf } from './spec.mjs';
|
|
2
3
|
import { parse, rawJsonFlag } from '../argv.mjs';
|
|
3
4
|
import { CLI, MANIFEST_FILE, STATE_DIR } from '../name.mjs';
|
|
4
5
|
import { SESSION_ENV } from '../agenthooks/policy.mjs';
|
|
@@ -47,6 +48,7 @@ ${CLI} rules list the rule catalogue (--root marks what applies to a
|
|
|
47
48
|
${CLI} rules show <id> one rule body
|
|
48
49
|
${CLI} rules why <id|ADR-NNN> the decision that settled it, and whether it is still in force
|
|
49
50
|
(--all prints every ruling, not the first two)
|
|
51
|
+
${CLI} rules decisions every known decision, shipped and repo, and which layer each came from
|
|
50
52
|
${CLI} hooks install [--yes] install the shared dispatcher; report what it would run
|
|
51
53
|
(dry-run unless --yes; refuses to take over routing git
|
|
52
54
|
already uses, and --yes is that consent)
|
|
@@ -58,11 +60,16 @@ ${CLI} agent-hook <event> the entry point a harness calls: pre-tool-use dec
|
|
|
58
60
|
(reads one JSON payload on stdin and answers in that
|
|
59
61
|
harness's dialect; exit 2 blocks; needs --harness)
|
|
60
62
|
${CLI} agent-hooks install write this repo's policies into the harnesses that
|
|
61
|
-
read a hooks file
|
|
63
|
+
read a hooks file (--harness <id> writes one, not all)
|
|
62
64
|
(dry-run unless --yes; merges into the file, keeps every
|
|
63
65
|
key it does not own; Codex needs the hook trusted)
|
|
64
66
|
${CLI} agent-hooks status what each harness will run, and what is not trusted yet
|
|
65
|
-
${CLI}
|
|
67
|
+
${CLI} agents install write the Simt-Agent into the harnesses that read an
|
|
68
|
+
agents file (--harness <id> writes one, not all; dry-run
|
|
69
|
+
unless --yes; markdown with a frontmatter the harness
|
|
70
|
+
documents, TOML for Codex)
|
|
71
|
+
${CLI} agents status what each harness carries, and what is not installed yet
|
|
72
|
+
${CLI} plugin <claude|gemini|cursor|opencode> generate a harness package from the same tables
|
|
66
73
|
(dry-run unless --yes; writes a self-contained runtime, the
|
|
67
74
|
hooks and MCP registration, and for cursor the kernel rules;
|
|
68
75
|
the skill registry is workspace data and is not shipped)
|
|
@@ -77,17 +84,24 @@ ${CLI} plan status count tracker rows
|
|
|
77
84
|
${CLI} plan next [<id>] one ready slice's section, or the one named; ~1 KB
|
|
78
85
|
${CLI} plan done <id> [<sha>] mark one row; dry-run unless --yes
|
|
79
86
|
${CLI} slice start <id> give a slice its own worktree and branch, preload the
|
|
80
|
-
brief, and mark the row
|
|
81
|
-
--yes; the worktree is ${STATE_DIR}/worktrees/<id>
|
|
82
|
-
branch slice/<id>, the brief ${STATE_DIR}/
|
|
87
|
+
brief, and mark the row started (dry-run unless
|
|
88
|
+
--yes; the worktree is ${STATE_DIR}/local/worktrees/<id>
|
|
89
|
+
on branch slice/<id>, the brief ${STATE_DIR}/local/briefs/<id>.md
|
|
90
|
+
beside it; --session <id> leases the slice)
|
|
83
91
|
${CLI} slice finish <id> run the pre-commit gates, commit what is staged with a
|
|
84
92
|
Conventional subject from the row's title, then record
|
|
85
93
|
the SHA and the --test command on the row (dry-run
|
|
86
|
-
unless --yes; --type picks the type, default feat
|
|
94
|
+
unless --yes; --type picks the type, default feat;
|
|
95
|
+
refuses unless HEAD is the slice branch; gates the
|
|
96
|
+
ledger already proves for this tree are not re-run)
|
|
97
|
+
${CLI} slice abandon <id> remove the worktree, delete the branch, and return
|
|
98
|
+
the row to ready (dry-run unless --yes; refuses from
|
|
99
|
+
inside the worktree)
|
|
87
100
|
${CLI} lease [<paths>...] claim files for one session and a TTL, or list the
|
|
88
101
|
claims (dry-run unless --yes; the session is --session
|
|
89
102
|
<id> or ${SESSION_ENV}; a pre-edit hook refuses an edit
|
|
90
|
-
to a path another session holds — ADR-101
|
|
103
|
+
to a path another session holds — ADR-101;
|
|
104
|
+
release and renew end and extend your own claims)
|
|
91
105
|
${CLI} graph lint check the skill registry against the skills on disk
|
|
92
106
|
(byte counts, dangling edges, unresolvable variants)
|
|
93
107
|
${CLI} ci simt-dev's own .github files: create or refresh them
|
|
@@ -100,7 +114,8 @@ ${CLI} ignore [--yes] render the one .simtignore list into .cursorignore
|
|
|
100
114
|
Claude settings file is merged, never replaced)
|
|
101
115
|
${CLI} compare org-wide matrix across every sibling repo
|
|
102
116
|
(read-only; exits non-zero on defects, not on
|
|
103
|
-
repos that have not adopted yet
|
|
117
|
+
repos that have not adopted yet;
|
|
118
|
+
--concurrency <n> caps the rows built at once)
|
|
104
119
|
${CLI} index rebuild the local file index from git blob hashes
|
|
105
120
|
${CLI} why [path] what governs a file: a decision whose Affects line names
|
|
106
121
|
it, a rule whose scope matches it, a skill, a gate
|
|
@@ -127,10 +142,11 @@ ${CLI} pr-body [--base <ref>] a pull request body: the evidence block for this
|
|
|
127
142
|
${CLI} evidence the runs recorded against the tree on disk
|
|
128
143
|
${CLI} evidence check <file> a commit message that claims a run this tree does not
|
|
129
144
|
have: a warning, or a block when gates.evidence is "block"
|
|
130
|
-
${CLI} lessons list deterministic lesson candidates in .simt/lessons.jsonl
|
|
131
|
-
and promoted lessons in docs/lessons/*.md
|
|
145
|
+
${CLI} lessons list deterministic lesson candidates in .simt/local/lessons.jsonl
|
|
146
|
+
and promoted lessons in docs/lessons/*.md (reads nothing else)
|
|
147
|
+
${CLI} lessons capture scan the ledger and git history for new candidates (the write half of list)
|
|
132
148
|
${CLI} lessons review [<id>] promote a lesson candidate to docs/lessons/NNNN-<slug>.md
|
|
133
|
-
(dry-run unless --yes; writes
|
|
149
|
+
(dry-run unless --yes; writes the lesson frontmatter)
|
|
134
150
|
${CLI} explain <CODE> what a check finding means: the decision behind it, how
|
|
135
151
|
to fix it, and a concrete trigger (DRIFT, UNMANAGED,
|
|
136
152
|
PACK-DIGEST-MISMATCH, ...; case-insensitive)
|
|
@@ -147,17 +163,17 @@ ${CLI} local doctor probe configured local model endpoints (chat and
|
|
|
147
163
|
unset; refuses non-loopback URLs without --allow-remote)
|
|
148
164
|
${CLI} distill <skill|doc> a budgeted proposal summary of a skill body or doc,
|
|
149
165
|
every claim citing the source line range it rests on
|
|
150
|
-
(writes .simt/distilled/<digest>.md; a proposal a
|
|
166
|
+
(writes .simt/local/distilled/<digest>.md; a proposal a
|
|
151
167
|
human merges - never projected or committed;
|
|
152
168
|
deterministic outline by default; --local proposes
|
|
153
169
|
from the configured chat model instead; the cache is
|
|
154
170
|
keyed by source digest and budget, --refresh regenerates)
|
|
155
171
|
${CLI} review [--local] an ADR-008 verdict skeleton for the staged diff,
|
|
156
|
-
the brief listing everything that governs it
|
|
172
|
+
the brief listing everything that governs it
|
|
157
173
|
(deterministic without --local: the brief and its
|
|
158
174
|
governing ids only; --local proposes from the
|
|
159
175
|
configured chat model and writes
|
|
160
|
-
.simt/reviews/<digest>.md — a proposal a human
|
|
176
|
+
.simt/local/reviews/<digest>.md — a proposal a human
|
|
161
177
|
reads, verified against the verdict vocabulary and
|
|
162
178
|
the brief's ids; advisory always, never a gate)
|
|
163
179
|
${CLI} shared plan what a workspace's repeated rules cost to carry
|
|
@@ -197,13 +213,23 @@ ${CLI} bench probes [--yes] 12 synthetic rule-compliance probes with determin
|
|
|
197
213
|
(dry-run unless --yes; grades git state, transcript and ledger,
|
|
198
214
|
and reports compliance per arm)
|
|
199
215
|
${CLI} bench variants [--yes] evaluate simt-variants rule slots on the canary suite and lock
|
|
200
|
-
winning variants in simt
|
|
216
|
+
winning variants in simt.lock.json (dry-run unless --yes;
|
|
201
217
|
re-opens when model or harness changes)
|
|
202
218
|
${CLI} bench critic precision and recall of the local critic over a labelled
|
|
203
|
-
set of historical diffs (.simt/critic-labels.jsonl;
|
|
219
|
+
set of historical diffs (.simt/local/critic-labels.jsonl;
|
|
204
220
|
overrides --labels; labels are human-written verdicts
|
|
205
221
|
under ADR-008; the critic is advisory until precision
|
|
206
222
|
reaches 0.8 on 30 labelled diffs)
|
|
223
|
+
${CLI} bench export <file> [--yes]
|
|
224
|
+
sealed export of the mined corpus: every task
|
|
225
|
+
descriptor and both hidden patches in one signed
|
|
226
|
+
JSON file, for import on another machine
|
|
227
|
+
(dry-run unless --yes; --root selects the repository)
|
|
228
|
+
${CLI} bench import <file> [--yes]
|
|
229
|
+
import a sealed corpus: verify the seal, then write
|
|
230
|
+
the task descriptors and hidden patches into the
|
|
231
|
+
repository's vault (dry-run unless --yes; --root
|
|
232
|
+
selects the repository)
|
|
207
233
|
${CLI} pack new <name> --source <spec>
|
|
208
234
|
scaffold a versioned pack: pack.json, an unmeasured
|
|
209
235
|
bench.json, and one stack rule (dry-run unless --yes;
|
|
@@ -240,6 +266,12 @@ const FLAGS = `--json structured output (compact; one document,
|
|
|
240
266
|
--workspace <path> where the skill sources live; "off" declines it
|
|
241
267
|
(default: SIMT_DEV_WORKSPACE, then the user config
|
|
242
268
|
file, then the sibling heuristic if it verifies)
|
|
269
|
+
--registry <path> which skill registry to read (skills commands and
|
|
270
|
+
graph lint; default: SIMT_REGISTRY, then the checkout's
|
|
271
|
+
own graph/skills.graph.json, then the one member of the
|
|
272
|
+
workspace that holds one)
|
|
273
|
+
--concurrency <n> compare: rows built at once (default 4, or
|
|
274
|
+
SIMT_CONCURRENCY; order-preserving whatever it is)
|
|
243
275
|
--dry-run report what would change, change nothing
|
|
244
276
|
--yes assume yes; required in automation, never prompts
|
|
245
277
|
--check report drift and write nothing (sync, ci)
|
|
@@ -301,8 +333,14 @@ const FLAGS = `--json structured output (compact; one document,
|
|
|
301
333
|
--embed index / map / brief: compute or query optional local vector embeddings
|
|
302
334
|
(off by default unless recall@10 gains at least 10 points)
|
|
303
335
|
--labels <path> bench critic: the labelled set of historical diffs to score
|
|
336
|
+
--cross-group bench ablate: compare across harness, model and experiment
|
|
337
|
+
groups instead of refusing the comparison
|
|
338
|
+
--expires <when> lessons capture: how long a captured candidate stays eligible
|
|
304
339
|
(default .simt/critic-labels.jsonl; one human-written
|
|
305
340
|
{sha, verdict} pair per line)
|
|
341
|
+
--replace bench mine: delete task files the current mine does not
|
|
342
|
+
reproduce (off by default: mining is append-only; a
|
|
343
|
+
re-mine adds, it does not replace the corpus)
|
|
306
344
|
--refresh distill / review: regenerate a proposal that is already cached
|
|
307
345
|
--local distill / review: propose the answer from the configured
|
|
308
346
|
local chat model (local.chat); off by default, which
|
|
@@ -317,17 +355,69 @@ const PRINCIPLES = `design rules:
|
|
|
317
355
|
zero dependencies a DX tool that needs an install step fails on a fresh machine
|
|
318
356
|
bounded output one fact per line, fixed field order, explicit TRUNCATED lines`;
|
|
319
357
|
|
|
320
|
-
export async function help(argv) {
|
|
321
|
-
|
|
358
|
+
export async function help(argv, dispatched) {
|
|
359
|
+
// `dispatched` is what `dispatch` already parsed. Called from a test or another
|
|
360
|
+
// command with only argv, help parses it itself.
|
|
361
|
+
const parsed =
|
|
362
|
+
dispatched === undefined
|
|
363
|
+
? parse(argv)
|
|
364
|
+
: dispatched.parseError === undefined
|
|
365
|
+
? { ok: true, value: { flags: dispatched.flags, positional: dispatched.positional } }
|
|
366
|
+
: { ok: false, error: dispatched.parseError };
|
|
322
367
|
if (!parsed.ok) {
|
|
323
368
|
jsonFailMode(rawJsonFlag(argv));
|
|
324
369
|
return fail(parsed.error.message, parsed.error.code);
|
|
325
370
|
}
|
|
326
|
-
const { flags } = parsed.value;
|
|
371
|
+
const { flags, positional } = parsed.value;
|
|
327
372
|
if (flags.version) {
|
|
328
373
|
emit((await version()).trim());
|
|
329
374
|
return 0;
|
|
330
375
|
}
|
|
376
|
+
// A reader who names one command gets that command, not the whole surface (review
|
|
377
|
+
// 0003 Q61): `simt help gate` and `simt gate --help` both printed 23 KB, so the one
|
|
378
|
+
// fact being asked for was 40 screens down.
|
|
379
|
+
const asked = commandFromHelp(positional);
|
|
380
|
+
if (asked !== null) {
|
|
381
|
+
emit(commandPage(asked));
|
|
382
|
+
return 0;
|
|
383
|
+
}
|
|
384
|
+
if (flags.json === true) {
|
|
385
|
+
emitJson(SPEC.map(specRow));
|
|
386
|
+
return 0;
|
|
387
|
+
}
|
|
388
|
+
// `--all` prints every command and every flag; the default page lists the core tier and
|
|
389
|
+
// says where the rest is. A reader asking "what can this do" needs the shape, not 23 KB
|
|
390
|
+
// of flag reference (review 0003 Q61).
|
|
391
|
+
if (flags.all === true) {
|
|
392
|
+
emit(
|
|
393
|
+
[
|
|
394
|
+
'simt-dev - shared agent rules, skills and gates for a repo ecosystem',
|
|
395
|
+
'',
|
|
396
|
+
`usage: ${CLI} <command> [args] [flags]`,
|
|
397
|
+
'',
|
|
398
|
+
'commands:',
|
|
399
|
+
COMMANDS,
|
|
400
|
+
'',
|
|
401
|
+
'flags:',
|
|
402
|
+
FLAGS,
|
|
403
|
+
'',
|
|
404
|
+
PRINCIPLES,
|
|
405
|
+
'',
|
|
406
|
+
`rulings ${CLI} rules list the decisions behind the rules you just read`,
|
|
407
|
+
].join('\n'),
|
|
408
|
+
);
|
|
409
|
+
return 0;
|
|
410
|
+
}
|
|
411
|
+
// One line per group and one per bare command: listing every subcommand with its
|
|
412
|
+
// summary does not fit in the 2 KB a reader will actually read (review 0003 Q61).
|
|
413
|
+
const groups = new Map();
|
|
414
|
+
const bare = [];
|
|
415
|
+
for (const row of SPEC) {
|
|
416
|
+
if (tierOf(row.path) !== 'core') continue;
|
|
417
|
+
const [head, sub] = row.path.split(' ');
|
|
418
|
+
if (sub === undefined) bare.push(row);
|
|
419
|
+
else groups.set(head, [...(groups.get(head) ?? []), sub]);
|
|
420
|
+
}
|
|
331
421
|
emit(
|
|
332
422
|
[
|
|
333
423
|
'simt-dev - shared agent rules, skills and gates for a repo ecosystem',
|
|
@@ -335,19 +425,12 @@ export async function help(argv) {
|
|
|
335
425
|
`usage: ${CLI} <command> [args] [flags]`,
|
|
336
426
|
'',
|
|
337
427
|
'commands:',
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
'flags:',
|
|
341
|
-
FLAGS,
|
|
428
|
+
...[...groups].map(([group, subs]) => ` ${CLI} ${group} <${subs.join('|')}>`),
|
|
429
|
+
...bare.map((row) => ` ${CLI} ${row.path.padEnd(8)} ${row.summary.length > 46 ? `${row.summary.slice(0, 43)}...` : row.summary}`),
|
|
342
430
|
'',
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// The plans ship inside the installed package but have no command that surfaces
|
|
346
|
-
// them, so naming the path would again be advice the reader cannot take. They
|
|
347
|
-
// are an implementation record; the rulings are the part a reader can act on.
|
|
348
|
-
`rulings ${CLI} rules list the decisions behind the rules you just read`,
|
|
431
|
+
`more ${CLI} help --all (every command and flag), ${CLI} help <command>`,
|
|
432
|
+
`rulings ${CLI} rules list (the decisions behind the rules)`,
|
|
349
433
|
].join('\n'),
|
|
350
|
-
{ maxBytes: flags.maxBytes ?? 0 },
|
|
351
434
|
);
|
|
352
435
|
return 0;
|
|
353
436
|
}
|
|
@@ -356,3 +439,49 @@ async function version() {
|
|
|
356
439
|
const { describeVersion } = await import('../package-version.mjs');
|
|
357
440
|
return `${describeVersion()}\n`;
|
|
358
441
|
}
|
|
442
|
+
|
|
443
|
+
/** The command a help request names, or null when it names none. */
|
|
444
|
+
function commandFromHelp(positional) {
|
|
445
|
+
const words = positional[0] === 'help' ? positional.slice(1) : positional;
|
|
446
|
+
const two = words.slice(0, 2).join(' ');
|
|
447
|
+
if (SPEC_PATHS.includes(two)) return two;
|
|
448
|
+
return SPEC_PATHS.includes(words[0]) ? words[0] : null;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** One spec row as the JSON a UI or a harness reads. */
|
|
452
|
+
function specRow(row) {
|
|
453
|
+
return { path: row.path, summary: row.summary, ...(row.defaultFor === undefined ? {} : { defaultFor: row.defaultFor }) };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const PAGE_WIDTH = 78;
|
|
457
|
+
|
|
458
|
+
/** The summary broken to the page width, so a narrow terminal keeps it readable. */
|
|
459
|
+
function wrapped(text) {
|
|
460
|
+
const lines = [];
|
|
461
|
+
let line = '';
|
|
462
|
+
for (const word of text.split(' ')) {
|
|
463
|
+
if (line !== '' && line.length + 1 + word.length > PAGE_WIDTH) {
|
|
464
|
+
lines.push(line);
|
|
465
|
+
line = word;
|
|
466
|
+
} else {
|
|
467
|
+
line = line === '' ? word : `${line} ${word}`;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (line !== '') lines.push(line);
|
|
471
|
+
return lines;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* One command's page: what it is, and where the rest of the answers are. The flags a
|
|
476
|
+
* single command declares arrive with the spec's `flags` field (Q62); until then the
|
|
477
|
+
* page points at the global list rather than inventing one per command.
|
|
478
|
+
*/
|
|
479
|
+
export function commandPage(path) {
|
|
480
|
+
const row = SPEC.find((r) => r.path === path);
|
|
481
|
+
if (row === undefined) return '';
|
|
482
|
+
const lines = [`${CLI} ${path} [args] [flags]`, '', ...wrapped(row.summary), ''];
|
|
483
|
+
if (row.defaultFor !== undefined) lines.push(`default ${CLI} ${row.defaultFor} runs this command`);
|
|
484
|
+
lines.push(`flags --json --pretty --root --max-bytes, and every global flag`);
|
|
485
|
+
lines.push(`all ${CLI} --help every command, and every flag it takes`);
|
|
486
|
+
return `${lines.join('\n')}\n`;
|
|
487
|
+
}
|