@lannguyensi/harness 0.5.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 (199) hide show
  1. package/CHANGELOG.md +552 -0
  2. package/LICENSE +21 -0
  3. package/README.md +154 -0
  4. package/dist/cli/add/index.d.ts +14 -0
  5. package/dist/cli/add/index.js +71 -0
  6. package/dist/cli/add/index.js.map +1 -0
  7. package/dist/cli/add/mutate.d.ts +39 -0
  8. package/dist/cli/add/mutate.js +36 -0
  9. package/dist/cli/add/mutate.js.map +1 -0
  10. package/dist/cli/adopt/derive.d.ts +38 -0
  11. package/dist/cli/adopt/derive.js +94 -0
  12. package/dist/cli/adopt/derive.js.map +1 -0
  13. package/dist/cli/adopt/index.d.ts +20 -0
  14. package/dist/cli/adopt/index.js +156 -0
  15. package/dist/cli/adopt/index.js.map +1 -0
  16. package/dist/cli/apply/apply.d.ts +49 -0
  17. package/dist/cli/apply/apply.js +333 -0
  18. package/dist/cli/apply/apply.js.map +1 -0
  19. package/dist/cli/apply/generate-memory-index.d.ts +17 -0
  20. package/dist/cli/apply/generate-memory-index.js +167 -0
  21. package/dist/cli/apply/generate-memory-index.js.map +1 -0
  22. package/dist/cli/apply/generate-settings.d.ts +15 -0
  23. package/dist/cli/apply/generate-settings.js +87 -0
  24. package/dist/cli/apply/generate-settings.js.map +1 -0
  25. package/dist/cli/apply/index.d.ts +1 -0
  26. package/dist/cli/apply/index.js +2 -0
  27. package/dist/cli/apply/index.js.map +1 -0
  28. package/dist/cli/audit.d.ts +36 -0
  29. package/dist/cli/audit.js +121 -0
  30. package/dist/cli/audit.js.map +1 -0
  31. package/dist/cli/describe.d.ts +13 -0
  32. package/dist/cli/describe.js +26 -0
  33. package/dist/cli/describe.js.map +1 -0
  34. package/dist/cli/diff/engine.d.ts +21 -0
  35. package/dist/cli/diff/engine.js +161 -0
  36. package/dist/cli/diff/engine.js.map +1 -0
  37. package/dist/cli/diff/git.d.ts +6 -0
  38. package/dist/cli/diff/git.js +32 -0
  39. package/dist/cli/diff/git.js.map +1 -0
  40. package/dist/cli/diff/index.d.ts +15 -0
  41. package/dist/cli/diff/index.js +39 -0
  42. package/dist/cli/diff/index.js.map +1 -0
  43. package/dist/cli/diff/since-apply.d.ts +57 -0
  44. package/dist/cli/diff/since-apply.js +255 -0
  45. package/dist/cli/diff/since-apply.js.map +1 -0
  46. package/dist/cli/doctor/format.d.ts +2 -0
  47. package/dist/cli/doctor/format.js +126 -0
  48. package/dist/cli/doctor/format.js.map +1 -0
  49. package/dist/cli/doctor/index.d.ts +14 -0
  50. package/dist/cli/doctor/index.js +281 -0
  51. package/dist/cli/doctor/index.js.map +1 -0
  52. package/dist/cli/doctor/types.d.ts +46 -0
  53. package/dist/cli/doctor/types.js +2 -0
  54. package/dist/cli/doctor/types.js.map +1 -0
  55. package/dist/cli/dry-run.d.ts +46 -0
  56. package/dist/cli/dry-run.js +168 -0
  57. package/dist/cli/dry-run.js.map +1 -0
  58. package/dist/cli/exit-codes.d.ts +10 -0
  59. package/dist/cli/exit-codes.js +15 -0
  60. package/dist/cli/exit-codes.js.map +1 -0
  61. package/dist/cli/explain.d.ts +14 -0
  62. package/dist/cli/explain.js +97 -0
  63. package/dist/cli/explain.js.map +1 -0
  64. package/dist/cli/export.d.ts +31 -0
  65. package/dist/cli/export.js +84 -0
  66. package/dist/cli/export.js.map +1 -0
  67. package/dist/cli/index.d.ts +8 -0
  68. package/dist/cli/index.js +549 -0
  69. package/dist/cli/index.js.map +1 -0
  70. package/dist/cli/init/index.d.ts +17 -0
  71. package/dist/cli/init/index.js +57 -0
  72. package/dist/cli/init/index.js.map +1 -0
  73. package/dist/cli/init/templates.d.ts +4 -0
  74. package/dist/cli/init/templates.js +175 -0
  75. package/dist/cli/init/templates.js.map +1 -0
  76. package/dist/cli/list.d.ts +12 -0
  77. package/dist/cli/list.js +118 -0
  78. package/dist/cli/list.js.map +1 -0
  79. package/dist/cli/loader.d.ts +24 -0
  80. package/dist/cli/loader.js +74 -0
  81. package/dist/cli/loader.js.map +1 -0
  82. package/dist/cli/main.d.ts +2 -0
  83. package/dist/cli/main.js +6 -0
  84. package/dist/cli/main.js.map +1 -0
  85. package/dist/cli/policy/intercept.d.ts +34 -0
  86. package/dist/cli/policy/intercept.js +172 -0
  87. package/dist/cli/policy/intercept.js.map +1 -0
  88. package/dist/cli/remove/index.d.ts +18 -0
  89. package/dist/cli/remove/index.js +95 -0
  90. package/dist/cli/remove/index.js.map +1 -0
  91. package/dist/cli/remove/mutate.d.ts +9 -0
  92. package/dist/cli/remove/mutate.js +68 -0
  93. package/dist/cli/remove/mutate.js.map +1 -0
  94. package/dist/cli/validate/checks.d.ts +23 -0
  95. package/dist/cli/validate/checks.js +253 -0
  96. package/dist/cli/validate/checks.js.map +1 -0
  97. package/dist/cli/validate/index.d.ts +18 -0
  98. package/dist/cli/validate/index.js +50 -0
  99. package/dist/cli/validate/index.js.map +1 -0
  100. package/dist/cli/validate/types.d.ts +7 -0
  101. package/dist/cli/validate/types.js +5 -0
  102. package/dist/cli/validate/types.js.map +1 -0
  103. package/dist/index.d.ts +15 -0
  104. package/dist/index.js +16 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/io/atomic-write.d.ts +8 -0
  107. package/dist/io/atomic-write.js +30 -0
  108. package/dist/io/atomic-write.js.map +1 -0
  109. package/dist/io/harness-lock.d.ts +33 -0
  110. package/dist/io/harness-lock.js +260 -0
  111. package/dist/io/harness-lock.js.map +1 -0
  112. package/dist/io/last-apply.d.ts +20 -0
  113. package/dist/io/last-apply.js +123 -0
  114. package/dist/io/last-apply.js.map +1 -0
  115. package/dist/io/lock.d.ts +11 -0
  116. package/dist/io/lock.js +33 -0
  117. package/dist/io/lock.js.map +1 -0
  118. package/dist/io/patch.d.ts +10 -0
  119. package/dist/io/patch.js +8 -0
  120. package/dist/io/patch.js.map +1 -0
  121. package/dist/io/restart-hints.d.ts +5 -0
  122. package/dist/io/restart-hints.js +59 -0
  123. package/dist/io/restart-hints.js.map +1 -0
  124. package/dist/io/three-state.d.ts +7 -0
  125. package/dist/io/three-state.js +20 -0
  126. package/dist/io/three-state.js.map +1 -0
  127. package/dist/io/validate-before-write.d.ts +12 -0
  128. package/dist/io/validate-before-write.js +23 -0
  129. package/dist/io/validate-before-write.js.map +1 -0
  130. package/dist/overrides/index.d.ts +2 -0
  131. package/dist/overrides/index.js +3 -0
  132. package/dist/overrides/index.js.map +1 -0
  133. package/dist/overrides/machines.d.ts +12 -0
  134. package/dist/overrides/machines.js +46 -0
  135. package/dist/overrides/machines.js.map +1 -0
  136. package/dist/overrides/merge.d.ts +6 -0
  137. package/dist/overrides/merge.js +173 -0
  138. package/dist/overrides/merge.js.map +1 -0
  139. package/dist/policies/duration.d.ts +5 -0
  140. package/dist/policies/duration.js +50 -0
  141. package/dist/policies/duration.js.map +1 -0
  142. package/dist/policies/extract.d.ts +50 -0
  143. package/dist/policies/extract.js +190 -0
  144. package/dist/policies/extract.js.map +1 -0
  145. package/dist/policies/index.d.ts +5 -0
  146. package/dist/policies/index.js +6 -0
  147. package/dist/policies/index.js.map +1 -0
  148. package/dist/policies/ledger-client.d.ts +39 -0
  149. package/dist/policies/ledger-client.js +378 -0
  150. package/dist/policies/ledger-client.js.map +1 -0
  151. package/dist/policies/requires.d.ts +44 -0
  152. package/dist/policies/requires.js +146 -0
  153. package/dist/policies/requires.js.map +1 -0
  154. package/dist/policies/timestamp.d.ts +14 -0
  155. package/dist/policies/timestamp.js +36 -0
  156. package/dist/policies/timestamp.js.map +1 -0
  157. package/dist/probes/mcp.d.ts +29 -0
  158. package/dist/probes/mcp.js +226 -0
  159. package/dist/probes/mcp.js.map +1 -0
  160. package/dist/probes/memory.d.ts +24 -0
  161. package/dist/probes/memory.js +89 -0
  162. package/dist/probes/memory.js.map +1 -0
  163. package/dist/runtime/index.d.ts +3 -0
  164. package/dist/runtime/index.js +4 -0
  165. package/dist/runtime/index.js.map +1 -0
  166. package/dist/runtime/intercept.d.ts +53 -0
  167. package/dist/runtime/intercept.js +181 -0
  168. package/dist/runtime/intercept.js.map +1 -0
  169. package/dist/runtime/ledger-record.d.ts +43 -0
  170. package/dist/runtime/ledger-record.js +239 -0
  171. package/dist/runtime/ledger-record.js.map +1 -0
  172. package/dist/runtime/session-id.d.ts +10 -0
  173. package/dist/runtime/session-id.js +37 -0
  174. package/dist/runtime/session-id.js.map +1 -0
  175. package/dist/schema/extract.d.ts +5 -0
  176. package/dist/schema/extract.js +23 -0
  177. package/dist/schema/extract.js.map +1 -0
  178. package/dist/schema/grounding.d.ts +65 -0
  179. package/dist/schema/grounding.js +21 -0
  180. package/dist/schema/grounding.js.map +1 -0
  181. package/dist/schema/hooks.d.ts +86 -0
  182. package/dist/schema/hooks.js +42 -0
  183. package/dist/schema/hooks.js.map +1 -0
  184. package/dist/schema/index.d.ts +961 -0
  185. package/dist/schema/index.js +55 -0
  186. package/dist/schema/index.js.map +1 -0
  187. package/dist/schema/memory.d.ts +131 -0
  188. package/dist/schema/memory.js +38 -0
  189. package/dist/schema/memory.js.map +1 -0
  190. package/dist/schema/policies.d.ts +412 -0
  191. package/dist/schema/policies.js +53 -0
  192. package/dist/schema/policies.js.map +1 -0
  193. package/dist/schema/requires.d.ts +115 -0
  194. package/dist/schema/requires.js +57 -0
  195. package/dist/schema/requires.js.map +1 -0
  196. package/dist/schema/tools.d.ts +283 -0
  197. package/dist/schema/tools.js +66 -0
  198. package/dist/schema/tools.js.map +1 -0
  199. package/package.json +63 -0
