@tech-leads-club/harness-toolkit 0.10.6 → 0.11.1

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 (63) hide show
  1. package/README.md +6 -4
  2. package/bin/tlc-cli.ts +3 -1
  3. package/capabilities/catalog.json +18 -1
  4. package/dist/compact-before.mjs +79 -78
  5. package/dist/doctor.mjs +80 -79
  6. package/dist/init-project.mjs +83 -82
  7. package/dist/install-runtime.mjs +83 -82
  8. package/dist/lessons-cli.mjs +80 -79
  9. package/dist/obs-cli.mjs +83 -82
  10. package/dist/prompt-submit.mjs +79 -78
  11. package/dist/refresh-model-prices.mjs +80 -79
  12. package/dist/response-after.mjs +80 -79
  13. package/dist/run.mjs +79 -78
  14. package/dist/session-end.mjs +85 -84
  15. package/dist/session-start.mjs +87 -86
  16. package/dist/shim.mjs +81 -80
  17. package/dist/ship-gate.mjs +79 -78
  18. package/dist/stop.mjs +86 -85
  19. package/dist/subagent-start.mjs +79 -78
  20. package/dist/subagent-stop.mjs +80 -79
  21. package/dist/support.mjs +84 -83
  22. package/dist/tlc-cli.mjs +102 -101
  23. package/dist/tool-after.mjs +80 -79
  24. package/dist/tool-before.mjs +82 -81
  25. package/dist/tool-failure.mjs +79 -78
  26. package/dist/uninstall-runtime.mjs +3 -3
  27. package/docs/architecture.md +16 -3
  28. package/docs/concepts.md +11 -0
  29. package/docs/log.md +10 -0
  30. package/docs/providers/claude-code.md +42 -21
  31. package/docs/providers/cursor.md +23 -7
  32. package/docs/providers/index.md +3 -1
  33. package/docs/troubleshooting.md +1 -0
  34. package/package.json +1 -1
  35. package/schema.json +12 -0
  36. package/skills/harness-init/references/capabilities.md +1 -0
  37. package/src/contracts/capabilities.ts +8 -1
  38. package/src/contracts/decision.ts +2 -1
  39. package/src/core/core.facade.ts +6 -0
  40. package/src/core/floor/floor.catalog.ts +5 -0
  41. package/src/core/floor/floor.paths.ts +17 -1
  42. package/src/core/floor/floor.policy-surface.ts +26 -9
  43. package/src/core/floor/floor.service.ts +37 -5
  44. package/src/core/policy/policy.defaults.ts +3 -0
  45. package/src/core/policy/policy.loader.ts +1 -0
  46. package/src/core/policy/policy.types.ts +4 -0
  47. package/src/core/secret-scan/secret-scan.service.ts +96 -0
  48. package/src/core/secret-scan/secret-scan.store.ts +56 -0
  49. package/src/entrypoints/run.ts +3 -1
  50. package/src/entrypoints/tool-after.ts +20 -0
  51. package/src/entrypoints/tool-before.ts +1 -0
  52. package/src/providers/claude/claude.capabilities.ts +3 -1
  53. package/src/providers/claude/claude.inbound.ts +37 -22
  54. package/src/providers/claude/claude.outbound.ts +4 -0
  55. package/src/providers/claude/claude.wiring.ts +4 -0
  56. package/src/providers/claude/index.ts +2 -1
  57. package/src/providers/cursor/cursor.capabilities.ts +3 -1
  58. package/src/providers/cursor/cursor.inbound.ts +1 -1
  59. package/src/providers/cursor/cursor.outbound.ts +9 -0
  60. package/src/providers/cursor/cursor.wiring.ts +9 -1
  61. package/src/providers/cursor/index.ts +2 -1
  62. package/src/providers/provider.degrade.ts +19 -0
  63. package/src/providers/provider.port.ts +1 -0
package/README.md CHANGED
@@ -39,7 +39,7 @@
39
39
  <p align="center">
40
40
  Hooks fire on the editor's own events. The harness answers each one with a decision — <b>allow</b>, <b>ask</b>,
