projecta-rrr 1.22.0 → 1.22.2
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/CHANGELOG.md +72 -0
- package/hooks/model-router.js +5 -2
- package/package.json +1 -1
- package/rrr/lib/install-hooks-wiring.js +4 -1
- package/scripts/register-mcp.js +19 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,78 @@ All notable changes to RRR will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [1.22.2] - 2026-04-19
|
|
8
|
+
|
|
9
|
+
**Patch: dynamic routing now actually fires in Claude Code (Opus 4.7+).**
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **Phase 83 model-router matcher**: Claude Code (Opus 4.7+) emits subagent dispatches as `tool_name: "Agent"`, not `"Task"`. v1.22.0/.1 hardcoded `"Task"` in both:
|
|
13
|
+
1. `hooks/model-router.js` internal gate (`if (toolName !== "Task") return emitAllow()`)
|
|
14
|
+
2. `rrr/lib/install-hooks-wiring.js` matcher (`{ matcher: "Task", ... }`)
|
|
15
|
+
Result: hook never fired for any Agent dispatch in Opus 4.7+ sessions, so dynamic routing was a no-op even with `settings.rrr.model_router: "dynamic"`.
|
|
16
|
+
|
|
17
|
+
v1.22.2 accepts both `Task` and `Agent`. Live UAT verified end-to-end:
|
|
18
|
+
```
|
|
19
|
+
{"ts":"2026-04-19T05:46:21Z","event":"dispatch","tool_name":"Agent",
|
|
20
|
+
"agent_name":"rrr-explore","tier":"haiku","reason":"dispatch"}
|
|
21
|
+
```
|
|
22
|
+
Token usage on rrr-explore call: ~10.4k (haiku) vs ~13.2k baseline (general-purpose, sonnet/inherit) — ~21% reduction from tier downgrade alone, on a single dispatch.
|
|
23
|
+
|
|
24
|
+
### Verified in UAT (v1.21 hosted webhook + Phase 80 App-level)
|
|
25
|
+
- **Hosted Fly app redeployed** with v1.22 code (was running pre-Phase-80 image — `/webhooks/github-app` returned 404 until `fly deploy`).
|
|
26
|
+
- **Phase 80 webhook end-to-end**:
|
|
27
|
+
- Ping: 200 OK
|
|
28
|
+
- Valid HMAC push (with `installation_id` lookup): 202 + `{queued:true, job_id}`
|
|
29
|
+
- Replay (same delivery_id): 200 + `{duplicate:true}` ✓ dedup
|
|
30
|
+
- Bad signature: 401 `signature_invalid`
|
|
31
|
+
- Non-default branch: 200 `{skipped:"non-default-branch"}`
|
|
32
|
+
- Unindexed repo (NULL `github_repo_id`): 200 `{skipped:"unindexed-repo"}`
|
|
33
|
+
- **Neon migration 014 applied**: `installations` table populated with 5 rows from existing `repos.installation_id` data.
|
|
34
|
+
- **`installations` table**: 5 rows under `team_id=pa-ai-team`. Largest installation: 125117864 (29 repos).
|
|
35
|
+
|
|
36
|
+
### Known followups
|
|
37
|
+
- **Backfill `repos.github_repo_id`** for all 62 repos via `gh api /repos/<full_name>`. Without this, App-level webhook deliveries hit "unindexed-repo" skip path. Operator-actionable.
|
|
38
|
+
- **Postinstall `--hud-only`** still requires separate `npx projecta-rrr install` for full provision. v1.22.x followup.
|
|
39
|
+
- **`tool-disallow` subagent exemption heuristic** uses `input.agent_name` — this field is NOT present in real Claude Code PreToolUse payload (UAT-verified payload schema has `tool_name`, `tool_input`, `session_id`, `transcript_path`, `cwd`, `permission_mode`, `tool_use_id`). Subagent context detection needs different mechanism.
|
|
40
|
+
|
|
41
|
+
## [1.22.1] - 2026-04-19
|
|
42
|
+
|
|
43
|
+
**Patch: fixes v1.22.0 fresh install regression.**
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- **`scripts/register-mcp.js` postinstall** no longer breaks `npm install -g projecta-rrr`. Two fixes:
|
|
47
|
+
1. Fallback path corrected — looks at `<pkg>/rrr/mcp-server/index.js` (npm layout) before `<pkg>/mcp-server/index.js` (legacy). v1.22.0 only checked the legacy path, which doesnt exist in the npm tarball, causing the postinstall to exit 1 and abort the entire install.
|
|
48
|
+
2. Registration failures are now advisory (`process.exit(0)` + warn) instead of fatal (`process.exit(1)`). Re-run `node scripts/register-mcp.js` or `/rrr:doctor` after install if needed.
|
|
49
|
+
|
|
50
|
+
Surfaced via UAT: fresh `HOME=tmp npm install -g projecta-rrr@1.22.0 --prefix=tmp` aborted before `node_modules/projecta-rrr` landed. v1.22.1 installs cleanly.
|
|
51
|
+
|
|
52
|
+
### Verified in UAT
|
|
53
|
+
- **Hosted MCP latency** (5 samples): 108–142ms (median ~128ms) on /health.
|
|
54
|
+
- **Model-router PreToolUse latency** (10 samples): 30–40ms per Task spawn.
|
|
55
|
+
- **Dynamic routing (Phase 83)** static = no rewrite (v1.21 bit-for-bit); dynamic = `rrr-explore→haiku` rewrite + telemetry row.
|
|
56
|
+
- **Stage-aware routing**: `verify-work` + `rrr-verifier` = sonnet; `plan-phase` execution + `general-purpose` = inherit.
|
|
57
|
+
- **Phase 84 escalation**: `rrr-debugger` iter-3 with state at `<project>/.rrr/state/debug-session.json` → opus + telemetry `reason:"debugger_iter_escalate", retry_count:3, prior_tier:"inherit"`.
|
|
58
|
+
- **Phase 85 tool-disallow**: BLOCKs main-thread Read with exit 2 when flag on; allows when flag off; respects `RRR_TOK_DISALLOW=off` kill switch.
|
|
59
|
+
- **Phase 85 edit-batching-nudge**: 2nd Edit within 30s → "edited foo.js 2× in ~30s" advisory; 3rd silent (lastNudgeMs prevents spam); state at `<project>/.planning/.cache/edit-batching-state.json`.
|
|
60
|
+
- **PUSH-POLICY**: 10/10 RRR command skills include `git push`/`auto-push` reference.
|
|
61
|
+
- **auto-push helper**: graceful failure on no-remote ("non-fatal — your work is committed locally"); `auto_push:false` → `{ran:false, skipped:"settings_disabled"}`.
|
|
62
|
+
- **measure-token-delta + measure-opus-rate**: correctly return INSUFFICIENT_DATA verdict on partial telemetry (13 dispatches, need ≥100). Methodology + min_required documented in JSON output.
|
|
63
|
+
- **/rrr:savings**: reads `<project>/.planning/observations*.jsonl` + `~/.rrr/telemetry/escalations.jsonl`.
|
|
64
|
+
- **doctor**: clean on populated install ("Found 1 command root(s) ✅ active"); reports 0 + SAFE MODE on hud-only install (expected — full provision needs `npx projecta-rrr install`).
|
|
65
|
+
- **Fresh install (v1.22.1)**: `HOME=tmp npm install -g projecta-rrr@1.22.1 --prefix=tmp` succeeds, package lands in node_modules.
|
|
66
|
+
|
|
67
|
+
### Known UAT findings (followups, not blockers)
|
|
68
|
+
- **edit-batching-nudge state location**: `<project>/.planning/.cache/edit-batching-state.json`. Hook is silent if CWD has no `.planning/` directory — by design (cant infer project context). Document in onboarding.
|
|
69
|
+
- **/rrr:savings input path**: project-root `.planning/observations*.jsonl`, NOT HOME. Reports 0 if v1.19 observation logger never ran in current project.
|
|
70
|
+
- **`tool-disallow` subagent exemption**: heuristic uses `input.agent_name` field; needs validation against real Claude Code PreToolUse payload schema (Phase 85 followup).
|
|
71
|
+
- **Postinstall `--hud-only`**: full command/agent/script provision requires separate `npx projecta-rrr install`. Consider auto-bootstrapping in v1.22.x.
|
|
72
|
+
- **`/metrics/freshness`** hosted endpoint returns 404 — by design; HUD reads freshness via `semantic_search` response payload.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Known limitations (followups)
|
|
76
|
+
- `tool-disallow` subagent exemption uses `input.agent_name` heuristic; may need updating when Claude Code PreToolUse payload schema is fully nailed down.
|
|
77
|
+
- Escalation requires per-project state file at `<project>/.rrr/state/debug-session.json` (not HOME). Increments are wired in v1.22 but operator should verify their /rrr:debug session writes to CWD.
|
|
78
|
+
|
|
7
79
|
## [1.22.0] - 2026-04-19
|
|
8
80
|
|
|
9
81
|
**Webhook Live Reindex + Dynamic Routing + Token Diet v2.**
|
package/hooks/model-router.js
CHANGED
|
@@ -85,9 +85,12 @@ function main() {
|
|
|
85
85
|
try { input = JSON.parse(raw); }
|
|
86
86
|
catch (_e) { return emitAllow('router: stdin not JSON'); }
|
|
87
87
|
|
|
88
|
-
// Only act on the
|
|
88
|
+
// Only act on the subagent-dispatch tool — every other tool is pass-through.
|
|
89
|
+
// Claude Code uses either "Task" (Anthropic API name, most builds) or "Agent"
|
|
90
|
+
// (Opus 4.7+ builds) for subagent dispatch. Accept both — confirmed via
|
|
91
|
+
// v1.22.2 UAT live-session capture (/tmp/uat-hook-log.jsonl).
|
|
89
92
|
const toolName = input.tool_name;
|
|
90
|
-
if (toolName !== 'Task') return emitAllow();
|
|
93
|
+
if (toolName !== 'Task' && toolName !== 'Agent') return emitAllow();
|
|
91
94
|
|
|
92
95
|
const toolInput = (input.tool_input && typeof input.tool_input === 'object') ? input.tool_input : {};
|
|
93
96
|
|
package/package.json
CHANGED
|
@@ -210,7 +210,10 @@ function wireToolRedirect({ repoHooksDir, userHooksDir, userSettingsPath, dryRun
|
|
|
210
210
|
*/
|
|
211
211
|
function buildModelRouterEntry(hookAbsPath) {
|
|
212
212
|
return {
|
|
213
|
-
|
|
213
|
+
// Claude Code uses either "Task" (most builds) or "Agent" (Opus 4.7+) as
|
|
214
|
+
// the subagent dispatch tool name. Match both via regex alternation —
|
|
215
|
+
// confirmed via v1.22.2 UAT live-session capture.
|
|
216
|
+
matcher: 'Task|Agent',
|
|
214
217
|
hooks: [
|
|
215
218
|
{ type: 'command', command: `node ${hookAbsPath}` },
|
|
216
219
|
],
|
package/scripts/register-mcp.js
CHANGED
|
@@ -41,8 +41,14 @@ function getMCPServerPath() {
|
|
|
41
41
|
return installedPath;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
// Fallback to relative path
|
|
45
|
-
//
|
|
44
|
+
// Fallback to package-relative path. Try both layouts: published npm package
|
|
45
|
+
// ships the server at <pkg>/rrr/mcp-server/index.js, but the dev repo also
|
|
46
|
+
// has a top-level <pkg>/mcp-server (legacy v1.17 layout).
|
|
47
|
+
// scripts/register-mcp.js → __dirname is <pkg>/scripts
|
|
48
|
+
const npmLayout = path.resolve(__dirname, '..', 'rrr', 'mcp-server', 'index.js');
|
|
49
|
+
if (fs.existsSync(npmLayout)) {
|
|
50
|
+
return npmLayout;
|
|
51
|
+
}
|
|
46
52
|
return path.resolve(__dirname, '..', 'mcp-server', 'index.js');
|
|
47
53
|
}
|
|
48
54
|
|
|
@@ -274,13 +280,20 @@ if (require.main === module) {
|
|
|
274
280
|
console.log(`Registered ${MCP_SERVER_ID} with Claude Code (method: ${result.method})`);
|
|
275
281
|
process.exit(0);
|
|
276
282
|
} else {
|
|
277
|
-
|
|
278
|
-
|
|
283
|
+
// Advisory only — don't fail npm postinstall on registration failure.
|
|
284
|
+
// The MCP server can be registered later via /rrr:doctor or by re-running
|
|
285
|
+
// `node scripts/register-mcp.js`. v1.22.0 shipped exit(1) here, which
|
|
286
|
+
// broke fresh `npm install -g projecta-rrr` (the package never landed
|
|
287
|
+
// because postinstall errored). v1.22.1 makes this advisory.
|
|
288
|
+
console.warn(`[mcp] Registration skipped: ${result.error}`);
|
|
289
|
+
console.warn(`[mcp] Run 'node scripts/register-mcp.js' or '/rrr:doctor' after install to retry.`);
|
|
290
|
+
process.exit(0);
|
|
279
291
|
}
|
|
280
292
|
})
|
|
281
293
|
.catch(err => {
|
|
282
|
-
console.
|
|
283
|
-
|
|
294
|
+
console.warn(`[mcp] Registration error: ${err.message}`);
|
|
295
|
+
console.warn(`[mcp] Continuing — re-run registration manually.`);
|
|
296
|
+
process.exit(0);
|
|
284
297
|
});
|
|
285
298
|
}
|
|
286
299
|
}
|