@lannguyensi/harness 0.30.1 → 0.32.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 (53) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -0
  3. package/dist/cli/index.js +59 -0
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/cli/init/templates.d.ts +1 -1
  6. package/dist/cli/init/templates.js +15 -0
  7. package/dist/cli/init/templates.js.map +1 -1
  8. package/dist/cli/pack/hook-branch-protection.js +2 -1
  9. package/dist/cli/pack/hook-branch-protection.js.map +1 -1
  10. package/dist/cli/pack/hook-codex-pre-tool-use.js +4 -3
  11. package/dist/cli/pack/hook-codex-pre-tool-use.js.map +1 -1
  12. package/dist/cli/pack/hook-codex-stop.js +1 -0
  13. package/dist/cli/pack/hook-codex-stop.js.map +1 -1
  14. package/dist/cli/pack/hook-post-tool-use.js +1 -0
  15. package/dist/cli/pack/hook-post-tool-use.js.map +1 -1
  16. package/dist/cli/pack/hook-pre-tool-use.js +3 -2
  17. package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
  18. package/dist/cli/pack/hook-runtime-reality.d.ts +50 -0
  19. package/dist/cli/pack/hook-runtime-reality.js +160 -0
  20. package/dist/cli/pack/hook-runtime-reality.js.map +1 -0
  21. package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +26 -0
  22. package/dist/cli/pack/hook-solution-acceptance-writeguard.js +187 -0
  23. package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +1 -0
  24. package/dist/cli/pack/hook-solution-acceptance.d.ts +26 -0
  25. package/dist/cli/pack/hook-solution-acceptance.js +237 -0
  26. package/dist/cli/pack/hook-solution-acceptance.js.map +1 -0
  27. package/dist/cli/pause/index.d.ts +17 -3
  28. package/dist/cli/pause/index.js +30 -6
  29. package/dist/cli/pause/index.js.map +1 -1
  30. package/dist/cli/policy/intercept.js +7 -1
  31. package/dist/cli/policy/intercept.js.map +1 -1
  32. package/dist/cli/session-start/branch-check.js +4 -2
  33. package/dist/cli/session-start/branch-check.js.map +1 -1
  34. package/dist/cli/session-start/index.js +4 -2
  35. package/dist/cli/session-start/index.js.map +1 -1
  36. package/dist/cli/validate/checks.js +38 -0
  37. package/dist/cli/validate/checks.js.map +1 -1
  38. package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +119 -0
  39. package/dist/policy-packs/builtin/solution-acceptance-runtime.js +289 -0
  40. package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -0
  41. package/dist/policy-packs/builtin/solution-acceptance.d.ts +44 -0
  42. package/dist/policy-packs/builtin/solution-acceptance.js +185 -0
  43. package/dist/policy-packs/builtin/solution-acceptance.js.map +1 -0
  44. package/dist/policy-packs/registry.d.ts +1 -1
  45. package/dist/policy-packs/registry.js +10 -0
  46. package/dist/policy-packs/registry.js.map +1 -1
  47. package/dist/runtime/risk-classifier.js +64 -0
  48. package/dist/runtime/risk-classifier.js.map +1 -1
  49. package/dist/runtime/session-id.d.ts +4 -3
  50. package/dist/runtime/session-id.js +17 -5
  51. package/dist/runtime/session-id.js.map +1 -1
  52. package/package.json +3 -1
  53. package/scripts/runtime-reality-docker-probe.mjs +71 -0
@@ -16,6 +16,11 @@
16
16
  // default; this module's job is only to report the unclassified state
17
17
  // honestly.
18
18
  //
19
+ // The one built-in exception is harness's own benign meta-commands (see
20
+ // BENIGN_HARNESS_COMMAND below): leaving them unclassified would let the
21
+ // fail-close gate deny `harness preflight` — a command other harness
22
+ // gates require — so they get a recognized `low`-severity floor.
23
+ //
19
24
  // Design source: lava-ice-logs/2026-04-30/harness-risk-gate-extension.md
20
25
  // (design phase B).
21
26
  import { RiskSeveritySchema } from "../schema/index.js";
@@ -32,6 +37,50 @@ const SEVERITY_ORDER = RiskSeveritySchema.options;
32
37
  // caution. A genuinely destructive-but-reversible action simply should
