feat(lanes): widen stage auto-detection, fix terminal UTF-8 decode
Add detect rules for plan/review/gate/tests/intake nodes (Agent subagent matches, TaskCreate, broader test-runner regex) so more of the pipeline lights up without an explicit ccam stage call, and fix a review/gate detect overlap where senior-gate-reviewer also matched the generic reviewer pattern. Also fix TerminalView's TextDecoder dropping the `stream: true` flag, which corrupted multi-byte UTF-8 chars split across WebSocket frames.
This commit is contained in:
@@ -76,7 +76,13 @@ export function TerminalView({ runId, wsBaseUrl }: TerminalViewProps) {
|
||||
};
|
||||
sock.onmessage = (event) => {
|
||||
const isArrayBuffer = Object.prototype.toString.call(event.data) === "[object ArrayBuffer]";
|
||||
const data = isArrayBuffer ? decoder.decode(event.data as ArrayBuffer) : event.data;
|
||||
// `stream: true` carries a UTF-8 multi-byte char's trailing bytes over
|
||||
// to the next decode() call when a PTY chunk splits mid-character —
|
||||
// without it, a Vietnamese/accented char split across two WS frames
|
||||
// decodes to garbage on both sides (U+FFFD or stray bytes).
|
||||
const data = isArrayBuffer
|
||||
? decoder.decode(event.data as ArrayBuffer, { stream: true })
|
||||
: event.data;
|
||||
if (typeof data === "string") {
|
||||
// A JSON control frame is the only thing that starts with `{"type"`.
|
||||
if (data.startsWith('{"type"')) {
|
||||
|
||||
+19
-18
@@ -780,12 +780,12 @@ a `detect` array on each node. The built-in `default.json`
|
||||
|
||||
| Node | Detect rules |
|
||||
|---|---|
|
||||
| `intake` | none — see below |
|
||||
| `plan` | `Skill` matching `brainstorming\|writing-plans`; `Write` matching `docs/.*plan.*\.md` |
|
||||
| `implement` | `Edit` (any); `Write` to any path NOT under a `docs/` directory (`^(?!.*(?:^\|/)docs/)`) |
|
||||
| `tests` | `Bash` matching `\b(npm (run )?test\|pytest\|vitest\|jest\|go test\|cargo test\|node\s+--test)\b` |
|
||||
| `review` | `Skill` matching `code-review\|requesting-code-review`; `Bash` matching `\bgh\b[^;&\|]*\bpr diff\b` |
|
||||
| `gate` | none — see below |
|
||||
| `intake` | `Agent` matching subagent `Explore` — a lane sitting at nothing else yet, but already exploring, shows *something* instead of idle |
|
||||
| `plan` | `Skill` matching `brainstorming\|writing-plans`; `Write` matching `docs/.*plan.*\.md`; `Agent` matching `Plan\|Software Architect\|Backend Architect\|UX Architect`; `TaskCreate` (any) |
|
||||
| `implement` | `Skill` matching `executing-plans\|subagent-driven-development\|test-driven-development`; `Edit` (any); `Write` to any path NOT under a `docs/` directory (`^(?!.*(?:^\|/)docs/)`) |
|
||||
| `tests` | `Bash` matching `\b(npm (run )?test\|pytest\|vitest\|jest\|go test\|cargo test\|node\s+--test\|rspec\|phpunit\|dotnet test\|mvn test\|gradle test)\b`; `Agent` matching `Test Results Analyzer\|API Tester\|Performance Benchmarker` |
|
||||
| `review` | `Skill` matching `code-review\|requesting-code-review\|receiving-code-review`; `Bash` matching `\bgh\b[^;&\|]*\bpr diff\b`; `Agent` matching a name containing `reviewer`/`Reviewer` (excluding `senior-gate-reviewer`, a lookbehind), `Evidence Collector`, or `Accessibility Auditor` |
|
||||
| `gate` | `Skill` matching `verification-before-completion`; `Agent` matching `senior-gate-reviewer\|Reality Checker` — entering the gate, never its verdict |
|
||||
| `ship` | `Bash` matching a `git push` **invocation** — `git`, then option groups, then `push` as the first non-flag token — or `gh … pr create` |
|
||||
| `done` | none — see below |
|
||||
|
||||
@@ -820,14 +820,14 @@ actually runs:
|
||||
|
||||
| Node | Detect rules |
|
||||
|---|---|
|
||||
| `intake` | `Skill` matching `brainstorming`; `Bash` matching `ccam … feature activate` |
|
||||
| `plan` | `Skill` matching `writing-plans`; `Write` matching `docs/superpowers/specs/lane-.*\.md` |
|
||||
| `intake` | `Skill` matching `brainstorming`; `Bash` matching `ccam … feature activate`; `Agent` matching subagent `Explore` |
|
||||
| `plan` | `Skill` matching `writing-plans`; `Write` matching `docs/superpowers/specs/lane-.*\.md`; `Agent` matching `Plan\|Software Architect`; `TaskCreate` (any) |
|
||||
| `implementing` | `Skill` matching `test-driven-development\|executing-plans\|subagent-driven-development\|systematic-debugging`; `Edit`/`Write` to any path NOT under `docs/superpowers/specs/` (resp. not under `docs/`) |
|
||||
| `gates` | `Bash` matching `ccam … hook ci-gate` or `ccam … sync-base --check` |
|
||||
| `e2e-feature` | `Bash` matching `ccam … up --qc` or `ccam … hook e2e` |
|
||||
| `review` | `Skill` matching `code-review\|requesting-code-review\|receiving-code-review` |
|
||||
| `qc` | `Agent` matching `qc-local`; `Bash` matching `ccam … lanes proof-link` |
|
||||
| `gate` | `Agent` matching `senior-gate-reviewer`; `Skill` matching `verification-before-completion` |
|
||||
| `review` | `Skill` matching `code-review\|requesting-code-review\|receiving-code-review`; `Agent` matching a name containing `reviewer`/`Reviewer` (excluding `senior-gate-reviewer`, a lookbehind) |
|
||||
| `qc` | `Agent` matching `qc-local\|Evidence Collector\|Accessibility Auditor`; `Bash` matching `ccam … lanes proof-link` |
|
||||
| `gate` | `Agent` matching `senior-gate-reviewer\|Reality Checker`; `Skill` matching `verification-before-completion` |
|
||||
| `publishing` | `Skill` matching `finishing-a-development-branch`; `Bash` matching a `git push` **invocation** (the same pattern `default.json`'s `ship` uses) |
|
||||
| `pr-open` | `Bash` matching `gh … pr create` |
|
||||
| `watching-pr` | `Bash` matching `gh … pr view` |
|
||||
@@ -849,13 +849,14 @@ forward-only AND never overrides a higher declared stage, a fix-loop re-entry
|
||||
that drops back to `gates` is invisible to detection — only the skill's
|
||||
`ccam stage gates` moves the lane back down.
|
||||
|
||||
`intake`, `gate`, and `done` in `default.json` deliberately have no rules.
|
||||
`intake` is where a lane starts — there is no tool event that means "just claimed," so there is
|
||||
nothing to detect. `gate` and `done` are explicitly out of scope for
|
||||
inference (see the task's "Out of scope" list): a gate's pass/fail is a human
|
||||
or skill decision, and `done` is the one state detection must never reach on
|
||||
its own — inferring either would let a heuristic assert an outcome instead of
|
||||
observing activity.
|
||||
`done` in `default.json` deliberately has no rule — it is explicitly out of
|
||||
scope for inference (see the task's "Out of scope" list): `done` is the one
|
||||
state detection must never reach on its own, since inferring it would let a
|
||||
heuristic assert an outcome instead of observing activity. `intake` and `gate`
|
||||
now carry entry-activity rules (an `Explore` agent, a `senior-gate-reviewer`/
|
||||
`Reality Checker` agent or `verification-before-completion` skill) — these
|
||||
detect that the *activity* of exploring or gate-reviewing started, never a
|
||||
gate's pass/fail verdict, so the "no outcome inference" rule still holds.
|
||||
|
||||
To add a rule, drop a template into the directory named by the
|
||||
`DASHBOARD_PIPELINES_DIR` environment variable (see "Custom pipeline
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
"assigned",
|
||||
"claimed",
|
||||
"start"
|
||||
],
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "^Explore$"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -31,6 +37,13 @@
|
||||
{
|
||||
"tool": "Write",
|
||||
"match": "docs/.*plan.*\\.md"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "^Plan$|Software Architect|Backend Architect|UX Architect"
|
||||
},
|
||||
{
|
||||
"tool": "TaskCreate"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -47,7 +60,7 @@
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Skill",
|
||||
"match": "executing-plans|subagent-driven-development"
|
||||
"match": "executing-plans|subagent-driven-development|test-driven-development"
|
||||
},
|
||||
{
|
||||
"tool": "Edit"
|
||||
@@ -72,7 +85,11 @@
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Bash",
|
||||
"match": "\\b(npm (run )?test|pytest|vitest|jest|go test|cargo test|node\\s+--test)\\b"
|
||||
"match": "\\b(npm (run )?test|pytest|vitest|jest|go test|cargo test|node\\s+--test|rspec|phpunit|dotnet test|mvn test|gradle test)\\b"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "Test Results Analyzer|API Tester|Performance Benchmarker"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -89,11 +106,15 @@
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Skill",
|
||||
"match": "code-review|requesting-code-review"
|
||||
"match": "code-review|requesting-code-review|receiving-code-review"
|
||||
},
|
||||
{
|
||||
"tool": "Bash",
|
||||
"match": "\\bgh\\b[^;&|]*\\bpr diff\\b"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "(?<!senior-gate-)[Rr]eviewer|Evidence Collector|Accessibility Auditor"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -107,6 +128,16 @@
|
||||
"verification",
|
||||
"sr-gate",
|
||||
"gate-blocked"
|
||||
],
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Skill",
|
||||
"match": "verification-before-completion"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "senior-gate-reviewer|Reality Checker"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
{
|
||||
"tool": "Bash",
|
||||
"match": "\\bccam\\b[^;&|]*\\bfeature activate\\b"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "^Explore$"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -42,6 +46,13 @@
|
||||
{
|
||||
"tool": "Write",
|
||||
"match": "docs/superpowers/specs/lane-.*\\.md"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "^Plan$|Software Architect"
|
||||
},
|
||||
{
|
||||
"tool": "TaskCreate"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -129,6 +140,10 @@
|
||||
{
|
||||
"tool": "Skill",
|
||||
"match": "code-review|requesting-code-review|receiving-code-review"
|
||||
},
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "(?<!senior-gate-)[Rr]eviewer"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -148,7 +163,7 @@
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "qc-local"
|
||||
"match": "qc-local|Evidence Collector|Accessibility Auditor"
|
||||
},
|
||||
{
|
||||
"tool": "Bash",
|
||||
@@ -170,7 +185,7 @@
|
||||
"detect": [
|
||||
{
|
||||
"tool": "Agent",
|
||||
"match": "senior-gate-reviewer"
|
||||
"match": "senior-gate-reviewer|Reality Checker"
|
||||
},
|
||||
{
|
||||
"tool": "Skill",
|
||||
|
||||
Reference in New Issue
Block a user