@agent_forge/forge-dsh 1.61.3 → 1.62.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.
package/README.md CHANGED
@@ -11,6 +11,12 @@ the forge binary — the plugin itself has **zero runtime dependencies**.
11
11
 
12
12
  ## How it works
13
13
 
14
+ > The mapping table below and the fail-open contract at the end of this README
15
+ > are the **two-sided bridge contract**, mirrored machine-readably in
16
+ > [`contract.json`](./contract.json) and enforced by forge's compat snapshot
17
+ > (surface `bridges`). Change all three together: `contract.json`, this README,
18
+ > and the tests on both sides.
19
+
14
20
  | DSH interception point | forge hook event | A forge block becomes |
15
21
  |---|---|---|
16
22
  | `tools/pre-execute` | `PreToolUse` | `{kind:'deny', reason}` |
package/lib/index.js CHANGED
@@ -135,8 +135,8 @@ function apply(ctx, config = {}) {
135
135
  return turnStoppingOutcome(outcome, agent);
136
136
  }), "forge: turn-stopping");
137
137
 
138
- // /forge-status — wired groups + recent runs (the only place fail-open
139
- // infrastructure errors surface without debug:true).
138
+ // /forge-status — wired groups + verdict summary + recent runs (the only
139
+ // place fail-open infrastructure errors surface without debug:true).
140
140
  const commands = ctx.get("commands");
141
141
  if (commands !== undefined) {
142
142
  ctx.effect(() => commands.register({
@@ -146,6 +146,21 @@ function apply(ctx, config = {}) {
146
146
  const groups = Object.entries(spec)
147
147
  .map(([event, gs]) => ` ${event}: ${gs.flatMap((g) => g.hooks.map((h) => h.command.replace("forge hook ", ""))).join(", ")}`)
148
148
  .join("\n");
149
+ // Verdict summary over the whole ring buffer (50 runs): the at-a-glance
150
+ // health line — how many runs forge blocked, and how many hook runs
151
+ // FAILED OPEN (infra errors, e.g. timeout) and thus lost that run's
152
+ // feedback. A rising fail-open count on a big project means timeoutMs
153
+ // needs raising.
154
+ const summary = recentRuns.reduce(
155
+ (acc, r) => {
156
+ acc.runs += 1;
157
+ if (r.blocked) acc.blocked += 1;
158
+ if (r.errors.length > 0) acc.failOpen += 1;
159
+ acc.contexts += r.contexts;
160
+ return acc;
161
+ },
162
+ { runs: 0, blocked: 0, failOpen: 0, contexts: 0 },
163
+ );
149
164
  const runs = recentRuns.length === 0
150
165
  ? " (no hook runs yet)"
151
166
  : recentRuns.slice(-10).map((r) => {
@@ -157,7 +172,7 @@ function apply(ctx, config = {}) {
157
172
  }).join("\n");
158
173
  return {
159
174
  kind: "success",
160
- text: `# Forge quality gates\n\nforgeBin: ${opts.forgeBin} timeoutMs: ${opts.timeoutMs}\n\n## Wired groups\n${groups}\n\n## Recent runs (last 10)\n${runs}`,
175
+ text: `# Forge quality gates\n\nforgeBin: ${opts.forgeBin} timeoutMs: ${opts.timeoutMs}\n\n## Wired groups\n${groups}\n\n## Verdict summary (last ${recentRuns.length} runs)\n runs=${summary.runs} blocked=${summary.blocked} fail-open=${summary.failOpen} contexts=${summary.contexts}\n\n## Recent runs (last 10)\n${runs}`,
161
176
  };
162
177
  },
163
178
  }), "forge: status command");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent_forge/forge-dsh",
3
- "version": "1.61.3",
3
+ "version": "1.62.0",
4
4
  "description": "Forge quality gates for DeepSeek Harness (dsh): task gates, read-before-edit, bash hazard interception and quality scoring, driven by the forge CLI through DSH's typed interception points.",
5
5
  "repository": {
6
6
  "type": "git",