33
38
  // not be tagged `destructive` by its classifier author.
34
39
  const IRREVERSIBLE_CATEGORIES = new Set(["irreversible_action", "data_loss", "destructive"]);
40
+ // Built-in benign-harness-command floor.
41
+ //
42
+ // harness's own read-only and gate-producer subcommands are benign: they
43
+ // read state, record evidence, or print diagnostics, and several
44
+ // (`harness preflight`, `harness session-start`) are REQUIRED by other
45
+ // harness gates (require-preflight-evidence et al). Leaving them
46
+ // unclassified lets the "unknown is not safe" fail-close treat them as
47
+ // risk-bearing, so a `when: { risk.severity_at_least: critical,
48
+ // environment.name: production }` policy HARD-DENIES `harness preflight`
49
+ // the moment a session resolves to production (a main / release branch)
50
+ // — deadlocking against the very gate that demands it. So we recognize
51
+ // these as a `low`-severity floor.
52
+ //
53
+ // Floor, not override: the contribution composes with operator
54
+ // classifiers under the same highest-severity-wins rule, so
55
+ // `harness preflight && rm -rf /var` still classifies `critical` (the
56
+ // dangerous-shell tail wins) and an operator pattern can only RAISE the
57
+ // severity, never sink below this floor. Mutating subcommands (`apply`,
58
+ // `init`, `add`, `adopt`, `remove`, `pack`, `uninstall`, `migrate-home`,
59
+ // `smoke`, `gate`, `pause`, `resume`) are deliberately excluded — they
60
+ // stay classifiable. Anchored at the command head, so `cd /x && harness
61
+ // preflight` does NOT match and stays unclassified (fail-safe = denied):
62
+ // a benign prefix must not launder a non-harness command.
63
+ const BENIGN_HARNESS_SUBCOMMANDS = [
64
+ "preflight",
65
+ "session-start",
66
+ "approve",
67
+ "doctor",
68
+ "validate",
69
+ "describe",
70
+ "list",
71
+ "diff",
72
+ "explain",
73
+ "explain-action",
74
+ "explain-policy",
75
+ "test-risk",
76
+ "resolve-env",
77
+ "audit",
78
+ "session-export",
79
+ "dry-run",
80
+ "export",
81
+ "help",
82
+ ];
83
+ const BENIGN_HARNESS_COMMAND = new RegExp(`^\\s*harness\\s+(?:${BENIGN_HARNESS_SUBCOMMANDS.join("|")})\\b`);
35
84
  // Hot-path ReDoS guard (Phase 7 #6). As of Phase 7 #5/#6 the classifier
36
85
  // runs operator-authored regexes against tool input on EVERY PreToolUse
37
86
  // call inside `harness policy intercept`. Catastrophic-backtracking cost
@@ -121,6 +170,21 @@ export function classifyRisk(envelope, classifiers) {
121
170
  `severity ${pat.severity}, categories [${pat.categories.join(", ")}]`);
122
171
  }
123
172
  }