41
41
  <b>deny</b>, or text injected into the turn — and writes a record of what it decided and why.
42
- <b>7 floor rules</b> no configuration can reach, <b>3 always-on checks</b>, and <b>24 rails</b> you choose.
42
+ <b>8 floor rules</b> no configuration can reach, <b>3 always-on checks</b>, and <b>24 rails</b> you choose.
43
43
  </p>
44
44
 
45
45
  - **[Everything it validates](#everything-it-validates)** — the whole list, one row per check
@@ -90,11 +90,11 @@ Three tiers, and which tier a check is in decides whether you can turn it off.
90
90
 
91
91
  | Tier | Count | Configurable | Runs |
92
92
  |------|-------|--------------|------|
93
- | [Floor](#tier-1--the-floor-no-configuration-reaches-it) | 7 rules | Never | Before any policy is loaded, on every tool call, shell command and read |
93
+ | [Floor](#tier-1--the-floor-no-configuration-reaches-it) | 8 rules | Never | Before any policy is loaded, on every tool call, shell command and read |
94
94
  | [Always on](#tier-2--always-on-no-switch) | 3 checks | Never | After the floor, on every acting event |
95
- | [Rails](#tier-3--the-rails-you-choose) | 24 capabilities | Each one, individually | Where the table says |
95
+ | [Rails](#tier-3--the-rails-you-choose) | 25 capabilities | Each one, individually | Where the table says |
96
96
 
97
- Nothing else runs. If a message on your screen is not from one of the thirty-four rows below, it is not the
97
+ Nothing else runs. If a message on your screen is not from one of the thirty-six rows below, it is not the
98
98
  harness.
99
99
 
100
100
  ### Tier 1 — the floor, no configuration reaches it
@@ -113,6 +113,7 @@ prints `rule=<name>`, and the name is the first column here.
113
113
  | `machine-control` | `shutdown`, `reboot`, `halt`, `poweroff` | — |
114
114
  | `unprovable-execution` | a program fetched over the network and handed to a shell — piped, process-substituted, or inside a shell's `-c`/`eval` substitution. The gate cannot read what would run | a fetch with no shell downstream, and a shell fed a local file the gate can read |
115
115
  | `policy-surface-write` | every route an agent has to harness policy and state — a shell redirect, an interpreter, a heredoc program, or a write tool — in the project and under the runtime home, plus the mutating `tlc harness` subcommands from inside a session | reading them with a proven reader (`cat`, `head`, `grep`, `jq`, `ls`, `stat`, `test`), and `tlc harness handoff` for the handoff state |
116
+ | `wiring-tamper` | a shell redirect, in-place edit, or delete into a registered provider's wiring target — the document its own editor reads to register the harness's hooks — and a direct `Edit`/`Write`/`MultiEdit` tool call against the same path — overwriting it silences every hook the harness has for that host | reading the same path with a proven reader or a read tool |
116
117
 
117
118
  <!-- /generated -->
118
119
 
@@ -167,6 +168,7 @@ trade-off when you ran the init wizard. `configPath` is the key in `.tlc/harness
167
168
  | **Plan gate (declared scope vs diff)**<br>`planGate.enabled` · off | Checks the files the turn changed against the scope it declared, and against any stated deviation. | `response.after`<br>`stop` | `block-stop` | tlc harness handoff — plan_paths, plan_at and plan_deviations |
168
169
  | **Observation mode (measure a rail with its rule off)**<br>`observe.enabled` · off | Runs a rail's checker while that rail is not enforcing, and records the reading without acting on it. | `stop`<br>`session.end` | `record` | tlc harness obs report — the observation readings, held apart from the refusal counters so those stay honest |
169
170
  | **Operator rules (your trigger, your proof)**<br>`rules.enabled` · off | Reads the rules you declare in markdown and enforces them: on this trigger, this must have happened. | `tool.before`<br>`stop` | `deny` | tlc harness doctor — each active rule, its tier, and any proof kind never observed here |
171
+ | **Secret redaction (tool/shell output)**<br>`secrets.redactOutput` · **on** | Scans a tool's or shell command's output for a secret-shaped signature or high-entropy span and masks it. | `tool.after` | `context` | the masked placeholder itself, in the tool output — `[REDACTED:<kind>:<hash>]` |
170
172
 
171
173
  <!-- /generated -->
172
174
 
package/bin/tlc-cli.ts CHANGED
@@ -1332,7 +1332,8 @@ export const TEST_ENV_IMPORT = ["--import", "./tools/test-env.mjs"];
1332
1332
  * commit is one somebody looks at. Lowering it is the point; raising it needs an argument in the diff
1333
1333
  * ([/decisions/ad-102.md](/decisions/ad-102.md)).
1334
1334
  */
1335
- export const KNIP_EXPORTS_CEILING = 76;
1335
+ // why: raised from 76 to 80 — knip cannot trace render-provider-docs.ts's dynamic import() of each provider's inbound module, so EVENT_KIND_BY_HOOK (both adapters) and Claude's PRE_TOOL_USE_FAN_OUT/POST_TOOL_USE_FAN_OUT report as unused though the drift gate depends on them.
1336
+ export const KNIP_EXPORTS_CEILING = 80;
1336
1337
 
1337
1338
  export function buildTestSteps(): TestStep[] {
1338
1339
  return [
@@ -1378,6 +1379,7 @@ export function buildTestSteps(): TestStep[] {
1378
1379
  // for an unrelated reason ([/decisions/ad-081.md](/decisions/ad-081.md)).
1379
1380
  { label: "check-manifest", bin: "node", args: ["tools/dev/check-manifest.ts"] },
1380
1381
  { label: "capabilities in sync", bin: "node", args: ["tools/dev/render-capabilities.ts", "--check"] },
1382
+ { label: "provider docs in sync", bin: "node", args: ["tools/dev/render-provider-docs.ts", "--check"] },
1381
1383
  { label: "changelog in sync", bin: "node", args: ["tools/dev/render-changelog.ts", "--check"] },
1382
1384
  // why: the OKF bundle's log is a reserved file that cannot be retired, and hand-maintaining it drifted to 19
1383
1385
  // of 66 records before anyone noticed ([/decisions/ad-067.md](/decisions/ad-067.md)).
@@ -1,5 +1,5 @@
1
1
  {
2
- "catalogVersion": 14,
2
+ "catalogVersion": 15,
3
3
  "capabilities": [
4
4
  {
5
5
  "id": "grind",
@@ -430,6 +430,23 @@
430
430
  "verdict": "deny",
431
431
  "inspect": "tlc harness doctor \u2014 each active rule, its tier, and any proof kind never observed here",
432
432
  "asks": []
433
+ },
434
+ {
435
+ "id": "secretRedaction",
436
+ "configPath": "secrets.redactOutput",
437
+ "title": "Secret redaction (tool/shell output)",
438
+ "summary": "Scans a tool's or shell command's output for a secret-shaped signature or high-entropy span and masks it.",
439
+ "benefit": "Masks an AWS access key, GitHub/Slack/Stripe token, PEM private-key block, JWT, or an unlabelled high-entropy string with a deterministic placeholder \u2014 the same value always yields the same placeholder within a session \u2014 instead of blocking the command that produced it.",
440
+ "tradeOff": "A synchronous regex plus Shannon-entropy pass on every tool/shell output; a high-diversity non-secret string can be masked as a false positive, and an unlabelled low-entropy secret can be missed. On a host with no rewrite mechanism for the firing event, the mask degrades to a context warning instead \u2014 the model is told a secret was masked but the raw value already reached it.",
441
+ "defaultOn": true,
442
+ "sinceCatalogVersion": 15,
443
+ "fires": [
444
+ "tool.after"
445
+ ],
446
+ "verdict": "context",
447
+ "inspect": "the masked placeholder itself, in the tool output \u2014 `[REDACTED:<kind>:<hash>]`",
448
+ "asks": [],
449
+ "recommend": "on"
433
450
  }
434
451
  ]
435
452
  }