@@ -0,0 +1,87 @@
1
+ // Inverse of `src/cli/adopt/derive.ts#parseSettingsHooks`: turn the manifest's
2
+ // `hooks[]` into the nested Claude Code settings.json shape that `harness apply`
3
+ // writes to `harness.generated/settings.json`. Pure function, no I/O.
4
+ //
5
+ // Output shape (matches Claude Code's settings.json `hooks` section):
6
+ //
7
+ // { hooks: { <EventName>: [ { matcher?, hooks: [{ type, command, timeout? }] } ] } }
8
+ //
9
+ // Field decisions for v1 (per ARCHITECTURE §5 + Phase 3 #2 task scope):
10
+ // - `type: "command"` is always emitted explicitly. Claude Code accepts
11
+ // missing `type` (it defaults to "command") but explicit is friendlier
12
+ // to humans diffing the file.
13
+ // - `matcher` is omitted when the manifest hook has no `match`. Hooks with
14
+ // a match string emit a `matcher` field with that exact string. Regex
15
+ // metacharacters are passed through unchanged.
16
+ // - `timeout` is always emitted (the manifest's `budget_ms` is always set
17
+ // after schema-defaulting). Always-emit is the conservative choice
18
+ // against an unknown runtime default; an explicit value is consumed
19
+ // identically whether or not the runtime would have defaulted to it.
20
+ // - `path_match` and `bash_match` are NOT projected. Claude Code's
21
+ // settings.json `matcher` filters only on the tool name, so there is
22
+ // no native settings.json field for "additional filter when this hook
23
+ // fires". Per the canonical example in ARCHITECTURE.md Appendix A
24
+ // (e.g. `require-preflight-evidence` with `bash_match: "^git ..."`),
25
+ // these filters are enforced inside the referenced hook script, not by
26
+ // harness's wiring. The manifest fields are documentation: they tell
27
+ // `harness validate`/`doctor` what the script claims to filter on, so
28
+ // the script's behaviour can be cross-checked, but `harness apply`
29
+ // does not synthesise wrapper shell to enforce them. Wrapping was
30
+ // considered and rejected: it (a) doubles the surface for hook bugs,
31
+ // (b) hard-codes shell semantics into the manifest projection, and
32
+ // (c) the canonical hook scripts already enforce these filters.
33
+ // - `blocking` is harness-internal: it tells `validate`/`doctor` how to
34
+ // classify a hook for soft/hard-failure reporting. Claude Code's
35
+ // settings.json has no documented equivalent (verified against the
36
+ // ecosystem as of 2026-04 — revisit if a runtime field appears), so
37
+ // it does NOT survive the projection.
38
+ //
39
+ // Stable-output rules (load-bearing for byte-equivalent regeneration on a
40
+ // no-op apply):
41
+ // - Event keys sorted ascending by name (insertion order in the JSON
42
+ // object reflects this; JSON.stringify preserves it).
43
+ // - Within an event, groups sorted by (matcher, command).
44
+ // - Within a group, the inner hooks[] preserves matcher-grouping order
45
+ // and is sorted by command for the same reason.
46
+ export const DEFAULT_BUDGET_MS = 30_000;
47
+ export function generateSettings(manifest) {
48
+ const byEvent = new Map();
49
+ for (const h of manifest.hooks) {
50
+ const list = byEvent.get(h.event) ?? [];
51
+ list.push(h);
52
+ byEvent.set(h.event, list);
53
+ }
54
+ const out = { hooks: {} };
55
+ const eventNames = [...byEvent.keys()].sort();
56
+ for (const event of eventNames) {
57
+ const hooks = byEvent.get(event) ?? [];
58
+ out.hooks[event] = buildGroups(hooks);
59
+ }
60
+ return out;
61
+ }
62
+ function buildGroups(hooks) {
63
+ // Group by exact `match` value. Unmatched hooks share the empty-string
64
+ // bucket and emit a group without a `matcher` field.
65
+ const byMatcher = new Map();
66
+ for (const h of hooks) {
67
+ const key = h.match ?? "";
68
+ const list = byMatcher.get(key) ?? [];
69
+ list.push(h);
70
+ byMatcher.set(key, list);
71
+ }
72
+ const matcherKeys = [...byMatcher.keys()].sort();
73
+ const groups = [];
74
+ for (const key of matcherKeys) {
75
+ const groupHooks = byMatcher.get(key) ?? [];
76
+ const inner = [...groupHooks]
77
+ .sort((a, b) => (a.command < b.command ? -1 : a.command > b.command ? 1 : 0))
78
+ .map(toSettingsCommand);
79
+ const group = key === "" ? { hooks: inner } : { matcher: key, hooks: inner };
80
+ groups.push(group);
81
+ }
82
+ return groups;
83
+ }
84
+ function toSettingsCommand(h) {
85
+ return { type: "command", command: h.command, timeout: h.budget_ms };
86
+ }
87
+ //# sourceMappingURL=generate-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-settings.js","sourceRoot":"","sources":["../../../src/cli/apply/generate-settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { apply, DRIFT_HINT_MESSAGE, GENERATED_DIRNAME, MANIFEST_BASENAME, MEMORY_BASENAME, SETTINGS_BASENAME, type ApplyOptions, type ApplyOutcome, type ApplyResult, type FileApplyOutcome, } from "./apply.js";
@@ -0,0 +1,2 @@
1
+ export { apply, DRIFT_HINT_MESSAGE, GENERATED_DIRNAME, MANIFEST_BASENAME, MEMORY_BASENAME, SETTINGS_BASENAME, } from "./apply.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/apply/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,GAKlB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type LedgerQueryResult } from "../policies/index.js";
2
+ import { type PolicyDecisionPayload } from "../runtime/ledger-record.js";
3
+ import { type LoaderOptions } from "./loader.js";
4
+ export type AuditOutcome = PolicyDecisionPayload["outcome"];
5
+ export interface AuditOptions extends LoaderOptions {
6
+ json?: boolean;
7
+ since?: string;
8
+ policy?: string;
9
+ outcome?: AuditOutcome;
10
+ sessionId?: string;
11
+ /**
12
+ * Override the ledger fetcher (tests). The optional `filters` arg
13
+ * carries the Phase 5 #5 server-side narrowing hints (sinceIso,
14
+ * contentPrefix); test fakes can ignore it without consequence.
15
+ */
16
+ fetchLedger?: (sessionId: string, filters?: {
17
+ sinceIso?: string;
18
+ contentPrefix?: string;
19
+ }) => Promise<LedgerQueryResult>;
20
+ /** Override "now" (tests). */
21
+ now?: Date;
22
+ }
23
+ export interface AuditDecisionRow {
24
+ timestamp: string;
25
+ name: string;
26
+ outcome: AuditOutcome;
27
+ enforcement: PolicyDecisionPayload["enforcement"];
28
+ reason: string;
29
+ ledgerTag: string;
30
+ extractValues: Record<string, string>;
31
+ }
32
+ export interface AuditResult {
33
+ output: string;
34
+ decisions: AuditDecisionRow[];
35
+ }
36
+ export declare function audit(opts?: AuditOptions): Promise<AuditResult>;
@@ -0,0 +1,121 @@
1
+ import { parseDurationSeconds, parseLedgerTimestamp, queryLedgerByTag, } from "../policies/index.js";
2
+ import { decisionSortKey, decodeLedgerContent, } from "../runtime/ledger-record.js";
3
+ import { resolveSessionId } from "../runtime/session-id.js";
4
+ import { EX_UNAVAILABLE, EX_USAGE, HarnessExitError } from "./exit-codes.js";
5
+ import { loadManifest } from "./loader.js";
6
+ const DEFAULT_SINCE = "24h";
7
+ const VALID_OUTCOMES = ["allow", "deny", "warn-degraded"];
8
+ function isValidOutcome(v) {
9
+ return VALID_OUTCOMES.includes(v);
10
+ }
11
+ function defaultFetcher(opts) {
12
+ return async (sessionId, filters) => {
13
+ const { manifest } = loadManifest(opts);
14
+ const server = manifest.tools.mcp.find((m) => m.name === "grounding-mcp");
15
+ if (!server) {
16
+ return { kind: "degraded", reason: "grounding-mcp not declared in manifest" };
17
+ }
18
+ const command = Array.isArray(server.command)
19
+ ? server.command
20
+ : server.command.trim().split(/\s+/);
21
+ return queryLedgerByTag({
22
+ mcpCommand: command,
23
+ ...(server.env && { mcpEnv: server.env }),
24
+ sessionId,
25
+ timeoutMs: server.health?.timeout_ms ?? 5_000,
26
+ ...(filters?.sinceIso !== undefined && { sinceIso: filters.sinceIso }),
27
+ ...(filters?.contentPrefix !== undefined && { contentPrefix: filters.contentPrefix }),
28
+ });
29
+ };
30
+ }
31
+ function rowsFromEntries(entries) {
32
+ // Decode + retain the entry/payload pair so we can sort by Phase 5 #9's
33
+ // ms-precision `evaluatedAt` before flattening to the display row. The
34
+ // displayed `timestamp` field stays the ledger's `createdAt` (which is
35
+ // what users see in the table); only the sort key changes.
36
+ const decoded = [];
37
+ for (const entry of entries) {
38
+ const payload = decodeLedgerContent(entry.content);
39
+ if (!payload)
40
+ continue;
41
+ decoded.push({ entry, payload });
42
+ }
43
+ decoded.sort((a, b) => decisionSortKey(a.entry, a.payload) - decisionSortKey(b.entry, b.payload));
44
+ return decoded.map(({ entry, payload }) => ({
45
+ timestamp: typeof entry.createdAt === "string"
46
+ ? entry.createdAt
47
+ : entry.createdAt.toISOString(),
48
+ name: payload.name,
49
+ outcome: payload.outcome,
50
+ enforcement: payload.enforcement,
51
+ reason: payload.reason,
52
+ ledgerTag: payload.ledgerTag,
53
+ extractValues: payload.extractValues,
54
+ }));
55
+ }
56
+ function formatTable(rows) {
57
+ if (rows.length === 0)
58
+ return "";
59
+ const header = ["timestamp", "policy", "outcome", "reason"];
60
+ // Reasons are normally single-line; flatten just in case so the column
61
+ // alignment doesn't break on a newline buried in a future policy's reason.
62
+ const flatten = (s) => s.replace(/\s+/g, " ").trim();
63
+ const data = rows.map((r) => [r.timestamp, r.name, r.outcome, flatten(r.reason)]);
64
+ const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
65
+ const fmt = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ").trimEnd();
66
+ const lines = [];
67
+ lines.push(fmt(header));
68
+ lines.push(widths.map((w) => "-".repeat(w)).join(" ").trimEnd());
69
+ for (const row of data)
70
+ lines.push(fmt(row));
71
+ return `${lines.join("\n")}\n`;
72
+ }
73
+ export async function audit(opts = {}) {
74
+ const since = opts.since ?? DEFAULT_SINCE;
75
+ let windowSeconds;
76
+ try {
77
+ windowSeconds = parseDurationSeconds(since);
78
+ }
79
+ catch (err) {
80
+ throw new HarnessExitError(`--since: ${err.message}`, EX_USAGE);
81
+ }
82
+ if (opts.outcome !== undefined && !isValidOutcome(opts.outcome)) {
83
+ throw new HarnessExitError(`--outcome: must be one of allow, deny, warn-degraded (got "${opts.outcome}")`, EX_USAGE);
84
+ }
85
+ const sessionId = resolveSessionId(opts.sessionId);
86
+ const fetch = opts.fetchLedger ?? defaultFetcher(opts);
87
+ // Phase 5 #5 — push filters server-side when the connected
88
+ // grounding-mcp supports them (capability-detected by
89
+ // queryLedgerByTag via tools/list). The audit's own client-side
90
+ // filter math at line ~165 is preserved verbatim, so an old server
91
+ // ignoring these args still produces the correct table.
92
+ const now = opts.now ?? new Date();
93
+ const cutoffMs = now.getTime() - windowSeconds * 1000;
94
+ const sinceIso = new Date(cutoffMs).toISOString();
95
+ const result = await fetch(sessionId, {
96
+ sinceIso,
97
+ contentPrefix: "policy_decision:",
98
+ });
99
+ if (result.kind === "degraded") {
100
+ throw new HarnessExitError(`ledger unreachable: ${result.reason}`, EX_UNAVAILABLE);
101
+ }
102
+ const all = rowsFromEntries(result.entries);
103
+ let filtered = all.filter((r) => parseLedgerTimestamp(r.timestamp) >= cutoffMs);
104
+ if (opts.policy) {
105
+ filtered = filtered.filter((r) => r.name === opts.policy);
106
+ }
107
+ if (opts.outcome) {
108
+ filtered = filtered.filter((r) => r.outcome === opts.outcome);
109
+ }
110
+ if (filtered.length === 0) {
111
+ const output = opts.json
112
+ ? `${JSON.stringify({ decisions: [] }, null, 2)}\n`
113
+ : `no policy decisions in the last ${since}\n`;
114
+ return { output, decisions: [] };
115
+ }
116
+ const output = opts.json
117
+ ? `${JSON.stringify({ decisions: filtered }, null, 2)}\n`
118
+ : formatTable(filtered);
119
+ return { output, decisions: filtered };
120
+ }
121
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/cli/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Manifest } from "../schema/index.js";
2
+ import { type LoaderOptions } from "./loader.js";
3
+ export type Pillar = "grounding" | "tools" | "memory" | "hooks" | "policies";
4
+ export declare function isPillar(value: string): value is Pillar;
5
+ export interface DescribeOptions extends LoaderOptions {
6
+ pillar?: Pillar;
7
+ json?: boolean;
8
+ }
9
+ export interface DescribeResult {
10
+ output: string;
11
+ manifest: Manifest;
12
+ }
13
+ export declare function describe(opts?: DescribeOptions): DescribeResult;
@@ -0,0 +1,26 @@
1
+ import { stringify as stringifyYaml } from "yaml";
2
+ import { loadManifest } from "./loader.js";
3
+ const PILLARS = [
4
+ "grounding",
5
+ "tools",
6
+ "memory",
7
+ "hooks",
8
+ "policies",
9
+ ];
10
+ export function isPillar(value) {
11
+ return PILLARS.includes(value);
12
+ }
13
+ function projectPillar(manifest, pillar) {
14
+ return { version: manifest.version, [pillar]: manifest[pillar] };
15
+ }
16
+ export function describe(opts = {}) {
17
+ const { manifest } = loadManifest(opts);
18
+ const projection = opts.pillar
19
+ ? projectPillar(manifest, opts.pillar)
20
+ : manifest;
21
+ const output = opts.json
22
+ ? JSON.stringify(projection, null, 2)
23
+ : stringifyYaml(projection, { lineWidth: 0 });
24
+ return { output, manifest };
25
+ }
26
+ //# sourceMappingURL=describe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/cli/describe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAElD,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAI/D,MAAM,OAAO,GAAsB;IACjC,WAAW;IACX,OAAO;IACP,QAAQ;IACR,OAAO;IACP,UAAU;CACX,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAQ,OAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAYD,SAAS,aAAa,CAAC,QAAkB,EAAE,MAAc;IACvD,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAwB,EAAE;IACjD,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,UAAU,GAA4B,IAAI,CAAC,MAAM;QACrD,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;QACtC,CAAC,CAAE,QAA+C,CAAC;IAErD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI;QACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,aAAa,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;IAEhD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,21 @@
1
+ export type ChangeKind = "added" | "removed" | "modified";
2
+ export interface Change {
3
+ kind: ChangeKind;
4
+ path: string;
5
+ before?: unknown;
6
+ after?: unknown;
7
+ }
8
+ declare function isNameKeyedList(arr: unknown[]): arr is Array<Record<string, unknown> & {
9
+ name: string;
10
+ }>;
11
+ declare function fmtPath(parts: Array<string | number>): string;
12
+ export declare function diffManifests(before: unknown, after: unknown): Change[];
13
+ declare function pillarOf(changePath: string): string;
14
+ export declare function groupByPillar(changes: Change[]): Map<string, Change[]>;
15
+ export declare function formatDiff(changes: Change[]): string;
16
+ export declare const __testables: {
17
+ isNameKeyedList: typeof isNameKeyedList;
18
+ fmtPath: typeof fmtPath;
19
+ pillarOf: typeof pillarOf;
20
+ };
21
+ export {};
@@ -0,0 +1,161 @@
1
+ const PILLAR_ORDER = ["version", "grounding", "tools", "memory", "hooks", "policies"];
2
+ function isPlainObject(v) {
3
+ return typeof v === "object" && v !== null && !Array.isArray(v);
4
+ }
5
+ function isNameKeyedList(arr) {
6
+ if (arr.length === 0)
7
+ return false;
8
+ return arr.every((item) => isPlainObject(item) && typeof item.name === "string");
9
+ }
10
+ function fmtPath(parts) {
11
+ let out = "";
12
+ for (const p of parts) {
13
+ if (typeof p === "number") {
14
+ out += `[${p}]`;
15
+ }
16
+ else if (out === "") {
17
+ out = p;
18
+ }
19
+ else {
20
+ out += `.${p}`;
21
+ }
22
+ }
23
+ return out;
24
+ }
25
+ function fmtPathWithName(parts) {
26
+ let out = "";
27
+ for (const p of parts) {
28
+ if (typeof p === "number") {
29
+ out += `[${p}]`;
30
+ }
31
+ else if (typeof p === "object") {
32
+ out += `[${p.name}]`;
33
+ }
34
+ else if (out === "") {
35
+ out = p;
36
+ }
37
+ else {
38
+ out += `.${p}`;
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ function diffArrays(before, after, pathParts, out) {
44
+ const beforeNamed = isNameKeyedList(before);
45
+ const afterNamed = isNameKeyedList(after);
46
+ if (beforeNamed && afterNamed) {
47
+ const byName = new Map();
48
+ for (const item of before)
49
+ byName.set(item.name, item);
50
+ const seen = new Set();
51
+ for (const item of after) {
52
+ const prev = byName.get(item.name);
53
+ seen.add(item.name);
54
+ if (!prev) {
55
+ out.push({ kind: "added", path: fmtPathWithName([...pathParts, { name: item.name }]), after: item });
56
+ }
57
+ else {
58
+ diffValue(prev, item, [...pathParts, { name: item.name }], out);
59
+ }
60
+ }
61
+ for (const [name, item] of byName) {
62
+ if (!seen.has(name)) {
63
+ out.push({ kind: "removed", path: fmtPathWithName([...pathParts, { name }]), before: item });
64
+ }
65
+ }
66
+ return;
67
+ }
68
+ if (JSON.stringify(before) !== JSON.stringify(after)) {
69
+ out.push({ kind: "modified", path: fmtPathWithName(pathParts), before, after });
70
+ }
71
+ }
72
+ function diffObjects(before, after, pathParts, out) {
73
+ const keys = new Set([...Object.keys(before), ...Object.keys(after)]);
74
+ for (const key of keys) {
75
+ const a = before[key];
76
+ const b = after[key];
77
+ if (a === undefined && b !== undefined) {
78
+ out.push({ kind: "added", path: fmtPathWithName([...pathParts, key]), after: b });
79
+ }
80
+ else if (b === undefined && a !== undefined) {
81
+ out.push({ kind: "removed", path: fmtPathWithName([...pathParts, key]), before: a });
82
+ }
83
+ else if (!equal(a, b)) {
84
+ diffValue(a, b, [...pathParts, key], out);
85
+ }
86
+ }
87
+ }
88
+ function equal(a, b) {
89
+ return JSON.stringify(a) === JSON.stringify(b);
90
+ }
91
+ function diffValue(before, after, pathParts, out) {
92
+ if (equal(before, after))
93
+ return;
94
+ if (Array.isArray(before) && Array.isArray(after)) {
95
+ diffArrays(before, after, pathParts, out);
96
+ return;
97
+ }
98
+ if (isPlainObject(before) && isPlainObject(after)) {
99
+ diffObjects(before, after, pathParts, out);
100
+ return;
101
+ }
102
+ out.push({ kind: "modified", path: fmtPathWithName(pathParts), before, after });
103
+ }
104
+ export function diffManifests(before, after) {
105
+ const out = [];
106
+ diffValue(before, after, [], out);
107
+ return out;
108
+ }
109
+ function pillarOf(changePath) {
110
+ for (const pillar of PILLAR_ORDER) {
111
+ if (changePath === pillar || changePath.startsWith(`${pillar}.`) || changePath.startsWith(`${pillar}[`)) {
112
+ return pillar;
113
+ }
114
+ }
115
+ return "(other)";
116
+ }
117
+ export function groupByPillar(changes) {
118
+ const out = new Map();
119
+ for (const pillar of PILLAR_ORDER)
120
+ out.set(pillar, []);
121
+ out.set("(other)", []);
122
+ for (const c of changes) {
123
+ const p = pillarOf(c.path);
124
+ out.get(p).push(c);
125
+ }
126
+ for (const [k, v] of out)
127
+ if (v.length === 0)
128
+ out.delete(k);
129
+ return out;
130
+ }
131
+ function renderValue(v) {
132
+ if (typeof v === "string")
133
+ return v;
134
+ return JSON.stringify(v);
135
+ }
136
+ export function formatDiff(changes) {
137
+ if (changes.length === 0)
138
+ return "no changes\n";
139
+ const lines = [];
140
+ const grouped = groupByPillar(changes);
141
+ for (const [pillar, group] of grouped) {
142
+ lines.push(`## ${pillar}`);
143
+ for (const c of group) {
144
+ switch (c.kind) {
145
+ case "added":
146
+ lines.push(`+ ${c.path}: ${renderValue(c.after)}`);
147
+ break;
148
+ case "removed":
149
+ lines.push(`- ${c.path}: ${renderValue(c.before)}`);
150
+ break;
151
+ case "modified":
152
+ lines.push(`~ ${c.path}: ${renderValue(c.before)} → ${renderValue(c.after)}`);
153
+ break;
154
+ }
155
+ }
156
+ lines.push("");
157
+ }
158
+ return `${lines.join("\n")}`;
159
+ }
160
+ export const __testables = { isNameKeyedList, fmtPath, pillarOf };
161
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/cli/diff/engine.ts"],"names":[],"mappings":"AASA,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAU,CAAC;AAE/F,SAAS,aAAa,CAAC,CAAU;IAC/B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,eAAe,CAAC,GAAc;IACrC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,OAAO,CAAC,KAA6B;IAC5C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QAClB,CAAC;aAAM,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YACtB,GAAG,GAAG,CAAC,CAAC;QACV,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,eAAe,CAAC,KAAgD;IACvE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QAClB,CAAC;aAAM,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YACjC,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC;QACvB,CAAC;aAAM,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YACtB,GAAG,GAAG,CAAC,CAAC;QACV,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CACjB,MAAiB,EACjB,KAAgB,EAChB,SAAoD,EACpD,GAAa;IAEb,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,WAAW,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC1D,KAAK,MAAM,IAAI,IAAI,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,GAAG,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACvG,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,GAAG,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/F,CAAC;QACH,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAClB,MAA+B,EAC/B,KAA8B,EAC9B,SAAoD,EACpD,GAAa;IAEb,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;aAAM,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9C,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACvF,CAAC;aAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACxB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,CAAU,EAAE,CAAU;IACnC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,SAAS,CAChB,MAAe,EACf,KAAc,EACd,SAAoD,EACpD,GAAa;IAEb,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO;IACjC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAe,EAAE,KAAc;IAC3D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,UAAkB;IAClC,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;QAClC,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC;YACxG,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAiB;IAC7C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,MAAM,MAAM,IAAI,YAAY;QAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACvB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG;QAAE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,CAAU;IAC7B,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAiB;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,cAAc,CAAC;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;gBACf,KAAK,OAAO;oBACV,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBACnD,MAAM;gBACR,KAAK,SAAS;oBACZ,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBACpD,MAAM;gBACR,KAAK,UAAU;oBACb,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;oBAC9E,MAAM;YACV,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface GitContext {
2
+ root: string;
3
+ manifestRelPath: string;
4
+ }
5
+ export declare function locateGitContext(manifestPath: string): GitContext;
6
+ export declare function readManifestAtRef(ctx: GitContext, ref: string): string;
@@ -0,0 +1,32 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import * as path from "node:path";
3
+ import { EX_UNAVAILABLE, EX_USAGE, HarnessExitError } from "../exit-codes.js";
4
+ function runGit(args, cwd) {
5
+ return execFileSync("git", args, {
6
+ cwd,
7
+ encoding: "utf8",
8
+ stdio: ["ignore", "pipe", "pipe"],
9
+ });
10
+ }
11
+ export function locateGitContext(manifestPath) {
12
+ const dir = path.dirname(path.resolve(manifestPath));
13
+ let root;
14
+ try {
15
+ root = runGit(["rev-parse", "--show-toplevel"], dir).trim();
16
+ }
17
+ catch (err) {
18
+ throw new HarnessExitError(`git is not available or ${dir} is not inside a git work tree: ${err.message.trim()}`, EX_UNAVAILABLE);
19
+ }
20
+ const relPath = path.relative(root, path.resolve(manifestPath));
21
+ return { root, manifestRelPath: relPath };
22
+ }
23
+ export function readManifestAtRef(ctx, ref) {
24
+ try {
25
+ return runGit(["show", `${ref}:${ctx.manifestRelPath}`], ctx.root);
26
+ }
27
+ catch (err) {
28
+ const message = err.stderr?.trim() || err.message;
29
+ throw new HarnessExitError(`cannot read ${ctx.manifestRelPath} at git ref "${ref}": ${message}`, EX_USAGE);
30
+ }
31
+ }
32
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/cli/diff/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAO9E,SAAS,MAAM,CAAC,IAAc,EAAE,GAAW;IACzC,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;QAC/B,GAAG;QACH,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,YAAoB;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IACrD,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,gBAAgB,CACxB,2BAA2B,GAAG,mCAAoC,GAAa,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAChG,cAAc,CACf,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IAChE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAe,EAAE,GAAW;IAC5D,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAI,GAAmC,CAAC,MAAM,EAAE,IAAI,EAAE,IAAK,GAAa,CAAC,OAAO,CAAC;QAC9F,MAAM,IAAI,gBAAgB,CACxB,eAAe,GAAG,CAAC,eAAe,gBAAgB,GAAG,MAAM,OAAO,EAAE,EACpE,QAAQ,CACT,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type Manifest } from "../../schema/index.js";
2
+ import { type LoaderOptions } from "../loader.js";
3
+ import { type Change } from "./engine.js";
4
+ export interface DiffOptions extends LoaderOptions {
5
+ since?: string;
6
+ }
7
+ export interface DiffResult {
8
+ changes: Change[];
9
+ output: string;
10
+ before: Manifest;
11
+ after: Manifest;
12
+ }
13
+ export declare function diff(opts: DiffOptions): DiffResult;
14
+ export { diffManifests, formatDiff } from "./engine.js";
15
+ export type { Change, ChangeKind } from "./engine.js";
@@ -0,0 +1,39 @@
1
+ import { parse as parseYaml } from "yaml";
2
+ import { ManifestParseError, parseManifest } from "../../schema/index.js";
3
+ import { EX_NOINPUT, EX_USAGE, HarnessExitError } from "../exit-codes.js";
4
+ import { loadManifest, resolvePaths } from "../loader.js";
5
+ import { diffManifests, formatDiff } from "./engine.js";
6
+ import { locateGitContext, readManifestAtRef } from "./git.js";
7
+ function parseRefManifest(raw) {
8
+ let parsed;
9
+ try {
10
+ parsed = parseYaml(raw);
11
+ }
12
+ catch (err) {
13
+ throw new HarnessExitError(`manifest at git ref is not valid YAML: ${err.message}`, EX_NOINPUT);
14
+ }
15
+ try {
16
+ return parseManifest(parsed);
17
+ }
18
+ catch (err) {
19
+ if (err instanceof ManifestParseError) {
20
+ throw new HarnessExitError(`manifest at git ref failed schema validation:\n${err.message}`, EX_NOINPUT);
21
+ }
22
+ throw err;
23
+ }
24
+ }
25
+ export function diff(opts) {
26
+ if (!opts.since) {
27
+ throw new HarnessExitError("harness diff requires --since <ref>; --since-apply lands in Phase 3", EX_USAGE);
28
+ }
29
+ const resolved = resolvePaths(opts);
30
+ const ctx = locateGitContext(resolved.base);
31
+ const refRaw = readManifestAtRef(ctx, opts.since);
32
+ const before = parseRefManifest(refRaw);
33
+ const { manifest: after } = loadManifest(opts);
34
+ const changes = diffManifests(before, after);
35
+ const output = formatDiff(changes);
36
+ return { changes, output, before, after };
37
+ }
38
+ export { diffManifests, formatDiff } from "./engine.js";
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/diff/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAiB,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAsB,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,UAAU,EAAe,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAa/D,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,gBAAgB,CACxB,0CAA2C,GAAa,CAAC,OAAO,EAAE,EAClE,UAAU,CACX,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;YACtC,MAAM,IAAI,gBAAgB,CACxB,kDAAkD,GAAG,CAAC,OAAO,EAAE,EAC/D,UAAU,CACX,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAiB;IACpC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,gBAAgB,CACxB,qEAAqE,EACrE,QAAQ,CACT,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC5C,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}