173
+ // Built-in benign-harness floor (see BENIGN_HARNESS_COMMAND above).
174
+ // Folded in AFTER the operator loop so it composes by the same
175
+ // highest-severity-wins rule: it only raises an otherwise-unclassified
176
+ // action up to `low`, and never sinks an operator match (a dangerous
177
+ // tail in `harness preflight && rm -rf /var` keeps the higher
178
+ // severity). Gated on a real shell command so a non-shell tool whose
179
+ // serialized input happens to start with "harness" cannot match.
180
+ const shellCommand = extractShellCommand({ raw_input: envelope.raw_input });
181
+ if (shellCommand !== null && BENIGN_HARNESS_COMMAND.test(subject)) {
182
+ const lowIdx = SEVERITY_ORDER.indexOf("low");
183
+ if (lowIdx > severityIdx) {
184
+ severityIdx = lowIdx;
185
+ reasons.push("built-in: benign harness meta-command recognized (severity low)");
186
+ }
187
+ }
124
188
  if (severityIdx === -1) {
125
189
  return {
126
190
  classified: false,
@@ -1 +1 @@
1
- {"version":3,"file":"risk-classifier.js","sourceRoot":"","sources":["../../src/runtime/risk-classifier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"risk-classifier.js","sourceRoot":"","sources":["../../src/runtime/risk-classifier.ts"],"names":[],"mappings":"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"}
@@ -38,9 +38,10 @@ export interface ResolveReadSessionOptions extends DiscoverSessionOptions {
38
38
  *
39
39
  * Precedence:
40
40
  * 1. explicit value (the `--session` flag)
41
- * 2. `$CLAUDE_SESSION_ID` env
42
- * 3. newest Claude Code transcript (the live session)
43
- * 4. literal `"default"`
41
+ * 2. `$CLAUDE_CODE_SESSION_ID` env (the var Claude Code actually exports)
42
+ * 3. `$CLAUDE_SESSION_ID` env (legacy fallback)
43
+ * 4. newest Claude Code transcript (the live session)
44
+ * 5. literal `"default"`
44
45
  *
45
46
  * The WRITE path keeps `resolveSessionId`: it always has
46
47
  * `event.session_id`, so it never reaches the discovery tier, and a
@@ -13,8 +13,9 @@
13
13
  // WRITE path (`policy intercept`), which always carries a concrete
14
14
  // `event.session_id`:
15
15
  // 1. explicit value (the runtime's `event.session_id`)
16
- // 2. `$CLAUDE_SESSION_ID` env
17
- // 3. literal `"default"`
16
+ // 2. `$CLAUDE_CODE_SESSION_ID` env (the var Claude Code actually exports)
17
+ // 3. `$CLAUDE_SESSION_ID` env (legacy fallback)
18
+ // 4. literal `"default"`
18
19
  //
19
20
  // The READ path (`audit`, `explain --trace/--last`) needs more. The
20
21
  // Phase 5 #2 fix assumed `$CLAUDE_SESSION_ID` is exported into the
@@ -25,6 +26,10 @@
25
26
  // the active session id off the newest Claude Code transcript JSONL.
26
27
  // That is the programmatic form of the heuristic `harness approve`'s
27
28
  // own help text recommends to humans.
29
+ //
30
+ // Both resolvers also accept `$CLAUDE_CODE_SESSION_ID` as a higher-priority
31
+ // env tier than the legacy `$CLAUDE_SESSION_ID`, mirroring the
32
+ // `harness approve` verbs (`src/cli/approve/{risk,understanding}.ts`).
28
33
  import * as fs from "node:fs";
29
34
  import * as os from "node:os";
30
35
  import * as path from "node:path";
@@ -41,6 +46,9 @@ const FALLBACK = "default";
41
46
  export function resolveSessionId(explicit) {
42
47
  if (typeof explicit === "string" && explicit.length > 0)
43
48
  return explicit;
49
+ const envCode = process.env.CLAUDE_CODE_SESSION_ID;
50
+ if (typeof envCode === "string" && envCode.length > 0)
51
+ return envCode;
44
52
  const env = process.env.CLAUDE_SESSION_ID;
45
53
  if (typeof env === "string" && env.length > 0)
46
54
  return env;
@@ -102,9 +110,10 @@ export function discoverNewestSessionId(opts = {}) {
102
110
  *
103
111
  * Precedence:
104
112
  * 1. explicit value (the `--session` flag)
105
- * 2. `$CLAUDE_SESSION_ID` env
106
- * 3. newest Claude Code transcript (the live session)
107
- * 4. literal `"default"`
113
+ * 2. `$CLAUDE_CODE_SESSION_ID` env (the var Claude Code actually exports)
114
+ * 3. `$CLAUDE_SESSION_ID` env (legacy fallback)
115
+ * 4. newest Claude Code transcript (the live session)
116
+ * 5. literal `"default"`
108
117
  *
109
118
  * The WRITE path keeps `resolveSessionId`: it always has
110
119
  * `event.session_id`, so it never reaches the discovery tier, and a
@@ -113,6 +122,9 @@ export function discoverNewestSessionId(opts = {}) {
113
122
  export function resolveReadSessionId(explicit, opts = {}) {
114
123
  if (typeof explicit === "string" && explicit.length > 0)
115
124
  return explicit;
125
+ const envCode = process.env.CLAUDE_CODE_SESSION_ID;
126
+ if (typeof envCode === "string" && envCode.length > 0)
127
+ return envCode;
116
128
  const env = process.env.CLAUDE_SESSION_ID;
117
129
  if (typeof env === "string" && env.length > 0)
118
130
  return env;
@@ -1 +1 @@
1
- {"version":3,"file":"session-id.js","sourceRoot":"","sources":["../../src/runtime/session-id.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-id.js","sourceRoot":"","sources":["../../src/runtime/session-id.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lannguyensi/harness",
3
- "version": "0.30.1",
3
+ "version": "0.32.0",
4
4
  "description": "Declarative control plane for agent harnesses — one YAML for grounding, tools, memory, and hooks.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/LanNguyenSi/harness",
@@ -27,6 +27,7 @@
27
27
  "types": "./dist/index.d.ts",
28
28
  "files": [
29
29
  "dist",
30
+ "scripts/runtime-reality-docker-probe.mjs",
30
31
  "README.md",
31
32
  "CHANGELOG.md",
32
33
  "LICENSE"
@@ -43,6 +44,7 @@
43
44
  },
44
45
  "dependencies": {
45
46
  "@inquirer/prompts": "^8.4.3",
47
+ "@lannguyensi/runtime-reality-checker": "^0.2.0",
46
48
  "chalk": "^5.3.0",
47
49
  "commander": "^12.1.0",
48
50
  "diff": "^9.0.0",
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // Docker probe for the runtime-reality PreToolUse hook.
3
+ //
4
+ // Contract (see `harness pack hook runtime-reality`): print a JSON array
5
+ // of ActualProcessState `{ name, running, startup_mode, port }` on stdout,
6
+ // one entry per running/known container. The hook spawns this via
7
+ // RUNTIME_REALITY_PROBE_CMD, parses stdout, and compares it against the
8
+ // keyword's expectations file. A non-zero exit or non-JSON output is
9
+ // treated by the hook as "probe failed" (fail-open unless
10
+ // RUNTIME_REALITY_PROBE_FAIL_BLOCK=1) — so this script must either emit a
11
+ // valid array or exit non-zero, never print partial garbage.
12
+ //
13
+ // Host-coupling lives here on purpose: the agent-grounding package stays
14
+ // probe-agnostic; this is the harness-side concrete probe. Copy/adapt it
15
+ // for systemd or pm2 hosts.
16
+
17
+ import { execFileSync } from "node:child_process";
18
+
19
+ /** Pull the first published host port out of a `docker ps` Ports string,
20
+ * e.g. "0.0.0.0:3001->3001/tcp, :::3001->3001/tcp" -> 3001. Returns
21
+ * undefined when the container publishes no host port. */
22
+ function firstHostPort(ports) {
23
+ if (typeof ports !== "string") return undefined;
24
+ const m = ports.match(/:(\d+)->/);
25
+ if (!m) return undefined;
26
+ const n = Number.parseInt(m[1], 10);
27
+ return Number.isFinite(n) ? n : undefined;
28
+ }
29
+
30
+ function main() {
31
+ let raw;
32
+ try {
33
+ raw = execFileSync("docker", ["ps", "--format", "{{json .}}"], {
34
+ encoding: "utf8",
35
+ timeout: 8000,
36
+ maxBuffer: 4 * 1024 * 1024,
37
+ });
38
+ } catch (err) {
39
+ process.stderr.write(`docker-probe: docker ps failed: ${String(err)}\n`);
40
+ process.exit(1);
41
+ }
42
+
43
+ const states = [];
44
+ for (const line of raw.split("\n")) {
45
+ const trimmed = line.trim();
46
+ if (!trimmed) continue;
47
+ let row;
48
+ try {
49
+ row = JSON.parse(trimmed);
50
+ } catch {
51
+ // A single malformed line shouldn't sink the whole probe; skip it.
52
+ continue;
53
+ }
54
+ // `docker ps` may join multiple names with commas; the first is the
55
+ // canonical container name expectations are written against.
56
+ const name = String(row.Names ?? "").split(",")[0].trim();
57
+ if (!name) continue;
58
+ const state = {
59
+ name,
60
+ running: row.State === "running",
61
+ startup_mode: "docker",
62
+ };
63
+ const port = firstHostPort(row.Ports);
64
+ if (port !== undefined) state.port = port;
65
+ states.push(state);
66
+ }
67
+
68
+ process.stdout.write(JSON.stringify(states) + "\n");
69
+ }
70
+
71
+ main();