@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,97 @@
1
+ import { stringify as stringifyYaml } from "yaml";
2
+ import { queryLedgerByTag, } from "../policies/index.js";
3
+ import { decisionSortKey, decodeLedgerContent, } from "../runtime/ledger-record.js";
4
+ import { resolveSessionId } from "../runtime/session-id.js";
5
+ import { EX_FAIL, EX_USAGE, HarnessExitError } from "./exit-codes.js";
6
+ import { loadManifest } from "./loader.js";
7
+ function defaultFetcher(opts) {
8
+ return async (sessionId) => {
9
+ const { manifest } = loadManifest(opts);
10
+ const server = manifest.tools.mcp.find((m) => m.name === "grounding-mcp");
11
+ if (!server) {
12
+ return { kind: "degraded", reason: "grounding-mcp not declared in manifest" };
13
+ }
14
+ const command = Array.isArray(server.command)
15
+ ? server.command
16
+ : server.command.trim().split(/\s+/);
17
+ return queryLedgerByTag({
18
+ mcpCommand: command,
19
+ ...(server.env && { mcpEnv: server.env }),
20
+ sessionId,
21
+ timeoutMs: server.health?.timeout_ms ?? 5_000,
22
+ });
23
+ };
24
+ }
25
+ function selectLatestForPolicy(entries, policyName) {
26
+ const matches = entries
27
+ .map((e) => {
28
+ const payload = decodeLedgerContent(e.content);
29
+ if (!payload)
30
+ return null;
31
+ if (payload.name !== policyName)
32
+ return null;
33
+ return { entry: e, payload };
34
+ })
35
+ .filter((x) => x !== null);
36
+ if (matches.length === 0)
37
+ return null;
38
+ matches.sort((a, b) => decisionSortKey(b.entry, b.payload) - decisionSortKey(a.entry, a.payload));
39
+ return matches[0];
40
+ }
41
+ export async function explain(policyName, opts = {}) {
42
+ const { manifest } = loadManifest(opts);
43
+ const policy = manifest.policies.find((p) => p.name === policyName);
44
+ if (!policy) {
45
+ const available = manifest.policies.map((p) => p.name).join(", ") || "(none)";
46
+ throw new HarnessExitError(`no policy named "${policyName}" declared; available: ${available}`, EX_USAGE);
47
+ }
48
+ if (!opts.trace) {
49
+ const projection = {
50
+ name: policy.name,
51
+ description: policy.description,
52
+ trigger: policy.trigger,
53
+ requires: policy.requires,
54
+ hook: policy.hook,
55
+ enforcement: policy.enforcement,
56
+ note: "run with --trace to see the last evaluation's full decision trail",
57
+ };
58
+ const output = opts.json
59
+ ? `${JSON.stringify(projection, null, 2)}\n`
60
+ : stringifyYaml(projection, { lineWidth: 0 });
61
+ return { output };
62
+ }
63
+ const sessionId = resolveSessionId(opts.sessionId);
64
+ const fetch = opts.fetchLedger ?? defaultFetcher(opts);
65
+ const result = await fetch(sessionId);
66
+ if (result.kind === "degraded") {
67
+ throw new HarnessExitError(`cannot read audit log: ${result.reason}`, EX_FAIL);
68
+ }
69
+ const latest = selectLatestForPolicy(result.entries, policyName);
70
+ if (!latest) {
71
+ throw new HarnessExitError(`no recorded evaluations for policy \`${policyName}\`; the policy may not have fired yet, or grounding-mcp is unreachable`, EX_FAIL);
72
+ }
73
+ const projection = {
74
+ name: latest.payload.name,
75
+ decision: latest.payload.outcome,
76
+ enforcement: latest.payload.enforcement,
77
+ reason: latest.payload.reason,
78
+ ledgerTag: latest.payload.ledgerTag,
79
+ evaluatedAt: latest.payload.evaluatedAt,
80
+ triggerMatched: {
81
+ event: policy.trigger.event,
82
+ ...(policy.trigger.match !== undefined && { match: policy.trigger.match }),
83
+ ...(policy.trigger.bash_match !== undefined && {
84
+ bashMatch: policy.trigger.bash_match,
85
+ }),
86
+ },
87
+ extract: latest.payload.extractValues,
88
+ ...(latest.payload.requiresEval && { requiresEval: latest.payload.requiresEval }),
89
+ // sessionId is resolved via runtime/session-id.ts: explicit > env > "default".
90
+ ledgerQuery: { verb: "ledger_summary", sessionId },
91
+ };
92
+ const output = opts.json
93
+ ? `${JSON.stringify(projection, null, 2)}\n`
94
+ : stringifyYaml(projection, { lineWidth: 0 });
95
+ return { output };
96
+ }
97
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/cli/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { Manifest } from "../schema/index.js";
2
+ import { type LoaderOptions } from "./loader.js";
3
+ export interface ExportOptions extends LoaderOptions {
4
+ json?: boolean;
5
+ sanitize?: boolean;
6
+ outputPath?: string;
7
+ }
8
+ export interface ExportResult {
9
+ output: string;
10
+ manifest: Manifest;
11
+ sanitized: boolean;
12
+ wroteTo: string | null;
13
+ }
14
+ export declare const SANITIZE_FOOTER: string;
15
+ export declare function exportManifest(opts?: ExportOptions): ExportResult;
16
+ /**
17
+ * Best-effort sanitiser. Walks the manifest, replaces `/home/<user>/...` paths
18
+ * with `~/...` and redacts env values whose key looks credential-shaped. Does
19
+ * NOT touch command:[] entries (they often contain absolute paths that are
20
+ * intentional and not secret) and does NOT inspect policy ledger_tag values.
21
+ */
22
+ export declare function sanitize(value: unknown, homeDir: string): unknown;
23
+ declare function isInsideEnvBlock(pathSegs: (string | number)[]): boolean;
24
+ declare function rewriteHomePath(s: string, homeDir: string): string;
25
+ export declare const __testables: {
26
+ sanitize: typeof sanitize;
27
+ rewriteHomePath: typeof rewriteHomePath;
28
+ isInsideEnvBlock: typeof isInsideEnvBlock;
29
+ SECRET_KEY_PATTERN: RegExp;
30
+ };
31
+ export {};
@@ -0,0 +1,84 @@
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
3
+ import { stringify as stringifyYaml } from "yaml";
4
+ import { atomicWriteFile } from "../io/atomic-write.js";
5
+ import { loadManifest } from "./loader.js";
6
+ const SECRET_KEY_PATTERN = /(?:_|^)(KEY|TOKEN|SECRET|PASSWORD|API_KEY)$/i;
7
+ const REDACTED = "<REDACTED>";
8
+ export const SANITIZE_FOOTER = "# sanitised: /home/<user>/ paths replaced with ~/; env values whose key " +
9
+ "matches /(_|^)(KEY|TOKEN|SECRET|PASSWORD|API_KEY)$/i are redacted. The " +
10
+ "sanitiser does NOT touch secrets in command:[] arrays or in policy " +
11
+ "`requires.ledger_tag` values; review before sharing.";
12
+ export function exportManifest(opts = {}) {
13
+ const { manifest } = loadManifest(opts);
14
+ const projection = manifest;
15
+ const projected = opts.sanitize ? sanitize(projection, os.homedir()) : projection;
16
+ let output;
17
+ if (opts.json) {
18
+ output = JSON.stringify(projected, null, 2);
19
+ if (!output.endsWith("\n"))
20
+ output += "\n";
21
+ }
22
+ else {
23
+ output = stringifyYaml(projected, {
24
+ lineWidth: 0,
25
+ flowCollectionPadding: false,
26
+ });
27
+ if (opts.sanitize)
28
+ output += `\n${SANITIZE_FOOTER}\n`;
29
+ }
30
+ let wroteTo = null;
31
+ if (opts.outputPath) {
32
+ const target = path.resolve(opts.outputPath);
33
+ atomicWriteFile(target, output);
34
+ wroteTo = target;
35
+ }
36
+ return { output, manifest, sanitized: !!opts.sanitize, wroteTo };
37
+ }
38
+ /**
39
+ * Best-effort sanitiser. Walks the manifest, replaces `/home/<user>/...` paths
40
+ * with `~/...` and redacts env values whose key looks credential-shaped. Does
41
+ * NOT touch command:[] entries (they often contain absolute paths that are
42
+ * intentional and not secret) and does NOT inspect policy ledger_tag values.
43
+ */
44
+ export function sanitize(value, homeDir) {
45
+ return walk(value, homeDir, []);
46
+ }
47
+ function walk(value, homeDir, pathSegs) {
48
+ if (Array.isArray(value)) {
49
+ return value.map((v, i) => walk(v, homeDir, [...pathSegs, i]));
50
+ }
51
+ if (value !== null && typeof value === "object") {
52
+ const out = {};
53
+ for (const [k, v] of Object.entries(value)) {
54
+ if (isInsideEnvBlock(pathSegs) && SECRET_KEY_PATTERN.test(k) && typeof v === "string") {
55
+ out[k] = REDACTED;
56
+ }
57
+ else {
58
+ out[k] = walk(v, homeDir, [...pathSegs, k]);
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ if (typeof value === "string") {
64
+ return rewriteHomePath(value, homeDir);
65
+ }
66
+ return value;
67
+ }
68
+ function isInsideEnvBlock(pathSegs) {
69
+ // Immediate parent key must be `env` — i.e. we're walking a {KEY: value}
70
+ // map directly under an env: section. Today that's only `tools.mcp[].env`.
71
+ return pathSegs[pathSegs.length - 1] === "env";
72
+ }
73
+ function rewriteHomePath(s, homeDir) {
74
+ if (homeDir.length === 0 || homeDir === "/")
75
+ return s;
76
+ const escaped = homeDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
77
+ // Lookahead `/` or end-of-string so `/home/lan` does not match inside
78
+ // `/home/landscape`. We deliberately don't use \b — the homeDir's last char
79
+ // could be a "word" character that erases the boundary semantics on a
80
+ // following slash.
81
+ return s.replace(new RegExp(`${escaped}(?=/|$)`, "g"), "~");
82
+ }
83
+ export const __testables = { sanitize, rewriteHomePath, isInsideEnvBlock, SECRET_KEY_PATTERN };
84
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { Command } from "commander";
2
+ export interface RunOptions {
3
+ argv?: string[];
4
+ stdout?: (s: string) => void;
5
+ stderr?: (s: string) => void;
6
+ }
7
+ export declare function buildProgram(opts?: RunOptions): Command;
8
+ export declare function run(opts?: RunOptions): Promise<number>;