@intentset/cli 0.2.0 → 0.4.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/dist/agents.d.ts +5 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +146 -0
- package/dist/agents.js.map +1 -0
- package/dist/commands/context.d.ts +14 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +34 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +44 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/review.d.ts +20 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +52 -8
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +38 -16
- package/dist/commands/serve.js.map +1 -1
- package/dist/git.d.ts +8 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +15 -0
- package/dist/git.js.map +1 -1
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -13
- package/dist/main.js.map +1 -1
- package/dist/slices.d.ts +24 -0
- package/dist/slices.d.ts.map +1 -0
- package/dist/slices.js +48 -0
- package/dist/slices.js.map +1 -0
- package/package.json +9 -9
- package/src/agents.ts +150 -0
- package/src/commands/context.ts +39 -1
- package/src/commands/init.ts +45 -10
- package/src/commands/review.ts +66 -9
- package/src/commands/serve.ts +34 -14
- package/src/git.ts +15 -0
- package/src/main.ts +33 -13
- package/src/slices.ts +54 -0
package/src/main.ts
CHANGED
|
@@ -33,10 +33,12 @@ export type { Io } from "./output.ts";
|
|
|
33
33
|
export const USAGE = `usage: intentset <command> [options]
|
|
34
34
|
|
|
35
35
|
commands
|
|
36
|
-
init [--repository <name>] [--example]
|
|
37
|
-
create .intentset/config.yaml
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
init [--repository <name>] [--example] [--agents]
|
|
37
|
+
create .intentset/config.yaml, an empty .intentset/registries.yaml and
|
|
38
|
+
.intentset/agents.md, the guide that tells coding agents how to keep the
|
|
39
|
+
model current; --example adds the scheduling example under
|
|
40
|
+
product/scheduling/; --agents writes only the guide, for a repository
|
|
41
|
+
already initialized. Never overwrites a file.
|
|
40
42
|
validate every check the level asks for; exit 1 when any diagnostic is an error
|
|
41
43
|
graph [--format json] [--include-bodies] [--release <product>:<label>] [--out <file>]
|
|
42
44
|
[--generated-at <time>] [--report evidence|knowledge|impact|ownership|all]...
|
|
@@ -52,9 +54,14 @@ commands
|
|
|
52
54
|
[--tool-version <v>]
|
|
53
55
|
turn a test report into run records bound to this commit and graph
|
|
54
56
|
impact <ID> what depends on an artifact: direct, candidates, review context, ancestors
|
|
55
|
-
context <ID> [--include-restricted]
|
|
56
|
-
the bounded engineering context of an artifact, with paths and bodies
|
|
57
|
-
|
|
57
|
+
context <ID|path> [--include-restricted]
|
|
58
|
+
the bounded engineering context of an artifact, with paths and bodies;
|
|
59
|
+
given a file a slice claims, the context of that slice
|
|
60
|
+
review [--base <ref>] [--fail-on-drift]
|
|
61
|
+
the local review report: checks, coverage, the impact of what changed,
|
|
62
|
+
and each slice whose code changed while its records did not;
|
|
63
|
+
--fail-on-drift exits 1 for any such slice no commit acknowledged with
|
|
64
|
+
an Intentset-Unchanged trailer
|
|
58
65
|
publish --visibility <v> --audience <a> --product <ID> --release <r> --role <r> --edition <e>
|
|
59
66
|
[--flag <f>]... [--authorized-internal] [--authorized-restricted] --out <dir> [--html]
|
|
60
67
|
[--published-at <time>]
|
|
@@ -84,7 +91,8 @@ options
|
|
|
84
91
|
(for mcp, --mode names the server's mode instead)
|
|
85
92
|
-h, --help show this help
|
|
86
93
|
|
|
87
|
-
exit codes: 0 no errors, 1 validation errors,
|
|
94
|
+
exit codes: 0 no errors, 1 validation errors (or, with review --fail-on-drift, unacknowledged drift),
|
|
95
|
+
2 invocation or tool failure`;
|
|
88
96
|
|
|
89
97
|
const COMMANDS = [
|
|
90
98
|
"init",
|
|
@@ -103,7 +111,7 @@ const COMMANDS = [
|
|
|
103
111
|
const GLOBAL = ["root", "json", "carrier", "level", "help"];
|
|
104
112
|
const LEVEL_OPTIONS = ["evidence", "product", "release", "mode", "baseline"];
|
|
105
113
|
const COMMAND_OPTIONS: Record<string, string[]> = {
|
|
106
|
-
init: ["repository", "example"],
|
|
114
|
+
init: ["repository", "example", "agents"],
|
|
107
115
|
validate: LEVEL_OPTIONS,
|
|
108
116
|
graph: [
|
|
109
117
|
"format",
|
|
@@ -131,7 +139,7 @@ const COMMAND_OPTIONS: Record<string, string[]> = {
|
|
|
131
139
|
],
|
|
132
140
|
impact: LEVEL_OPTIONS,
|
|
133
141
|
context: ["include-restricted", ...LEVEL_OPTIONS],
|
|
134
|
-
review: ["base", ...LEVEL_OPTIONS],
|
|
142
|
+
review: ["base", "fail-on-drift", ...LEVEL_OPTIONS],
|
|
135
143
|
serve: ["port", "host", "out", ...LEVEL_OPTIONS],
|
|
136
144
|
mcp: [
|
|
137
145
|
"mode",
|
|
@@ -168,7 +176,7 @@ const POSITIONALS: Record<string, { sub?: string; count: number; what?: string }
|
|
|
168
176
|
architecture: { sub: "check", count: 0 },
|
|
169
177
|
evidence: { sub: "import", count: 1, what: "a report file" },
|
|
170
178
|
impact: { count: 1, what: "an artifact ID" },
|
|
171
|
-
context: { count: 1, what: "an artifact ID" },
|
|
179
|
+
context: { count: 1, what: "an artifact ID or a file path" },
|
|
172
180
|
};
|
|
173
181
|
|
|
174
182
|
export async function main(argv: string[], io: Io): Promise<number> {
|
|
@@ -228,7 +236,12 @@ export async function main(argv: string[], io: Io): Promise<number> {
|
|
|
228
236
|
return usage(`--mode ${values.mode}: the modes are migration and strict`);
|
|
229
237
|
}
|
|
230
238
|
if (command === "init") {
|
|
231
|
-
|
|
239
|
+
if (values.agents && values.example)
|
|
240
|
+
return usage("--agents writes only the guide; it does not combine with --example");
|
|
241
|
+
return initCommand(
|
|
242
|
+
{ root: values.root, repository: values.repository, example: values.example, agentsOnly: values.agents },
|
|
243
|
+
io,
|
|
244
|
+
);
|
|
232
245
|
}
|
|
233
246
|
|
|
234
247
|
// Evidence scope: --product with --release, or graph's --release <product>:<label>.
|
|
@@ -321,7 +334,12 @@ export async function main(argv: string[], io: Io): Promise<number> {
|
|
|
321
334
|
}
|
|
322
335
|
const session = openSession(command, sessionOptions(level), io);
|
|
323
336
|
if (typeof session === "number") return session;
|
|
324
|
-
return reviewCommand(
|
|
337
|
+
return reviewCommand(
|
|
338
|
+
session,
|
|
339
|
+
{ base: values.base, levelReason: reason, failOnDrift: values["fail-on-drift"] },
|
|
340
|
+
values.json,
|
|
341
|
+
io,
|
|
342
|
+
);
|
|
325
343
|
}
|
|
326
344
|
case "serve": {
|
|
327
345
|
const port = values.port === undefined ? 3000 : Number(values.port);
|
|
@@ -391,6 +409,8 @@ function parse(argv: string[]) {
|
|
|
391
409
|
help: { type: "boolean", short: "h", default: false },
|
|
392
410
|
repository: { type: "string" },
|
|
393
411
|
example: { type: "boolean", default: false },
|
|
412
|
+
agents: { type: "boolean", default: false },
|
|
413
|
+
"fail-on-drift": { type: "boolean", default: false },
|
|
394
414
|
format: { type: "string" },
|
|
395
415
|
"include-bodies": { type: "boolean", default: false },
|
|
396
416
|
release: { type: "string" },
|
package/src/slices.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slices, the code they claim and the records that describe them, for
|
|
3
|
+
* `review`'s list of slices whose code changed while their records did not
|
|
4
|
+
* (Core §10) and for `context <path>`.
|
|
5
|
+
*
|
|
6
|
+
* A slice's code is what its `source`, `backend` and `contract` claims match;
|
|
7
|
+
* its `verification` and `documentation` claims are checks and prose, not
|
|
8
|
+
* implementation. The records that describe a slice are the slice itself, the
|
|
9
|
+
* behaviors it implements, the rules that govern them, the scenarios that
|
|
10
|
+
* illustrate them, the verifications of any of those, the contracts it
|
|
11
|
+
* exposes, and the decisions that inform the slice, its behaviors or its
|
|
12
|
+
* contracts. Knowledge is left out: it explains the model to an audience, and
|
|
13
|
+
* review pins already mark it for review when the model changes.
|
|
14
|
+
*/
|
|
15
|
+
import { type Artifact, compareStrings, type Graph } from "@intentset/core";
|
|
16
|
+
import { matchGlob } from "./glob.ts";
|
|
17
|
+
|
|
18
|
+
const CODE_CLAIMS = new Set(["source", "backend", "contract"]);
|
|
19
|
+
|
|
20
|
+
/** Every slice that is not retired and has slice metadata, sorted by ID. */
|
|
21
|
+
export function activeSlices(graph: Graph): Artifact[] {
|
|
22
|
+
return [...graph.artifacts.values()]
|
|
23
|
+
.filter((a) => a.meta.type === "slice" && a.meta.status !== "retired" && a.meta.slice !== undefined)
|
|
24
|
+
.sort((a, b) => compareStrings(a.meta.id, b.meta.id));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The slices with any claim matching `path`, sorted by ID. */
|
|
28
|
+
export function claimingSlices(graph: Graph, path: string): Artifact[] {
|
|
29
|
+
return activeSlices(graph).filter((slice) => slice.meta.slice?.claims.some((claim) => matchGlob(claim.path, path)));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** True when one of the slice's source, backend or contract claims matches `path`. */
|
|
33
|
+
export function isSliceCode(slice: Artifact, path: string): boolean {
|
|
34
|
+
return slice.meta.slice?.claims.some((claim) => CODE_CLAIMS.has(claim.kind) && matchGlob(claim.path, path)) ?? false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The IDs of the records that describe a slice, the slice included, sorted. Only IDs present in the graph. */
|
|
38
|
+
export function describingRecords(graph: Graph, slice: Artifact): string[] {
|
|
39
|
+
const out = new Set<string>([slice.meta.id]);
|
|
40
|
+
const targets = (id: string, kind: string) =>
|
|
41
|
+
(graph.out.get(id) ?? []).filter((edge) => edge.kind === kind).map((edge) => edge.to);
|
|
42
|
+
const sources = (id: string, kind: string) =>
|
|
43
|
+
(graph.in.get(id) ?? []).filter((edge) => edge.kind === kind).map((edge) => edge.from);
|
|
44
|
+
|
|
45
|
+
const behaviors = targets(slice.meta.id, "implements");
|
|
46
|
+
const rules = behaviors.flatMap((id) => targets(id, "governedBy"));
|
|
47
|
+
const scenarios = behaviors.flatMap((id) => sources(id, "illustrates"));
|
|
48
|
+
const claims = [...behaviors, ...rules, ...scenarios];
|
|
49
|
+
const verifications = claims.flatMap((id) => sources(id, "verifies"));
|
|
50
|
+
const contracts = targets(slice.meta.id, "exposes");
|
|
51
|
+
const decisions = [slice.meta.id, ...behaviors, ...contracts].flatMap((id) => targets(id, "informedBy"));
|
|
52
|
+
for (const id of [...claims, ...verifications, ...contracts, ...decisions]) out.add(id);
|
|
53
|
+
return [...out].filter((id) => graph.artifacts.has(id)).sort(compareStrings);
|
|
54
|
+
}
|