@intentius/chant 0.100.0 → 0.101.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.
Files changed (276) hide show
  1. package/dist/build.d.ts +6 -0
  2. package/dist/build.d.ts.map +1 -1
  3. package/dist/cli/build-options.d.ts +2 -0
  4. package/dist/cli/build-options.d.ts.map +1 -1
  5. package/dist/cli/commands/build.d.ts.map +1 -1
  6. package/dist/cli/commands/import.d.ts.map +1 -1
  7. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  8. package/dist/cli/main.d.ts.map +1 -1
  9. package/dist/cli/mcp/workspace-tools.d.ts +8 -0
  10. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  11. package/dist/cli/registry.d.ts +22 -0
  12. package/dist/cli/registry.d.ts.map +1 -1
  13. package/dist/config.d.ts +11 -0
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/lexicon.d.ts +24 -1
  16. package/dist/lexicon.d.ts.map +1 -1
  17. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  18. package/dist/lifecycle/plan-digest.d.ts +26 -5
  19. package/dist/lifecycle/plan-digest.d.ts.map +1 -1
  20. package/dist/lint/config.d.ts +4 -4
  21. package/dist/op/activities/activity-contracts.d.ts +1 -0
  22. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  23. package/dist/op/activities/propose-upgrade.d.ts +2 -0
  24. package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
  25. package/dist/op/index.d.ts +1 -1
  26. package/dist/op/index.d.ts.map +1 -1
  27. package/dist/serializer.d.ts +8 -0
  28. package/dist/serializer.d.ts.map +1 -1
  29. package/dist/telemetry-attribution.d.ts +77 -0
  30. package/dist/telemetry-attribution.d.ts.map +1 -0
  31. package/dist/workspace/agent-cli.d.ts +83 -0
  32. package/dist/workspace/agent-cli.d.ts.map +1 -0
  33. package/dist/workspace/changes-cli.d.ts.map +1 -1
  34. package/dist/workspace/changes.d.ts +8 -1
  35. package/dist/workspace/changes.d.ts.map +1 -1
  36. package/dist/workspace/checks/links.d.ts +1 -0
  37. package/dist/workspace/checks/links.d.ts.map +1 -1
  38. package/dist/workspace/checks/live.d.ts +40 -0
  39. package/dist/workspace/checks/live.d.ts.map +1 -0
  40. package/dist/workspace/checks.d.ts +21 -2
  41. package/dist/workspace/checks.d.ts.map +1 -1
  42. package/dist/workspace/compose-graph.d.ts +63 -0
  43. package/dist/workspace/compose-graph.d.ts.map +1 -1
  44. package/dist/workspace/decide.d.ts +1 -1
  45. package/dist/workspace/decide.d.ts.map +1 -1
  46. package/dist/workspace/declaration.d.ts +32 -0
  47. package/dist/workspace/declaration.d.ts.map +1 -1
  48. package/dist/workspace/declaration.schema.json +138 -3
  49. package/dist/workspace/export-cli.d.ts +12 -0
  50. package/dist/workspace/export-cli.d.ts.map +1 -0
  51. package/dist/workspace/export.d.ts +145 -0
  52. package/dist/workspace/export.d.ts.map +1 -0
  53. package/dist/workspace/graph-cli.d.ts.map +1 -1
  54. package/dist/workspace/import.d.ts +73 -0
  55. package/dist/workspace/import.d.ts.map +1 -0
  56. package/dist/workspace/kinds.d.ts +6 -2
  57. package/dist/workspace/kinds.d.ts.map +1 -1
  58. package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
  59. package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
  60. package/dist/workspace/lineage-adopt.d.ts +106 -0
  61. package/dist/workspace/lineage-adopt.d.ts.map +1 -0
  62. package/dist/workspace/lineage-check.d.ts +9 -2
  63. package/dist/workspace/lineage-check.d.ts.map +1 -1
  64. package/dist/workspace/lineage-cli.d.ts +6 -1
  65. package/dist/workspace/lineage-cli.d.ts.map +1 -1
  66. package/dist/workspace/lineage-hash-index.d.ts +110 -0
  67. package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
  68. package/dist/workspace/lineage-init.d.ts +10 -0
  69. package/dist/workspace/lineage-init.d.ts.map +1 -1
  70. package/dist/workspace/lineage-lock.d.ts +147 -0
  71. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  72. package/dist/workspace/lineage-migrations.d.ts +15 -3
  73. package/dist/workspace/lineage-migrations.d.ts.map +1 -1
  74. package/dist/workspace/lineage-provenance.d.ts +18 -0
  75. package/dist/workspace/lineage-provenance.d.ts.map +1 -0
  76. package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
  77. package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
  78. package/dist/workspace/lineage-upgrade.d.ts +30 -1
  79. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  80. package/dist/workspace/lineage-versions.d.ts +116 -0
  81. package/dist/workspace/lineage-versions.d.ts.map +1 -0
  82. package/dist/workspace/links.d.ts +31 -5
  83. package/dist/workspace/links.d.ts.map +1 -1
  84. package/dist/workspace/ls-generated.d.ts +37 -0
  85. package/dist/workspace/ls-generated.d.ts.map +1 -0
  86. package/dist/workspace/ls.d.ts +4 -0
  87. package/dist/workspace/ls.d.ts.map +1 -1
  88. package/dist/workspace/member-commands.d.ts.map +1 -1
  89. package/dist/workspace/nested-graph.d.ts +56 -0
  90. package/dist/workspace/nested-graph.d.ts.map +1 -0
  91. package/dist/workspace/nesting.d.ts +21 -0
  92. package/dist/workspace/nesting.d.ts.map +1 -0
  93. package/dist/workspace/pin-cli.d.ts +10 -0
  94. package/dist/workspace/pin-cli.d.ts.map +1 -0
  95. package/dist/workspace/pin-integrity.d.ts +51 -0
  96. package/dist/workspace/pin-integrity.d.ts.map +1 -0
  97. package/dist/workspace/reason-codes.d.ts +26 -2
  98. package/dist/workspace/reason-codes.d.ts.map +1 -1
  99. package/dist/workspace/record-sessions.d.ts +7 -11
  100. package/dist/workspace/record-sessions.d.ts.map +1 -1
  101. package/dist/workspace/records-cli.d.ts +30 -1
  102. package/dist/workspace/records-cli.d.ts.map +1 -1
  103. package/dist/workspace/records-close.d.ts +5 -2
  104. package/dist/workspace/records-close.d.ts.map +1 -1
  105. package/dist/workspace/records-write.d.ts +22 -4
  106. package/dist/workspace/records-write.d.ts.map +1 -1
  107. package/dist/workspace/records.d.ts +43 -5
  108. package/dist/workspace/records.d.ts.map +1 -1
  109. package/dist/workspace/returns.d.ts +129 -0
  110. package/dist/workspace/returns.d.ts.map +1 -0
  111. package/dist/workspace/status-gates.d.ts.map +1 -1
  112. package/dist/workspace/template-manifest.d.ts +11 -3
  113. package/dist/workspace/template-manifest.d.ts.map +1 -1
  114. package/dist/workspace/trust/attestor.d.ts +8 -0
  115. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  116. package/dist/workspace/trust/dsse.d.ts +58 -0
  117. package/dist/workspace/trust/dsse.d.ts.map +1 -0
  118. package/dist/workspace/trust/evidence-cli.d.ts +66 -0
  119. package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
  120. package/dist/workspace/trust/evidence.d.ts +93 -0
  121. package/dist/workspace/trust/evidence.d.ts.map +1 -0
  122. package/dist/workspace/trust/policy.d.ts +54 -1
  123. package/dist/workspace/trust/policy.d.ts.map +1 -1
  124. package/dist/workspace/trust/provenance.d.ts +21 -1
  125. package/dist/workspace/trust/provenance.d.ts.map +1 -1
  126. package/dist/workspace/trust/rotation.d.ts +132 -0
  127. package/dist/workspace/trust/rotation.d.ts.map +1 -0
  128. package/dist/workspace/trust/seal.d.ts.map +1 -1
  129. package/dist/workspace/trust/signers-cli.d.ts +49 -0
  130. package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
  131. package/dist/workspace/trust/ssh-commit.d.ts +12 -0
  132. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  133. package/dist/workspace/trust/test-repo.d.ts +13 -0
  134. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  135. package/dist/workspace/trust/verify.d.ts +15 -0
  136. package/dist/workspace/trust/verify.d.ts.map +1 -1
  137. package/dist/workspace/work-evidence.d.ts +1 -1
  138. package/dist/workspace/work-evidence.d.ts.map +1 -1
  139. package/dist/workspace/write-scope.d.ts +199 -0
  140. package/dist/workspace/write-scope.d.ts.map +1 -0
  141. package/package.json +1 -1
  142. package/src/build.ts +8 -0
  143. package/src/cli/build-options.ts +4 -1
  144. package/src/cli/commands/build.ts +2 -0
  145. package/src/cli/commands/import-live.test.ts +69 -1
  146. package/src/cli/commands/import.ts +48 -22
  147. package/src/cli/handlers/fan-out.test.ts +6 -6
  148. package/src/cli/handlers/fan-out.ts +2 -1
  149. package/src/cli/handlers/graph.test.ts +42 -0
  150. package/src/cli/handlers/graph.ts +22 -0
  151. package/src/cli/handlers/operator.ts +1 -1
  152. package/src/cli/main.test.ts +32 -0
  153. package/src/cli/main.ts +103 -6
  154. package/src/cli/mcp/workspace-tools.test.ts +1 -1
  155. package/src/cli/mcp/workspace-tools.ts +33 -2
  156. package/src/cli/registry.ts +22 -0
  157. package/src/cli/serve-mcp-workspace.test.ts +1 -1
  158. package/src/codegen/release-wiring.test.ts +5 -1
  159. package/src/components/fan-out-output.test.ts +1 -1
  160. package/src/components/fan-out.test.ts +1 -1
  161. package/src/components/promote.test.ts +1 -1
  162. package/src/config.ts +12 -0
  163. package/src/content-digest.test.ts +2 -2
  164. package/src/lexicon.ts +25 -1
  165. package/src/lifecycle/gate-ledger.test.ts +14 -0
  166. package/src/lifecycle/gate-ledger.ts +2 -1
  167. package/src/lifecycle/plan-digest.test.ts +54 -3
  168. package/src/lifecycle/plan-digest.ts +38 -8
  169. package/src/op/activities/activity-contracts.ts +1 -0
  170. package/src/op/activities/propose-upgrade.ts +8 -5
  171. package/src/op/gate-approval.test.ts +17 -0
  172. package/src/op/gate.ts +3 -3
  173. package/src/op/index.ts +1 -1
  174. package/src/serializer.ts +9 -0
  175. package/src/telemetry-attribution.test.ts +91 -0
  176. package/src/telemetry-attribution.ts +145 -0
  177. package/src/workspace/agent-cli.ts +134 -0
  178. package/src/workspace/agent.schema.json +356 -0
  179. package/src/workspace/behold-kinds.test.ts +1 -1
  180. package/src/workspace/changes-cli.ts +5 -0
  181. package/src/workspace/changes.schema.json +179 -1
  182. package/src/workspace/changes.ts +58 -4
  183. package/src/workspace/check-live.test.ts +192 -0
  184. package/src/workspace/check.schema.json +64 -0
  185. package/src/workspace/checks/links.ts +23 -2
  186. package/src/workspace/checks/live.ts +113 -0
  187. package/src/workspace/checks.test.ts +2 -2
  188. package/src/workspace/checks.ts +20 -3
  189. package/src/workspace/compose-graph.test.ts +47 -0
  190. package/src/workspace/compose-graph.ts +120 -3
  191. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
  192. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
  193. package/src/workspace/declaration.schema.json +138 -3
  194. package/src/workspace/declaration.ts +106 -1
  195. package/src/workspace/declared-kinds.test.ts +33 -0
  196. package/src/workspace/evidence.schema.json +279 -0
  197. package/src/workspace/export-cli.ts +180 -0
  198. package/src/workspace/export-import.test.ts +282 -0
  199. package/src/workspace/export.ts +486 -0
  200. package/src/workspace/graph-cli.ts +47 -1
  201. package/src/workspace/graph-contract.test.ts +89 -4
  202. package/src/workspace/graph.schema.json +206 -1
  203. package/src/workspace/import.ts +325 -0
  204. package/src/workspace/kinds.test.ts +5 -5
  205. package/src/workspace/kinds.ts +25 -3
  206. package/src/workspace/lineage-adopt-cli.ts +103 -0
  207. package/src/workspace/lineage-adopt.test.ts +552 -0
  208. package/src/workspace/lineage-adopt.ts +452 -0
  209. package/src/workspace/lineage-check.ts +26 -5
  210. package/src/workspace/lineage-cli.ts +12 -2
  211. package/src/workspace/lineage-hash-index.ts +305 -0
  212. package/src/workspace/lineage-init.test.ts +9 -0
  213. package/src/workspace/lineage-init.ts +29 -9
  214. package/src/workspace/lineage-lock.ts +54 -0
  215. package/src/workspace/lineage-migrations.test.ts +27 -0
  216. package/src/workspace/lineage-migrations.ts +44 -14
  217. package/src/workspace/lineage-provenance.ts +40 -0
  218. package/src/workspace/lineage-upgrade-cli.ts +9 -5
  219. package/src/workspace/lineage-upgrade.test.ts +92 -1
  220. package/src/workspace/lineage-upgrade.ts +111 -16
  221. package/src/workspace/lineage-versions.ts +348 -0
  222. package/src/workspace/links.test.ts +121 -2
  223. package/src/workspace/links.ts +97 -6
  224. package/src/workspace/ls-contract.test.ts +84 -1
  225. package/src/workspace/ls-generated.ts +111 -0
  226. package/src/workspace/ls.schema.json +19 -0
  227. package/src/workspace/ls.ts +8 -1
  228. package/src/workspace/member-commands.ts +3 -1
  229. package/src/workspace/nested-graph.test.ts +176 -0
  230. package/src/workspace/nested-graph.ts +169 -0
  231. package/src/workspace/nesting.ts +37 -0
  232. package/src/workspace/pin-cli.test.ts +71 -0
  233. package/src/workspace/pin-cli.ts +57 -0
  234. package/src/workspace/pin-integrity.test.ts +121 -0
  235. package/src/workspace/pin-integrity.ts +104 -0
  236. package/src/workspace/points-write.schema.json +1 -0
  237. package/src/workspace/read-contract.test.ts +24 -0
  238. package/src/workspace/reason-codes.test.ts +10 -0
  239. package/src/workspace/reason-codes.ts +29 -2
  240. package/src/workspace/record-sessions.ts +12 -14
  241. package/src/workspace/records-amend.schema.json +4 -0
  242. package/src/workspace/records-cli.ts +93 -12
  243. package/src/workspace/records-close.schema.json +6 -2
  244. package/src/workspace/records-close.ts +10 -2
  245. package/src/workspace/records-formats.test.ts +13 -5
  246. package/src/workspace/records-new.schema.json +4 -0
  247. package/src/workspace/records-review.schema.json +4 -0
  248. package/src/workspace/records-sessions.test.ts +23 -6
  249. package/src/workspace/records-write.test.ts +65 -8
  250. package/src/workspace/records-write.ts +70 -6
  251. package/src/workspace/records.schema.json +55 -3
  252. package/src/workspace/records.ts +96 -5
  253. package/src/workspace/returns.ts +328 -0
  254. package/src/workspace/signers.schema.json +206 -0
  255. package/src/workspace/status-gates.ts +2 -1
  256. package/src/workspace/template-manifest.ts +22 -4
  257. package/src/workspace/trust/attestor.ts +15 -0
  258. package/src/workspace/trust/dsse.ts +134 -0
  259. package/src/workspace/trust/evidence-cli.ts +195 -0
  260. package/src/workspace/trust/evidence.test.ts +241 -0
  261. package/src/workspace/trust/evidence.ts +207 -0
  262. package/src/workspace/trust/policy.ts +110 -3
  263. package/src/workspace/trust/provenance.ts +41 -4
  264. package/src/workspace/trust/record-seal.test.ts +1 -1
  265. package/src/workspace/trust/rotation.test.ts +258 -0
  266. package/src/workspace/trust/rotation.ts +336 -0
  267. package/src/workspace/trust/seal.ts +11 -0
  268. package/src/workspace/trust/signers-cli.ts +178 -0
  269. package/src/workspace/trust/ssh-commit.ts +53 -4
  270. package/src/workspace/trust/test-repo.ts +18 -0
  271. package/src/workspace/trust/trust.test.ts +8 -2
  272. package/src/workspace/trust/verify-cli.ts +1 -0
  273. package/src/workspace/trust/verify.ts +22 -0
  274. package/src/workspace/work-evidence.schema.json +4 -0
  275. package/src/workspace/write-scope.test.ts +340 -0
  276. package/src/workspace/write-scope.ts +448 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * `chant workspace agent [<name>] [--json]` (#2524 D20, #2548, ws-067): what
3
+ * an agent session reloads from, read from the repository alone.
4
+ *
5
+ * A session is declared in the declaration's `agents` list and bound to one
6
+ * member. This prints the session, its member, its write scope (the files
7
+ * and the record kinds, with their verbs, it may write) and the spec: the
8
+ * `spec` block `chant workspace records --current --json` prints (#2546). An
9
+ * agent that resumes needs nothing else: no memory of an earlier run, no
10
+ * state outside the checkout.
11
+ *
12
+ * The session and its scope come from the declaration at base, as the
13
+ * write paths and `check --changes` read them; the spec from the working
14
+ * tree, which is what the agent works on. Without a name, the session
15
+ * `CHANT_AGENT` names.
16
+ */
17
+
18
+ import { formatError } from "../cli/format";
19
+ import type { CommandContext } from "../cli/registry";
20
+ import { readerVersion, WORKSPACE_ERROR_CODES, WorkspaceReadError, WRITE_VERBS, type WriteVerb } from "./declaration";
21
+ import type { ReasonCode } from "./reason-codes";
22
+ import { declaredKindFiles, queryDeclaredRecords, type SpecView } from "./records-cli";
23
+ import { AGENT_ENV, resolveWriter, scopeOf, scopeSource, WriteScopeError } from "./write-scope";
24
+
25
+ /** The version of the `agent` document this chant writes. */
26
+ export const AGENT_CONTRACT_VERSION = 1;
27
+
28
+ export const AGENT_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/agent/v1/agent.schema.json";
29
+
30
+ /** Why the session can't be printed. Closed. */
31
+ export const AGENT_ERROR_CODES = [...WORKSPACE_ERROR_CODES, "agent-unknown"] as const satisfies readonly ReasonCode[];
32
+ export type AgentErrorCode = (typeof AGENT_ERROR_CODES)[number];
33
+
34
+ /** A record kind in the session's reach, with the verbs it may write it with. */
35
+ export interface AgentKindScope {
36
+ /** The kind file from the workspace root, as the declaration names it. */
37
+ path: string;
38
+ /** The kind file's recordKind.name, or null when it can't be loaded. */
39
+ kind: string | null;
40
+ /** The name the declaration gives it, or null. */
41
+ name: string | null;
42
+ /** The member that declares it, or null for the workspace's own. */
43
+ member: string | null;
44
+ /** Empty when writeScope.agent.records leaves the kind out. */
45
+ verbs: WriteVerb[];
46
+ }
47
+
48
+ interface Head {
49
+ $schema: string;
50
+ contract: number;
51
+ chant: string;
52
+ }
53
+
54
+ export type AgentDocument =
55
+ | (Head & {
56
+ workspace: { name: string; root: string; scopeFrom: "base" | "working-tree" };
57
+ agent: { name: string; member: { name: string; dir: string; kind: string }; principals: string[] };
58
+ scope: {
59
+ /** The one member whose files the session writes. */
60
+ members: string[];
61
+ /** Every declared kind in reach: the workspace's own and the member's. */
62
+ records: AgentKindScope[];
63
+ };
64
+ /** The spec, as records --current --json prints it. */
65
+ spec: SpecView;
66
+ /** The reads that rebuild the session's context. */
67
+ reload: string[];
68
+ })
69
+ | (Head & { error: { code: AgentErrorCode; message: string } });
70
+
71
+ /** The session `name` names, as {@link AgentDocument} prints it. Never throws a read or scope error. */
72
+ export async function agentSession(q: { cwd: string; name: string }): Promise<AgentDocument> {
73
+ const head: Head = { $schema: AGENT_OUTPUT_SCHEMA_ID, contract: AGENT_CONTRACT_VERSION, chant: readerVersion() };
74
+ try {
75
+ const source = scopeSource(q.cwd);
76
+ if (source.declaration === null || source.from === null) {
77
+ throw new WorkspaceReadError("declaration-missing", "no chant.workspace.json or .jsonc between this directory and the git root, so no agent session is declared");
78
+ }
79
+ const decl = source.declaration;
80
+ const writer = resolveWriter(decl, source.policy, { agent: q.name });
81
+ const agent = writer.agent!;
82
+ const member = decl.members.find((m) => m.name === agent.member)!;
83
+ const rules = scopeOf(decl, writer)!.records;
84
+ // The spec query, over every declared kind in the working tree.
85
+ const set = await queryDeclaredRecords(declaredKindFiles(q.cwd), { cwd: q.cwd, current: true });
86
+ const loadedName = new Map(set.kinds.map((k) => [k.declared.path, "error" in k ? null : k.kind.name]));
87
+ const records: AgentKindScope[] = [...decl.records, ...member.records].map((d) => {
88
+ const kind = loadedName.get(d.path) ?? null;
89
+ const names = [kind, d.name].filter((n): n is string => n !== null);
90
+ const verbs = rules === null ? [...WRITE_VERBS] : WRITE_VERBS.filter((v) => names.some((n) => (rules[n] ?? []).includes(v)));
91
+ return { path: d.path, kind, name: d.name, member: d.member, verbs };
92
+ });
93
+ return {
94
+ ...head,
95
+ workspace: { name: decl.name, root: source.root ?? ".", scopeFrom: source.from },
96
+ agent: { name: agent.name, member: { name: member.name, dir: member.dir, kind: member.kind }, principals: agent.principals },
97
+ scope: { members: [member.name], records },
98
+ spec: set.spec ?? { kinds: [], records: [] },
99
+ reload: [`chant workspace agent ${agent.name} --json`, "chant workspace records --current --json"],
100
+ };
101
+ } catch (err) {
102
+ if (err instanceof WorkspaceReadError || err instanceof WriteScopeError) {
103
+ return { ...head, error: { code: err.code as AgentErrorCode, message: err instanceof WorkspaceReadError ? err.describe() : err.message } };
104
+ }
105
+ throw err;
106
+ }
107
+ }
108
+
109
+ const USAGE = "chant workspace agent [<name>] [--json]";
110
+
111
+ /** `chant workspace agent`: exit 0 when the session was printed, 1 otherwise. */
112
+ export async function runWorkspaceAgent(ctx: CommandContext): Promise<number> {
113
+ const { args } = ctx;
114
+ const name = args.extraPositional ?? (process.env[AGENT_ENV] || undefined);
115
+ if (!name) {
116
+ console.error(formatError({ message: `name the agent session, or set ${AGENT_ENV}`, hint: USAGE }));
117
+ return 1;
118
+ }
119
+ const doc = await agentSession({ cwd: process.cwd(), name });
120
+ if (args.json || args.format === "json") console.log(JSON.stringify(doc, null, 2));
121
+ if ("error" in doc) {
122
+ if (!args.json && args.format !== "json") console.error(formatError({ message: `${doc.error.code}: ${doc.error.message}`, hint: USAGE }));
123
+ return 1;
124
+ }
125
+ if (args.json || args.format === "json") return 0;
126
+ const out: string[] = [];
127
+ out.push(`agent ${doc.agent.name}, bound to member ${doc.agent.member.name} (${doc.agent.member.dir}), scope read from ${doc.workspace.scopeFrom}`);
128
+ for (const r of doc.scope.records) out.push(`records ${r.name ?? r.kind ?? r.path} (${r.path}): ${r.verbs.length > 0 ? r.verbs.join(", ") : "not writable"}`);
129
+ out.push(`spec ${doc.spec.records.length} current records of ${doc.spec.kinds.length} spec kinds`);
130
+ for (const r of doc.spec.records) out.push(` ${r.kind}/${r.id ?? "?"} ${r.state ?? ""} ${r.path}`);
131
+ out.push(`reload ${doc.reload.join("; ")}`);
132
+ console.log(out.join("\n"));
133
+ return 0;
134
+ }
@@ -0,0 +1,356 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://intentius.io/chant/schemas/workspace/agent/v1/agent.schema.json",
4
+ "title": "chant workspace agent output",
5
+ "description": "What `chant workspace agent <name> --json` prints (#2524 D20, #2548, ws-067): an agent session, the one member it is bound to, its write scope and the spec, read from the repository alone, so a session that resumes rebuilds its context from this and nothing else. The session and its scope are read from the declaration at base, as the write paths and check --changes read them; the spec from the working tree. Readers ignore fields they do not know; a field is only ever added within a version. The error codes are a closed list, and every one is in the one closed list of `reason-codes.ts`. Contract version 1; this document was added to it by #2548.",
6
+ "oneOf": [
7
+ {
8
+ "$ref": "#/$defs/result"
9
+ },
10
+ {
11
+ "$ref": "#/$defs/failure"
12
+ }
13
+ ],
14
+ "$defs": {
15
+ "result": {
16
+ "description": "The session was found. Exit code 0.",
17
+ "type": "object",
18
+ "required": [
19
+ "$schema",
20
+ "contract",
21
+ "chant",
22
+ "workspace",
23
+ "agent",
24
+ "scope",
25
+ "spec",
26
+ "reload"
27
+ ],
28
+ "properties": {
29
+ "$schema": {
30
+ "const": "https://intentius.io/chant/schemas/workspace/agent/v1/agent.schema.json"
31
+ },
32
+ "contract": {
33
+ "const": 1
34
+ },
35
+ "chant": {
36
+ "type": "string",
37
+ "description": "The chant that wrote the document."
38
+ },
39
+ "workspace": {
40
+ "type": "object",
41
+ "required": [
42
+ "name",
43
+ "root",
44
+ "scopeFrom"
45
+ ],
46
+ "properties": {
47
+ "name": {
48
+ "type": "string"
49
+ },
50
+ "root": {
51
+ "type": "string",
52
+ "description": "The workspace root relative to the git root, \".\" for the git root."
53
+ },
54
+ "scopeFrom": {
55
+ "enum": [
56
+ "base",
57
+ "working-tree"
58
+ ],
59
+ "description": "Where the declaration was read: the base revision (origin/HEAD, main or master), or the working tree when there is no base or no declaration at it."
60
+ }
61
+ }
62
+ },
63
+ "agent": {
64
+ "type": "object",
65
+ "required": [
66
+ "name",
67
+ "member",
68
+ "principals"
69
+ ],
70
+ "properties": {
71
+ "name": {
72
+ "type": "string"
73
+ },
74
+ "member": {
75
+ "type": "object",
76
+ "required": [
77
+ "name",
78
+ "dir",
79
+ "kind"
80
+ ],
81
+ "properties": {
82
+ "name": {
83
+ "type": "string"
84
+ },
85
+ "dir": {
86
+ "type": "string"
87
+ },
88
+ "kind": {
89
+ "type": "string"
90
+ }
91
+ }
92
+ },
93
+ "principals": {
94
+ "type": "array",
95
+ "items": {
96
+ "type": "string"
97
+ },
98
+ "description": "Principals that write only as this session."
99
+ }
100
+ }
101
+ },
102
+ "scope": {
103
+ "type": "object",
104
+ "required": [
105
+ "members",
106
+ "records"
107
+ ],
108
+ "properties": {
109
+ "members": {
110
+ "type": "array",
111
+ "items": {
112
+ "type": "string"
113
+ },
114
+ "description": "The one member whose files the session writes."
115
+ },
116
+ "records": {
117
+ "type": "array",
118
+ "description": "Every declared record kind in the session's reach: the workspace's own kinds, then the member's.",
119
+ "items": {
120
+ "type": "object",
121
+ "required": [
122
+ "path",
123
+ "kind",
124
+ "name",
125
+ "member",
126
+ "verbs"
127
+ ],
128
+ "properties": {
129
+ "path": {
130
+ "type": "string",
131
+ "description": "The kind file from the workspace root."
132
+ },
133
+ "kind": {
134
+ "type": [
135
+ "string",
136
+ "null"
137
+ ],
138
+ "description": "The kind file's recordKind.name, or null when it can't be loaded."
139
+ },
140
+ "name": {
141
+ "type": [
142
+ "string",
143
+ "null"
144
+ ],
145
+ "description": "The name the declaration gives the kind, or null."
146
+ },
147
+ "member": {
148
+ "type": [
149
+ "string",
150
+ "null"
151
+ ],
152
+ "description": "The member that declares the kind, or null for the workspace's own."
153
+ },
154
+ "verbs": {
155
+ "type": "array",
156
+ "items": {
157
+ "enum": [
158
+ "new",
159
+ "amend",
160
+ "review",
161
+ "close"
162
+ ]
163
+ },
164
+ "description": "How the session may write the kind's records; empty when writeScope.agent.records leaves the kind out."
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ },
171
+ "spec": {
172
+ "description": "The spec exactly as chant workspace records --current --json prints it under spec (#2546): the current records of each declared kind marked spec: true, read in the working tree, each with the workspace files it pins.",
173
+ "type": "object",
174
+ "required": [
175
+ "kinds",
176
+ "records"
177
+ ],
178
+ "properties": {
179
+ "kinds": {
180
+ "type": "array",
181
+ "description": "The spec kinds, as the declaration names them, in its order.",
182
+ "items": {
183
+ "type": "object",
184
+ "required": [
185
+ "member",
186
+ "path",
187
+ "name"
188
+ ],
189
+ "properties": {
190
+ "member": {
191
+ "type": [
192
+ "string",
193
+ "null"
194
+ ]
195
+ },
196
+ "path": {
197
+ "type": "string"
198
+ },
199
+ "name": {
200
+ "type": [
201
+ "string",
202
+ "null"
203
+ ]
204
+ }
205
+ }
206
+ }
207
+ },
208
+ "records": {
209
+ "type": "array",
210
+ "description": "Every current record of the spec kinds, in the order of kinds and then path. Invalid records are listed with valid false, as under kinds.",
211
+ "items": {
212
+ "type": "object",
213
+ "required": [
214
+ "kind",
215
+ "id",
216
+ "path",
217
+ "state",
218
+ "valid",
219
+ "digest",
220
+ "assets"
221
+ ],
222
+ "properties": {
223
+ "kind": {
224
+ "type": "string",
225
+ "description": "The kind's name, such as decision."
226
+ },
227
+ "id": {
228
+ "type": [
229
+ "string",
230
+ "null"
231
+ ]
232
+ },
233
+ "path": {
234
+ "type": "string"
235
+ },
236
+ "state": {
237
+ "type": [
238
+ "string",
239
+ "null"
240
+ ]
241
+ },
242
+ "valid": {
243
+ "type": "boolean"
244
+ },
245
+ "digest": {
246
+ "type": "string",
247
+ "pattern": "^[0-9a-f]{64}$"
248
+ },
249
+ "assets": {
250
+ "type": "array",
251
+ "items": {
252
+ "$ref": "#/$defs/asset"
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ },
260
+ "reload": {
261
+ "type": "array",
262
+ "items": {
263
+ "type": "string"
264
+ },
265
+ "description": "The reads that rebuild the session's context."
266
+ }
267
+ }
268
+ },
269
+ "failure": {
270
+ "description": "The declaration could not be read, or names no such session. Exit code 1.",
271
+ "type": "object",
272
+ "required": [
273
+ "$schema",
274
+ "contract",
275
+ "chant",
276
+ "error"
277
+ ],
278
+ "properties": {
279
+ "$schema": {
280
+ "const": "https://intentius.io/chant/schemas/workspace/agent/v1/agent.schema.json"
281
+ },
282
+ "contract": {
283
+ "const": 1
284
+ },
285
+ "chant": {
286
+ "type": "string"
287
+ },
288
+ "error": {
289
+ "type": "object",
290
+ "required": [
291
+ "code",
292
+ "message"
293
+ ],
294
+ "properties": {
295
+ "code": {
296
+ "enum": [
297
+ "declaration-missing",
298
+ "declaration-ambiguous",
299
+ "declaration-unparseable",
300
+ "declaration-invalid",
301
+ "placement-invalid",
302
+ "reader-too-old",
303
+ "root-chant-required",
304
+ "not-a-git-repository",
305
+ "revision-unknown",
306
+ "agent-unknown"
307
+ ]
308
+ },
309
+ "message": {
310
+ "type": "string"
311
+ }
312
+ }
313
+ },
314
+ "agent": false,
315
+ "scope": false
316
+ }
317
+ },
318
+ "asset": {
319
+ "type": "object",
320
+ "required": [
321
+ "path",
322
+ "sha256",
323
+ "actual",
324
+ "state"
325
+ ],
326
+ "properties": {
327
+ "path": {
328
+ "type": "string",
329
+ "description": "From the workspace root (workspaceRoot), with / separators."
330
+ },
331
+ "sha256": {
332
+ "type": "string",
333
+ "pattern": "^[0-9a-f]{64}$",
334
+ "description": "The hash the record pins."
335
+ },
336
+ "actual": {
337
+ "type": [
338
+ "string",
339
+ "null"
340
+ ],
341
+ "pattern": "^[0-9a-f]{64}$",
342
+ "description": "The hash of the file's bytes in the tree read, or null when the file is missing."
343
+ },
344
+ "state": {
345
+ "enum": [
346
+ "pinned",
347
+ "drifted",
348
+ "missing",
349
+ "stale"
350
+ ],
351
+ "description": "pinned when the hashes match; drifted when they differ (a warning asset-drift); missing when the file is not there (a warning asset-missing); stale when the hashes match and a record this one supersedes pinned the same hash, with the file unchanged since this record was recorded (a warning asset-stale)."
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }
@@ -153,6 +153,6 @@ describe("behold's member kinds from their packages (#2545)", () => {
153
153
  await runWorkspaceLs({ args: parseArgs(["workspace", "ls", root, "--json"]), plugins: [] } as never);
154
154
  const doc = JSON.parse(out.join("\n")) as Extract<LsDocument, { members: unknown }>;
155
155
  expect(doc.members.map((m) => m.reason?.code ?? null)).toEqual(["unknown-kind", "unknown-kind", "unknown-kind", null]);
156
- expect(doc.members[0].reason?.message).toMatch(/known kinds: chant, other, workspace$/);
156
+ expect(doc.members[0].reason?.message).toMatch(/known kinds: chant, design, other, workspace$/);
157
157
  });
158
158
  });
@@ -32,6 +32,11 @@ export function formatChanges(doc: Result): string {
32
32
  out.push(`${p.status.padEnd(12)} ${p.change.padEnd(8)} ${p.path}${p.from ? ` (from ${p.from})` : ""}${why ? `; ${why}` : ""}`);
33
33
  }
34
34
  for (const f of doc.findings) out.push(`${f.severity === "fail" ? "error " : "warning"} ${f.code}: ${f.message}`);
35
+ if (doc.scope) {
36
+ const sc = doc.scope;
37
+ out.push(`scope ${sc.commits.length} commits judged against the declaration at ${sc.base.slice(0, 8)}; restricted: ${sc.restricted.join(", ") || "none"}`);
38
+ for (const f of sc.findings) out.push(`error ${f.code}: ${f.message}`);
39
+ }
35
40
  const s = doc.summary;
36
41
  out.push(`${s.paths} changed paths: ${s.covered} covered, ${s.uncovered} uncovered, ${s.outOfScope} out of scope, ${s.ignored} ignored, ${s.records} records; ${doc.findings.length} findings`);
37
42
  return out.join("\n");