simt-dev 0.2.1 → 0.3.0
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 +239 -0
- package/bin/simt-dev.mjs +21 -2
- package/docs/decisions/ADR-064-the-context-meter-counts-what-the-tool-wrote.md +107 -0
- package/docs/decisions/ADR-065-a-pack-is-one-shared-rule-set-pinned-by-digest.md +97 -0
- package/docs/decisions/ADR-066-a-monorepo-projects-once-per-package.md +115 -0
- package/docs/decisions/ADR-067-which-harnesses-read-agents-md-is-a-column.md +110 -0
- package/docs/decisions/ADR-068-the-mcp-revision-list-cites-what-was-read.md +111 -0
- package/docs/decisions/ADR-069-the-conformance-lint-checks-the-published-specification.md +90 -0
- package/docs/decisions/ADR-070-the-json-payload-carries-its-own-version.md +91 -0
- package/docs/decisions/ADR-071-a-rule-that-can-be-narrowed-is-written-narrow.md +106 -0
- package/docs/decisions/ADR-072-the-budget-is-a-declaration-beside-the-gates.md +104 -0
- package/docs/decisions/ADR-073-a-kernel-is-a-smaller-projection-the-repository-asks-for.md +92 -0
- package/docs/decisions/ADR-074-a-rule-and-a-decision-are-readable-by-uri.md +99 -0
- package/docs/decisions/ADR-075-nothing-leaves-the-machine.md +56 -0
- package/docs/decisions/ADR-076-a-change-to-what-agents-read-is-measured.md +70 -0
- package/docs/decisions/ADR-077-the-command-card-leads-the-region-and-reads-committed-evidence.md +91 -0
- package/docs/decisions/ADR-078-a-line-the-repository-already-proves-does-not-ship.md +117 -0
- package/docs/decisions/ADR-079-the-rules-are-enforced-at-the-tool-call-from-one-policy-table.md +162 -0
- package/docs/decisions/ADR-080-the-tools-own-names-are-not-repositories-and-neither-reader-decides-by-shape.md +99 -0
- package/docs/decisions/ADR-081-a-tracker-is-read-through-the-repositorys-template.md +36 -0
- package/docs/decisions/ADR-082-the-tracker-override-is-a-manifest-key.md +35 -0
- package/package.json +2 -1
- package/rules/core.md +1 -0
- package/rules/stacks/android.md +2 -0
- package/rules/stacks/cloudflare-workers.md +2 -0
- package/rules/stacks/connectiq.md +1 -0
- package/rules/stacks/container.md +2 -0
- package/rules/stacks/dart.md +2 -0
- package/rules/stacks/deno.md +2 -0
- package/rules/stacks/dotnet.md +2 -0
- package/rules/stacks/elixir.md +2 -0
- package/rules/stacks/go.md +2 -0
- package/rules/stacks/jvm.md +2 -0
- package/rules/stacks/node.md +2 -0
- package/rules/stacks/python.md +2 -0
- package/rules/stacks/react-native.md +2 -0
- package/rules/stacks/react-web.md +2 -0
- package/rules/stacks/ruby.md +2 -0
- package/rules/stacks/rust.md +2 -0
- package/rules/stacks/swift.md +2 -0
- package/rules/stacks/typescript.md +2 -0
- package/rules/stacks/uv.md +2 -0
- package/src/agenthooks/decide.mjs +123 -0
- package/src/agenthooks/policy.mjs +78 -0
- package/src/agenthooks/render.mjs +240 -0
- package/src/argv.mjs +55 -1
- package/src/bench/ablate.mjs +630 -0
- package/src/bench/adapters.json +149 -0
- package/src/bench/grade.mjs +229 -0
- package/src/bench/mine.mjs +811 -0
- package/src/bench/probes.mjs +1350 -0
- package/src/bench/report.mjs +899 -0
- package/src/bench/run.mjs +1002 -0
- package/src/commands/agenthook.mjs +282 -0
- package/src/commands/bench.mjs +359 -0
- package/src/commands/compare.mjs +15 -0
- package/src/commands/graph.mjs +45 -21
- package/src/commands/harness.mjs +301 -0
- package/src/commands/help.mjs +73 -2
- package/src/commands/index.mjs +67 -25
- package/src/commands/init.mjs +12 -8
- package/src/commands/mcp.mjs +20 -5
- package/src/commands/plan.mjs +99 -0
- package/src/commands/rules.mjs +42 -57
- package/src/commands/skills.mjs +67 -92
- package/src/commands/skillsinstall.mjs +17 -2
- package/src/commands/sync.mjs +62 -6
- package/src/commands/tokens.mjs +169 -0
- package/src/compare/row.mjs +73 -2
- package/src/decisions/index.mjs +23 -5
- package/src/graph/spec.mjs +227 -0
- package/src/graph/speccheck.mjs +68 -0
- package/src/hooks/dispatcher.mjs +35 -3
- package/src/kernel/card.mjs +254 -0
- package/src/kernel/inferability.mjs +188 -0
- package/src/mcp/resources.mjs +157 -0
- package/src/mcp/schema.mjs +139 -0
- package/src/mcp/server.mjs +228 -20
- package/src/mcp/tools.mjs +372 -1
- package/src/measure/context.mjs +542 -0
- package/src/measure/loaderView.mjs +435 -0
- package/src/measure/session.mjs +267 -0
- package/src/monorepo.mjs +339 -0
- package/src/output/index.mjs +78 -2
- package/src/packs.mjs +182 -0
- package/src/plan/index.mjs +650 -0
- package/src/plan/template.mjs +331 -0
- package/src/projection/loaders.mjs +689 -0
- package/src/projection/manifest.mjs +114 -3
- package/src/projection/project.mjs +140 -9
- package/src/projection/rules.mjs +365 -22
- package/src/projection/surfaces.mjs +155 -23
- package/src/projection/targets.mjs +37 -0
- package/src/toolwords.mjs +69 -0
- package/templates/plan/tracker.json +36 -0
package/src/mcp/tools.mjs
CHANGED
|
@@ -27,6 +27,7 @@ import { discover } from '../compare/discover.mjs';
|
|
|
27
27
|
import { buildRow, summarise } from '../compare/row.mjs';
|
|
28
28
|
import { GATES } from '../hooks/gates.mjs';
|
|
29
29
|
import { dirtyPaths, parsePathList, readBody } from '../commands/skills.mjs';
|
|
30
|
+
import { planNext, planDone } from '../plan/index.mjs';
|
|
30
31
|
import { resolveWorkspace } from '../workspace.mjs';
|
|
31
32
|
import { measureSkill } from '../graph/load.mjs';
|
|
32
33
|
import { CLI } from '../name.mjs';
|
|
@@ -35,6 +36,307 @@ const GATE_KINDS = new Map(Object.entries(GATES).map(([name, g]) => [name, g.kin
|
|
|
35
36
|
|
|
36
37
|
/** A schema with no required fields still needs the object declared. */
|
|
37
38
|
const noArgs = { type: 'object', properties: {}, required: [] };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Output schemas, one per tool, describing what a SUCCESSFUL call returns.
|
|
42
|
+
*
|
|
43
|
+
* Every one of these tools is a reader: none writes, and none writes twice. The
|
|
44
|
+
* annotations say so, and the schemas say what comes back — because a client that can
|
|
45
|
+
* validate an answer against a declared shape catches a wrong answer at the boundary,
|
|
46
|
+
* while one handed a bag of JSON has to trust that the tool meant it.
|
|
47
|
+
*
|
|
48
|
+
* Properties are required unless the payload can legitimately omit them: `error` is
|
|
49
|
+
* absent when there is none, `body` is null when there is none, and a schema that
|
|
50
|
+
* required the exception would describe a shape that never occurs. `additionalProperties`
|
|
51
|
+
* is left open, which is what the 2026-07-28 revision permits and what a reader wants:
|
|
52
|
+
* these payloads are data, and a new field from a future release should not make an
|
|
53
|
+
* older client's validation fail.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* The shape of a failure, exported because a client validating an answer needs it and
|
|
57
|
+
* because the test that checks every tool's answer needs it for the failures. Two
|
|
58
|
+
* copies of this schema would drift, and the copy that drifted would be the one nobody
|
|
59
|
+
* validates against - which is exactly how a remedy quietly stops being a string.
|
|
60
|
+
*/
|
|
61
|
+
export const ERROR_SHAPE = {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: { error: { type: 'string' }, remedy: { type: ['string', 'null'] } },
|
|
64
|
+
required: ['error'],
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const output = {
|
|
68
|
+
doctor: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
root: { type: 'string' },
|
|
72
|
+
workspace: {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
// Null is the honest value for a repository that is not inside a workspace:
|
|
76
|
+
// there is no root to name, and naming the repository as one would be a claim
|
|
77
|
+
// about the reader's directory layout that nothing established.
|
|
78
|
+
root: { type: ['string', 'null'] },
|
|
79
|
+
source: { type: ['string', 'null'] },
|
|
80
|
+
detail: { type: ['string', 'null'] },
|
|
81
|
+
},
|
|
82
|
+
required: ['root', 'source'],
|
|
83
|
+
},
|
|
84
|
+
stack: { type: 'array', items: { type: 'string' } },
|
|
85
|
+
facts: { type: 'object', additionalProperties: { type: ['string', 'null'] } },
|
|
86
|
+
signals: { type: 'array', items: { type: 'string' } },
|
|
87
|
+
// One entry per signal, naming the file that proved it. The payload is a list of
|
|
88
|
+
// paths, not of records - `fingerprint` returns evidence as the paths themselves.
|
|
89
|
+
evidence: { type: 'array', items: { type: 'string' } },
|
|
90
|
+
manifest: { type: ['object', 'null'] },
|
|
91
|
+
error: { type: ['string', 'null'] },
|
|
92
|
+
},
|
|
93
|
+
required: ['root', 'workspace', 'stack', 'facts', 'signals', 'evidence'],
|
|
94
|
+
},
|
|
95
|
+
skills_index: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
skills: { type: 'number' },
|
|
99
|
+
totalBytes: { type: 'number' },
|
|
100
|
+
deferred: { type: 'array', items: { type: 'string' } },
|
|
101
|
+
workspace: { type: 'object' },
|
|
102
|
+
verified: { type: 'boolean' },
|
|
103
|
+
entries: {
|
|
104
|
+
type: 'array',
|
|
105
|
+
items: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
name: { type: 'string' },
|
|
109
|
+
summary: { type: 'string' },
|
|
110
|
+
bytes: { type: 'number' },
|
|
111
|
+
stack: { type: 'array', items: { type: 'string' } },
|
|
112
|
+
deferred: { type: 'boolean' },
|
|
113
|
+
},
|
|
114
|
+
required: ['name', 'bytes'],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
required: ['skills', 'totalBytes', 'entries'],
|
|
119
|
+
},
|
|
120
|
+
skills_brief: {
|
|
121
|
+
type: 'object',
|
|
122
|
+
properties: {
|
|
123
|
+
repo: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
root: { type: 'string' },
|
|
127
|
+
stack: { type: 'array', items: { type: 'string' } },
|
|
128
|
+
facts: { type: 'array', items: { type: 'string' } },
|
|
129
|
+
},
|
|
130
|
+
required: ['root', 'stack', 'facts'],
|
|
131
|
+
},
|
|
132
|
+
task: { type: ['string', 'null'] },
|
|
133
|
+
budget: { type: 'number' },
|
|
134
|
+
inlineBytes: { type: 'number' },
|
|
135
|
+
selected: {
|
|
136
|
+
type: 'array',
|
|
137
|
+
items: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: {
|
|
140
|
+
name: { type: 'string' },
|
|
141
|
+
bytes: { type: 'number' },
|
|
142
|
+
summary: { type: 'string' },
|
|
143
|
+
why: { type: 'array', items: { type: 'string' } },
|
|
144
|
+
},
|
|
145
|
+
required: ['name', 'bytes', 'why'],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
deferred: {
|
|
149
|
+
type: 'array',
|
|
150
|
+
items: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: { name: { type: 'string' }, bytes: { type: 'number' }, reason: { type: 'string' } },
|
|
153
|
+
required: ['name', 'reason'],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
notSelected: {
|
|
157
|
+
type: 'array',
|
|
158
|
+
items: {
|
|
159
|
+
type: 'object',
|
|
160
|
+
properties: { name: { type: 'string' }, reason: { type: 'string' } },
|
|
161
|
+
required: ['name', 'reason'],
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
required: ['repo', 'budget', 'inlineBytes', 'selected', 'deferred', 'notSelected'],
|
|
166
|
+
},
|
|
167
|
+
skills_show: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
name: { type: 'string' },
|
|
171
|
+
summary: { type: 'string' },
|
|
172
|
+
bytes: { type: 'number' },
|
|
173
|
+
capabilities: { type: 'array', items: { type: 'string' } },
|
|
174
|
+
stack: { type: 'array', items: { type: 'string' } },
|
|
175
|
+
deferred: { type: 'boolean' },
|
|
176
|
+
source: { type: ['string', 'null'] },
|
|
177
|
+
readFrom: { type: 'string', enum: ['ok', 'empty', 'unavailable'] },
|
|
178
|
+
requires: { type: 'array', items: { type: 'string' } },
|
|
179
|
+
variants: {
|
|
180
|
+
type: 'array',
|
|
181
|
+
items: {
|
|
182
|
+
type: 'object',
|
|
183
|
+
properties: { id: { type: 'string' }, stack: { type: 'array', items: { type: 'string' } }, bytes: { type: 'number' } },
|
|
184
|
+
required: ['id'],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
maxBytes: { type: 'number' },
|
|
188
|
+
body: { type: ['string', 'null'] },
|
|
189
|
+
},
|
|
190
|
+
required: ['name', 'bytes', 'readFrom', 'requires', 'variants'],
|
|
191
|
+
},
|
|
192
|
+
skills_find: {
|
|
193
|
+
type: 'object',
|
|
194
|
+
properties: {
|
|
195
|
+
query: { type: 'string' },
|
|
196
|
+
results: {
|
|
197
|
+
type: 'array',
|
|
198
|
+
items: {
|
|
199
|
+
type: 'object',
|
|
200
|
+
properties: {
|
|
201
|
+
name: { type: 'string' },
|
|
202
|
+
score: { type: 'number' },
|
|
203
|
+
summary: { type: 'string' },
|
|
204
|
+
why: { type: 'array', items: { type: 'string' } },
|
|
205
|
+
},
|
|
206
|
+
required: ['name', 'score', 'why'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
required: ['query', 'results'],
|
|
211
|
+
},
|
|
212
|
+
skills_why: {
|
|
213
|
+
type: 'object',
|
|
214
|
+
properties: {
|
|
215
|
+
name: { type: 'string' },
|
|
216
|
+
score: { type: 'number' },
|
|
217
|
+
compatible: { type: 'boolean' },
|
|
218
|
+
reasons: { type: 'array', items: { type: 'string' } },
|
|
219
|
+
repo: {
|
|
220
|
+
type: 'object',
|
|
221
|
+
properties: { root: { type: 'string' }, signals: { type: 'array', items: { type: 'string' } } },
|
|
222
|
+
},
|
|
223
|
+
task: { type: ['string', 'null'] },
|
|
224
|
+
pathsSeen: { type: 'array', items: { type: 'string' } },
|
|
225
|
+
},
|
|
226
|
+
required: ['name', 'score', 'compatible', 'reasons'],
|
|
227
|
+
},
|
|
228
|
+
rules_list: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
sha: { type: 'string' },
|
|
232
|
+
notes: { type: 'array', items: { type: 'string' } },
|
|
233
|
+
rules: {
|
|
234
|
+
type: 'array',
|
|
235
|
+
items: {
|
|
236
|
+
type: 'object',
|
|
237
|
+
properties: {
|
|
238
|
+
id: { type: ['string', 'null'] },
|
|
239
|
+
title: { type: ['string', 'null'] },
|
|
240
|
+
// A profile may name one signal or several, and the frontmatter keeps both
|
|
241
|
+
// spellings. Describing only the list would make a conforming rule look
|
|
242
|
+
// broken.
|
|
243
|
+
applies: { anyOf: [{ type: 'array', items: { type: 'string' } }, { type: 'string' }] },
|
|
244
|
+
origin: { type: 'string' },
|
|
245
|
+
source: { type: 'string' },
|
|
246
|
+
bytes: { type: 'number' },
|
|
247
|
+
adrs: { type: 'array', items: { type: 'string' } },
|
|
248
|
+
error: { type: ['string', 'null'] },
|
|
249
|
+
selected: { type: 'boolean' },
|
|
250
|
+
},
|
|
251
|
+
required: ['source', 'bytes', 'selected'],
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
required: ['sha', 'rules'],
|
|
256
|
+
},
|
|
257
|
+
rules_why: {
|
|
258
|
+
type: 'object',
|
|
259
|
+
properties: {
|
|
260
|
+
direction: { type: 'string', enum: ['rule', 'decision'] },
|
|
261
|
+
id: { type: 'string' },
|
|
262
|
+
title: { type: ['string', 'null'] },
|
|
263
|
+
status: { type: 'string' },
|
|
264
|
+
source: { type: 'string' },
|
|
265
|
+
origin: { type: 'string' },
|
|
266
|
+
uncited: { type: 'boolean' },
|
|
267
|
+
readWith: { type: 'string' },
|
|
268
|
+
supersededBy: { type: ['string', 'null'] },
|
|
269
|
+
supersedes: { type: 'array', items: { type: 'string' } },
|
|
270
|
+
// A decision record may be partially superseded; the record carries the list of
|
|
271
|
+
// what it replaced, so this is a list and not a flag.
|
|
272
|
+
partial: { type: ['boolean', 'array'] },
|
|
273
|
+
decisions: { type: 'array', items: { type: 'object' } },
|
|
274
|
+
rules: { type: 'array', items: { type: 'string' } },
|
|
275
|
+
},
|
|
276
|
+
required: ['direction', 'id'],
|
|
277
|
+
},
|
|
278
|
+
check: {
|
|
279
|
+
type: 'object',
|
|
280
|
+
properties: {
|
|
281
|
+
root: { type: 'string' },
|
|
282
|
+
ok: { type: 'boolean' },
|
|
283
|
+
findings: {
|
|
284
|
+
type: 'array',
|
|
285
|
+
items: {
|
|
286
|
+
type: 'object',
|
|
287
|
+
properties: {
|
|
288
|
+
file: { type: 'string' },
|
|
289
|
+
status: { type: 'string' },
|
|
290
|
+
detail: { type: ['string', 'null'] },
|
|
291
|
+
remedy: { type: ['string', 'null'] },
|
|
292
|
+
},
|
|
293
|
+
required: ['file', 'status'],
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
required: ['root', 'ok', 'findings'],
|
|
298
|
+
},
|
|
299
|
+
compare: {
|
|
300
|
+
type: 'object',
|
|
301
|
+
properties: {
|
|
302
|
+
root: { type: 'string' },
|
|
303
|
+
shape: { type: 'string', enum: ['repo', 'workspace'] },
|
|
304
|
+
expectedSha: { type: 'string' },
|
|
305
|
+
summary: { type: 'object' },
|
|
306
|
+
repos: { type: 'array', items: { type: 'object' } },
|
|
307
|
+
worktrees: { type: 'array', items: { type: 'object' } },
|
|
308
|
+
directories: { type: 'array', items: { type: 'string' } },
|
|
309
|
+
},
|
|
310
|
+
required: ['root', 'shape', 'expectedSha', 'summary', 'repos'],
|
|
311
|
+
},
|
|
312
|
+
plan_next: {
|
|
313
|
+
type: 'object',
|
|
314
|
+
properties: {
|
|
315
|
+
root: { type: 'string' },
|
|
316
|
+
next: { type: ['object', 'null'] },
|
|
317
|
+
reason: { type: ['string', 'null'] },
|
|
318
|
+
},
|
|
319
|
+
required: ['root', 'next', 'reason'],
|
|
320
|
+
},
|
|
321
|
+
plan_done: {
|
|
322
|
+
type: 'object',
|
|
323
|
+
properties: {
|
|
324
|
+
root: { type: 'string' },
|
|
325
|
+
id: { type: 'string' },
|
|
326
|
+
doc: { type: 'string' },
|
|
327
|
+
line: { type: 'number' },
|
|
328
|
+
from: { type: 'string' },
|
|
329
|
+
to: { type: 'string' },
|
|
330
|
+
wouldChange: { type: 'boolean' },
|
|
331
|
+
dryRun: { type: 'boolean' },
|
|
332
|
+
remedy: { type: ['string', 'null'] },
|
|
333
|
+
},
|
|
334
|
+
required: ['root', 'id', 'wouldChange', 'dryRun'],
|
|
335
|
+
},
|
|
336
|
+
/** The shape of every tool failure, which is a result and not a protocol error. */
|
|
337
|
+
error: ERROR_SHAPE,
|
|
338
|
+
};
|
|
339
|
+
|
|
38
340
|
const rootArg = {
|
|
39
341
|
type: 'object',
|
|
40
342
|
properties: { root: { type: 'string', description: 'repository root; defaults to the editor cwd' } },
|
|
@@ -57,6 +359,7 @@ async function registry(args) {
|
|
|
57
359
|
|
|
58
360
|
export const TOOLS = [
|
|
59
361
|
{
|
|
362
|
+
outputSchema: output.doctor,
|
|
60
363
|
name: 'doctor',
|
|
61
364
|
description:
|
|
62
365
|
'Classify a repository: its stack tags, the emitted facts with the file that proved each, and whether a simt-dev manifest is present. Call this first when you do not yet know what a repo is.',
|
|
@@ -79,6 +382,7 @@ export const TOOLS = [
|
|
|
79
382
|
},
|
|
80
383
|
|
|
81
384
|
{
|
|
385
|
+
outputSchema: output.skills_index,
|
|
82
386
|
name: 'skills_index',
|
|
83
387
|
description:
|
|
84
388
|
'The full skill catalogue: every skill with its summary, size, stack tags and whether it is deferred. Cheap enough to always afford, and the fallback when brief returns nothing useful.',
|
|
@@ -99,6 +403,7 @@ export const TOOLS = [
|
|
|
99
403
|
},
|
|
100
404
|
|
|
101
405
|
{
|
|
406
|
+
outputSchema: output.skills_brief,
|
|
102
407
|
name: 'skills_brief',
|
|
103
408
|
description:
|
|
104
409
|
'THE entry point. Resolve the skill set for a task in a repository. Returns what was selected, why each was selected, what was deferred, and what was NOT selected with the reason - the last part matters, because it is what lets you override the resolver instead of guessing at it.',
|
|
@@ -165,6 +470,7 @@ export const TOOLS = [
|
|
|
165
470
|
},
|
|
166
471
|
|
|
167
472
|
{
|
|
473
|
+
outputSchema: output.skills_show,
|
|
168
474
|
name: 'skills_show',
|
|
169
475
|
description: 'One skill body, with the metadata needed to decide whether to trust it: source path, which of the two locations it was read from, and its cited decisions.',
|
|
170
476
|
inputSchema: {
|
|
@@ -206,6 +512,7 @@ export const TOOLS = [
|
|
|
206
512
|
},
|
|
207
513
|
|
|
208
514
|
{
|
|
515
|
+
outputSchema: output.skills_find,
|
|
209
516
|
name: 'skills_find',
|
|
210
517
|
description: 'Raw search across capability, keyword and summary. Use when skills_brief has nothing and you suspect a skill exists.',
|
|
211
518
|
inputSchema: {
|
|
@@ -230,6 +537,7 @@ export const TOOLS = [
|
|
|
230
537
|
},
|
|
231
538
|
|
|
232
539
|
{
|
|
540
|
+
outputSchema: output.skills_why,
|
|
233
541
|
name: 'skills_why',
|
|
234
542
|
description:
|
|
235
543
|
'The signal chain for one skill in one repository: its score, the reasons behind it, whether the stack gate admits it at all, and what it would take to make it selected.',
|
|
@@ -263,6 +571,7 @@ export const TOOLS = [
|
|
|
263
571
|
},
|
|
264
572
|
|
|
265
573
|
{
|
|
574
|
+
outputSchema: output.rules_list,
|
|
266
575
|
name: 'rules_list',
|
|
267
576
|
description:
|
|
268
577
|
'The rule catalogue, and which rules a given repository actually receives. Pass `root` to get the selection rather than just the catalogue.',
|
|
@@ -300,9 +609,10 @@ export const TOOLS = [
|
|
|
300
609
|
},
|
|
301
610
|
|
|
302
611
|
{
|
|
612
|
+
outputSchema: output.rules_why,
|
|
303
613
|
name: 'rules_why',
|
|
304
614
|
description:
|
|
305
|
-
'Why a rule exists. Give a rule id for the decisions that settled it and whether each is still in force, or an ADR id for the rules that decision
|
|
615
|
+
'Why a rule exists. Give a rule id for the decisions that settled it and whether each is still in force, or an ADR id for the rules that decision repeats. A rule citing no decision reports that - it is a finding, not an empty answer.',
|
|
306
616
|
inputSchema: {
|
|
307
617
|
type: 'object',
|
|
308
618
|
properties: { what: { type: 'string', description: 'a rule id or ADR-NNN' } },
|
|
@@ -355,6 +665,7 @@ export const TOOLS = [
|
|
|
355
665
|
},
|
|
356
666
|
|
|
357
667
|
{
|
|
668
|
+
outputSchema: output.check,
|
|
358
669
|
name: 'check',
|
|
359
670
|
description:
|
|
360
671
|
'The gate for one repository: is its generated region current, unmanaged, drifted or malformed, and does any rule file lack an id. Read-only - it never repairs.',
|
|
@@ -371,6 +682,7 @@ export const TOOLS = [
|
|
|
371
682
|
},
|
|
372
683
|
|
|
373
684
|
{
|
|
685
|
+
outputSchema: output.compare,
|
|
374
686
|
name: 'compare',
|
|
375
687
|
description:
|
|
376
688
|
'The organisation-wide matrix: every repository under the root, its adoption, region state, pinned simt-dev SHA, hook routing and declared gates, plus the problems found. This is the command that replaces reconstructing the estate by hand.',
|
|
@@ -401,6 +713,65 @@ export const TOOLS = [
|
|
|
401
713
|
};
|
|
402
714
|
},
|
|
403
715
|
},
|
|
716
|
+
{
|
|
717
|
+
outputSchema: output.plan_next,
|
|
718
|
+
name: 'plan_next',
|
|
719
|
+
description: 'The next queued slice whose dependencies are complete, and only that slice\'s section. Pass id to read one slice whether or not it is ready.',
|
|
720
|
+
inputSchema: {
|
|
721
|
+
type: 'object',
|
|
722
|
+
properties: {
|
|
723
|
+
root: { type: 'string', description: 'repository root; defaults to the editor cwd' },
|
|
724
|
+
id: { type: 'string', description: 'slice id; when given, return that slice' },
|
|
725
|
+
},
|
|
726
|
+
required: [],
|
|
727
|
+
},
|
|
728
|
+
async run(args) {
|
|
729
|
+
const root = rootOf(args);
|
|
730
|
+
const id = typeof args?.id === 'string' && args.id.length > 0 ? args.id : null;
|
|
731
|
+
const result = await planNext(root, id);
|
|
732
|
+
if (result.error) throw Object.assign(new Error(result.error), { remedy: result.remedy ?? null });
|
|
733
|
+
return { root: result.root, next: result.next, reason: result.reason };
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
outputSchema: output.plan_done,
|
|
738
|
+
name: 'plan_done',
|
|
739
|
+
// Same function as the command, and deliberately a preview. This surface does
|
|
740
|
+
// not write: the row change is a diff, and the command applies it behind --yes.
|
|
741
|
+
description: 'Preview the one-row rewrite for a slice. The write stays on the plan done command, behind --yes.',
|
|
742
|
+
inputSchema: {
|
|
743
|
+
type: 'object',
|
|
744
|
+
properties: {
|
|
745
|
+
root: { type: 'string', description: 'repository root; defaults to the editor cwd' },
|
|
746
|
+
id: { type: 'string', description: 'slice id' },
|
|
747
|
+
sha: { type: 'string', description: 'commit sha that closed the slice' },
|
|
748
|
+
test: { type: 'string', description: 'test command that closed it' },
|
|
749
|
+
state: { type: 'string', description: 'target state; omitted means the completed state of the repository template (Complete for tracker)' },
|
|
750
|
+
},
|
|
751
|
+
required: ['id'],
|
|
752
|
+
},
|
|
753
|
+
async run(args) {
|
|
754
|
+
const root = rootOf(args);
|
|
755
|
+
const result = await planDone(root, args?.id, {
|
|
756
|
+
sha: args?.sha ?? null,
|
|
757
|
+
test: args?.test ?? null,
|
|
758
|
+
state: args?.state ?? null,
|
|
759
|
+
dryRun: true,
|
|
760
|
+
});
|
|
761
|
+
if (result.error) throw Object.assign(new Error(result.error), { remedy: result.remedy ?? null });
|
|
762
|
+
return {
|
|
763
|
+
root: result.root,
|
|
764
|
+
id: result.id,
|
|
765
|
+
doc: result.doc,
|
|
766
|
+
line: result.line,
|
|
767
|
+
from: result.from,
|
|
768
|
+
to: result.to,
|
|
769
|
+
wouldChange: result.wouldChange,
|
|
770
|
+
dryRun: true,
|
|
771
|
+
remedy: result.remedy,
|
|
772
|
+
};
|
|
773
|
+
},
|
|
774
|
+
},
|
|
404
775
|
];
|
|
405
776
|
|
|
406
777
|
export function toolNames() {
|