@azure-id/orc 1.9.2 → 2.0.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 +321 -0
- package/README-id.md +21 -36
- package/README.md +25 -36
- package/bin/build-agents.js +117 -20
- package/bin/cli.js +725 -29
- package/bin/gotcha-import.js +1081 -0
- package/bin/gotcha.js +1286 -0
- package/bin/graph-query.js +1 -1
- package/bin/graph.js +717 -717
- package/bin/habit.js +1453 -0
- package/bin/mockrun-catalog.js +281 -276
- package/bin/run-undo.js +398 -0
- package/bin/trace-write.js +657 -0
- package/bin/verify-contracts.js +525 -79
- package/bin/verify-package.js +51 -4
- package/bin/webui/api.js +26 -0
- package/bin/webui/app.html +239 -232
- package/bin/webui/css/00-tokens.css +110 -92
- package/bin/webui/css/04-motion.css +87 -0
- package/bin/webui/css/06-responsive.css +203 -178
- package/bin/webui/css/panels/behaviour.css +205 -0
- package/bin/webui/fixtures/behaviour.js +532 -0
- package/bin/webui/fixtures/index.js +34 -0
- package/bin/webui/fixtures/knowledge.js +7 -1
- package/bin/webui/fixtures/stats.js +16 -0
- package/bin/webui/i18n/en/behaviour.json +143 -0
- package/bin/webui/i18n/en/nav.json +25 -24
- package/bin/webui/i18n/en/tour.json +37 -35
- package/bin/webui/i18n/id/behaviour.json +143 -0
- package/bin/webui/i18n/id/nav.json +25 -24
- package/bin/webui/i18n/id/tour.json +37 -35
- package/bin/webui/js/01-i18n.js +155 -154
- package/bin/webui/js/90-tour.js +498 -494
- package/bin/webui/js/91-shortcuts.js +126 -126
- package/bin/webui/js/99-boot.js +121 -118
- package/bin/webui/js/panels/behaviour.js +1022 -0
- package/mock-run/INDEX.md +109 -107
- package/mock-run/gotcha-import.md +118 -0
- package/mock-run/habits.md +129 -0
- package/mock-run/orc-quick.md +6 -1
- package/package.json +1 -1
- package/templates/agents/MODEL-MAPPING.md +7 -7
- package/templates/agents/orc-advisor-opus-5-xhigh.md +1 -7
- package/templates/agents/orc-analyze-mini-opus-5-med.md +1 -6
- package/templates/agents/orc-analyze-mini-sonnet-5-high.md +1 -4
- package/templates/agents/orc-claude-writer-opus-4-8-high.md +48 -53
- package/templates/agents/orc-claude-writer-opus-5-med.md +1 -8
- package/templates/agents/orc-context-combiner-opus-5-high.md +1 -11
- package/templates/agents/orc-executor-haiku-4-5.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-high.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-med.md +14 -6
- package/templates/agents/orc-executor-opus-4-8-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-low.md +14 -6
- package/templates/agents/orc-executor-opus-5-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-high.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-5-high.md +14 -6
- package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -10
- package/templates/agents/orc-judge-opus-5-xhigh.md +5 -9
- package/templates/agents/orc-learn-writer-opus-5-low.md +1 -7
- package/templates/agents/orc-pattern-codifier-opus-5-med.md +1 -8
- package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +58 -63
- package/templates/agents/orc-planner-mini-opus-5-med.md +1 -4
- package/templates/agents/orc-planner-mini-sonnet-5-high.md +1 -2
- package/templates/agents/orc-planner-opus-5-med.md +1 -4
- package/templates/agents/orc-recon-opus-5-low.md +1 -8
- package/templates/agents/orc-recon-sonnet-4-6-med.md +1 -8
- package/templates/agents/orc-retro-opus-5-med.md +6 -8
- package/templates/agents/orc-retro-sonnet-5-high.md +6 -7
- package/templates/agents/orc-reviewer-opus-5-med.md +52 -16
- package/templates/agents/orc-scout-opus-5-low.md +1 -6
- package/templates/agents/orc-scout-sonnet-4-6-high.md +35 -39
- package/templates/agents/orc-system-analyst-opus-5-high.md +1 -6
- package/templates/agents/orc-test-author-opus-5-med.md +4 -5
- package/templates/agents/orc-trace-writer-haiku-4-5.md +3 -7
- package/templates/agents/orc-verifier-opus-5-med.md +16 -8
- package/templates/agents/orc-wiki-scanner-opus-4-8-high.md +74 -79
- package/templates/agents/orc-wiki-scanner-opus-5-med.md +1 -8
- package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +97 -106
- package/templates/commands/orc-analyze.md +13 -21
- package/templates/commands/orc-fast.md +10 -15
- package/templates/commands/orc-poly.md +12 -21
- package/templates/commands/orc-pr-driver.md +11 -30
- package/templates/commands/orc-pr-setup.md +10 -31
- package/templates/commands/orc-route.md +11 -41
- package/templates/commands/orc-test.md +5 -60
- package/templates/hooks/README.md +34 -0
- package/templates/hooks/orc-session-hook.js +264 -0
- package/templates/hooks/orc-statusline.js +3 -1
- package/templates/skills/_shared/README.md +9 -0
- package/templates/skills/_shared/code-graph.md +47 -55
- package/templates/skills/_shared/config-precedence.md +3 -1
- package/templates/skills/_shared/extra-dispatch.md +73 -88
- package/templates/skills/_shared/gotchas.md +228 -177
- package/templates/skills/_shared/habits.md +101 -0
- package/templates/skills/_shared/lane-contract.md +84 -0
- package/templates/skills/_shared/phases/README.md +142 -83
- package/templates/skills/_shared/phases/analyst-gates.md +10 -21
- package/templates/skills/_shared/phases/execution.md +8 -14
- package/templates/skills/_shared/phases/house-rules.md +27 -32
- package/templates/skills/_shared/phases/intake.md +127 -133
- package/templates/skills/_shared/phases/mock-example.md +46 -56
- package/templates/skills/_shared/phases/plan-handoff.md +91 -97
- package/templates/skills/_shared/phases/planning.md +7 -17
- package/templates/skills/_shared/phases/preflight.md +19 -42
- package/templates/skills/_shared/phases/review.md +23 -27
- package/templates/skills/_shared/phases/rules.md +18 -42
- package/templates/skills/_shared/phases/scoring.md +55 -65
- package/templates/skills/_shared/phases/security-checklist.md +46 -50
- package/templates/skills/_shared/phases/security.md +45 -55
- package/templates/skills/_shared/phases/ship.md +6 -15
- package/templates/skills/_shared/phases/stop-resume.md +2 -5
- package/templates/skills/_shared/phases/summary.md +73 -48
- package/templates/skills/_shared/phases/testgen.md +41 -51
- package/templates/skills/_shared/phases/trace-verbs.md +433 -0
- package/templates/skills/_shared/phases/trace.md +136 -367
- package/templates/skills/_shared/phases/verify.md +62 -70
- package/templates/skills/_shared/phases/wave-grouping.md +128 -133
- package/templates/skills/_shared/phases/wiki-consult.md +10 -6
- package/templates/skills/_shared/read-ladder.md +2 -55
- package/templates/skills/_shared/return-validation.md +17 -70
- package/templates/skills/_shared/review-slice.md +79 -0
- package/templates/skills/_shared/smoke-gate.md +46 -28
- package/templates/skills/context-combiner/SKILL.md +15 -44
- package/templates/skills/orc/SKILL.md +34 -62
- package/templates/skills/orc/references/pattern-gate.md +89 -89
- package/templates/skills/orc/references/phases/intake.md +41 -47
- package/templates/skills/orc/references/phases/integration.md +13 -19
- package/templates/skills/orc/references/preflight-report.md +8 -9
- package/templates/skills/orc/references/ultra-mode.md +8 -6
- package/templates/skills/orc/subskills/orc-execution/SKILL.md +27 -73
- package/templates/skills/orc/subskills/orc-execution/core.md +12 -99
- package/templates/skills/orc/subskills/orc-execution/subagent.md +14 -13
- package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +11 -52
- package/templates/skills/orc/subskills/orc-review-verify/core.md +52 -135
- package/templates/skills/orc/subskills/orc-review-verify/subagent.md +7 -7
- package/templates/skills/orc/subskills/orc-testgen/SKILL.md +11 -22
- package/templates/skills/orc/subskills/orc-testgen/core.md +20 -59
- package/templates/skills/orc/subskills/orc-testgen/subagent.md +7 -7
- package/templates/skills/orc-advisor/SKILL.md +56 -60
- package/templates/skills/orc-analyze/SKILL.md +30 -66
- package/templates/skills/orc-analyze/schemas/report-audit.md +2 -1
- package/templates/skills/orc-analyze/schemas/report-prose.md +2 -1
- package/templates/skills/orc-analyze-mini/SKILL.md +35 -70
- package/templates/skills/orc-diy/README.md +31 -0
- package/templates/skills/orc-diy/SKILL.md +23 -74
- package/templates/skills/orc-diy/references/blocks/pattern.md +18 -18
- package/templates/skills/orc-fast/SKILL.md +44 -72
- package/templates/skills/orc-judge/SKILL.md +77 -82
- package/templates/skills/orc-mini/SKILL.md +61 -109
- package/templates/skills/orc-pattern/SKILL.md +27 -48
- package/templates/skills/orc-poly/SKILL.md +32 -61
- package/templates/skills/orc-pr-driver/SKILL.md +25 -51
- package/templates/skills/orc-pr-driver/references/green-gate.md +113 -105
- package/templates/skills/orc-pr-setup/SKILL.md +20 -45
- package/templates/skills/orc-quick/README.md +43 -2
- package/templates/skills/orc-quick/SKILL.md +76 -107
- package/templates/skills/orc-quick/references/dispatch-gate.md +16 -5
- package/templates/skills/orc-quick/references/gh-mode.md +48 -1
- package/templates/skills/orc-quick/references/look.md +3 -1
- package/templates/skills/orc-retro/SKILL.md +19 -18
- package/templates/skills/orc-retro/examples/retro-mock.md +1 -1
- package/templates/skills/orc-route/SKILL.md +25 -45
- package/templates/skills/orc-test/SKILL.md +16 -37
- package/templates/skills/orc-verify/SKILL.md +14 -32
- package/templates/skills/orc-wait/SKILL.md +156 -163
- package/templates/skills/orc-wiki/references/phases/phase-0.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-1.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-2.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-3.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-3c.md +1 -6
|
@@ -1,30 +1,11 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Stacked-PR driver — execute a stack plan: one branch per layer, mandatory per-layer green gate, gh stack submit, then sync/rebase/bottom-up merge
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Run the **orc-pr-driver** skill. It
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
**Three ways in — all read the same file** (`stacked-pr/<slug>/stack-plan.md`,
|
|
13
|
-
probed with `orc pr stack status`):
|
|
14
|
-
|
|
15
|
-
1. `/orc-pr-setup` planned it (the normal path),
|
|
16
|
-
2. ORC's ship phase handed it over (`stacked-pr/<slug>/STACK-FROM.md`),
|
|
17
|
-
3. **you wrote the plan yourself** — run `orc pr stack template` for the skeleton,
|
|
18
|
-
fill it in, and start here. No planner run required.
|
|
19
|
-
|
|
20
|
-
It **refuses to run** — naming the exact missing field — on a plan with an
|
|
21
|
-
unanswered uncertain seam, a missing ticket, a layer with no purpose or value
|
|
22
|
-
class, a FOUNDATION layer that names no consumer, fewer than 2 layers, or a red
|
|
23
|
-
build. It never fills a field in for you.
|
|
24
|
-
|
|
25
|
-
When the change already exists in the worktree, your work is snapshotted to a
|
|
26
|
-
scratch branch BEFORE any branch surgery, every layer is materialized from that
|
|
27
|
-
snapshot file-by-file, and a completeness gate proves the union of the layers
|
|
28
|
-
equals the snapshot exactly before anything is submitted.
|
|
29
|
-
|
|
30
|
-
Slug / plan path / stack action: $ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Stacked-PR driver — execute a stack plan: one branch per layer, mandatory per-layer green gate, gh stack submit, then sync/rebase/bottom-up merge
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run the **orc-pr-driver** skill. It executes `stacked-pr/<slug>/stack-plan.md`
|
|
6
|
+
(probed with `orc pr stack status`; written by `/orc-pr-setup`, by you, or
|
|
7
|
+
handed over as `STACK-FROM.md`): one branch per layer, a mandatory green gate
|
|
8
|
+
per layer, then `gh stack submit` and the merge care. It refuses a plan with an
|
|
9
|
+
open field or a red build, and never fills a field in for you.
|
|
10
|
+
|
|
11
|
+
Slug / plan path / stack action: $ARGUMENTS
|
|
@@ -1,31 +1,10 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Stacked-PR planner — decide where the PR cut lines go, prove each layer stands alone, write stacked-pr/<slug>/stack-plan.md (plans only, never touches git)
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Run the **orc-pr-setup** skill. It plans a
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
It **plans only**: no branches, no commits, no pushes, no PRs. That is
|
|
12
|
-
`/orc-pr-driver`.
|
|
13
|
-
|
|
14
|
-
Two entry modes, auto-detected: **greenfield** (nothing written yet — a spec or
|
|
15
|
-
ticket) and **orc-run** (the change already exists in the worktree, e.g. ORC just
|
|
16
|
-
built it — the split is file-granular; hunk surgery is forbidden). A ticket
|
|
17
|
-
number is required. The PR-description template is resolved from the ORC template,
|
|
18
|
-
then the project (`.github/`, `docs/`), then a `CLAUDE.md` section — and if none
|
|
19
|
-
exists you get three recommended options to pick from; declining them all means
|
|
20
|
-
the stack is skipped and the change ships as one regular PR.
|
|
21
|
-
|
|
22
|
-
**P0 hard gate:** every uncertain boundary STOPS the lane and asks you, one
|
|
23
|
-
decision at a time, with the LoC/file/CI cost of each option and a recommendation
|
|
24
|
-
— and records your answer under `## Decisions`. Same-tier files, shared helpers,
|
|
25
|
-
refactor mixed with behavior change, ordering ambiguity and oversize atoms are all
|
|
26
|
-
uncertain by definition. It never guesses a seam.
|
|
27
|
-
|
|
28
|
-
When the plan is written it shows the layer table, states that nothing has been
|
|
29
|
-
created yet, and hands off to `/orc-pr-driver`.
|
|
30
|
-
|
|
31
|
-
Ticket / change / spec: $ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Stacked-PR planner — decide where the PR cut lines go, prove each layer stands alone, write stacked-pr/<slug>/stack-plan.md (plans only, never touches git)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run the **orc-pr-setup** skill. It plans a stack of pull requests for a change
|
|
6
|
+
too big to review as one, and writes `stacked-pr/<slug>/stack-plan.md`. It plans
|
|
7
|
+
only: no branches, commits, pushes or PRs — that is `/orc-pr-driver`. A ticket
|
|
8
|
+
is required. Every uncertain boundary STOPS and asks you, one decision at a time.
|
|
9
|
+
|
|
10
|
+
Ticket / change / spec: $ARGUMENTS
|
|
@@ -1,41 +1,11 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: You have a plan — this says which lane should build it, with the numbers it decided from. Plan-only: it refuses a request in words rather than guess
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Use the **orc-route** skill. Zero agents, nothing is built.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
refusal and a pointer to `/orc-plan`, not a guess.
|
|
13
|
-
|
|
14
|
-
It reads the plan plus ORC's deterministic probes (`orc wiki status`,
|
|
15
|
-
`orc pattern status`, `orc gotcha status`, `orc diy status`) and answers:
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
Plan: merchant-notifications — 7 tasks, 3 waves, 14 files touched
|
|
19
|
-
top score 78, two tasks marked risky
|
|
20
|
-
|
|
21
|
-
→ /orc the plan has risky tasks and a task above 70;
|
|
22
|
-
review and verify are worth paying for here
|
|
23
|
-
runner-up /orc-mini — about 3x faster, but it skips full review
|
|
24
|
-
and verification. Fine only if you will read the diff yourself.
|
|
25
|
-
not possible /orc-fast — needs a fresh wiki (yours is STALE) and this plan
|
|
26
|
-
is 7 tasks; that lane runs ONE task
|
|
27
|
-
|
|
28
|
-
Start /orc now? [yes / no]
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Every runner-up says what choosing it costs you. Every impossible lane names the
|
|
32
|
-
condition blocking it **and** how to fix it. Risk beats size: a small plan with a
|
|
33
|
-
cited risk still earns the full lane.
|
|
34
|
-
|
|
35
|
-
`/orc-plan` also offers this automatically after **Save & stop**, so you rarely
|
|
36
|
-
need to type it.
|
|
37
|
-
|
|
38
|
-
New to ORC and wondering which command to use at all? That is
|
|
39
|
-
`orc onboarding first-run`, not this.
|
|
40
|
-
|
|
41
|
-
Plan (paste it, or give a path): $ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: You have a plan — this says which lane should build it, with the numbers it decided from. Plan-only: it refuses a request in words rather than guess
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Use the **orc-route** skill. Zero agents, nothing is built. It routes a PLAN
|
|
6
|
+
only — the same definition `skills/_shared/phases/plan-handoff.md` uses. It reads
|
|
7
|
+
the plan's tasks, files, deps, `facets` and scores plus ORC's probes, then names
|
|
8
|
+
the lane, the runner-up and its cost, and each impossible lane with its fix. A
|
|
9
|
+
request in words gets a pointer to `/orc-plan`, never a guess.
|
|
10
|
+
|
|
11
|
+
Plan (paste it, or give a path): $ARGUMENTS
|
|
@@ -2,65 +2,10 @@
|
|
|
2
2
|
description: Run the tests against the real running system — happy path to security — and report only what was observed
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
Use the **orc-test** skill. Standalone
|
|
6
|
-
your project.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
> **A test that ran is a FACT; a test that was written is an OPINION.**
|
|
11
|
-
|
|
12
|
-
ORC already has a lane that WRITES tests and never runs them (Phase 6.5,
|
|
13
|
-
`test-generator/`). This is the mirror image, and the two never mix: `/orc-test`
|
|
14
|
-
writes nothing into your test tree and runs everything.
|
|
15
|
-
|
|
16
|
-
**It never edits the system it is testing.** If the server will not come up, it
|
|
17
|
-
prints exactly what it ran and the tail of the output, and hands back. You fix
|
|
18
|
-
it, and re-run for free — the same shape as `/orc-challenge`, and for the same
|
|
19
|
-
reason: a session that just fixed the code cannot be trusted to measure it.
|
|
20
|
-
|
|
21
|
-
**It never reports a result it did not observe.** Three verdicts and no fourth:
|
|
22
|
-
`pass` (observed, matched), `fail` (observed, did not match), and `unknown` —
|
|
23
|
-
not observed. `unknown` keeps its slot in the report and never becomes a pass.
|
|
24
|
-
A flake is recorded, never retried away: there is no retry count, because if the
|
|
25
|
-
same case answers differently twice, *that instability is the finding*.
|
|
26
|
-
|
|
27
|
-
One pass:
|
|
28
|
-
|
|
29
|
-
1. **Target** — `orc test init <slug>` asks what it must not guess: back end or
|
|
30
|
-
front end, local or remote, the base URL. On a remote target it also requires
|
|
31
|
-
`--authorized "<who authorized this, and where it is recorded>"`, stored
|
|
32
|
-
verbatim and reprinted at the head of every report. ORC cannot verify
|
|
33
|
-
authorization and does not pretend to — it makes the assertion impossible to
|
|
34
|
-
skip. Frozen, and never asked again.
|
|
35
|
-
2. **Surface** — free, deterministic: an OpenAPI or GraphQL spec on disk, the
|
|
36
|
-
same spec at the target, route extraction by framework fingerprint, FE router
|
|
37
|
-
config. Anything ambiguous comes back as `unresolved[]` and is never guessed.
|
|
38
|
-
The **code-vs-live diff** is a first-class output: routes that answer live and
|
|
39
|
-
exist in no source file are zombie APIs.
|
|
40
|
-
3. **Flow** — it digs the repo for how a request reaches your endpoint: the
|
|
41
|
-
route registration, the middleware in order, the handler, what it writes, what
|
|
42
|
-
must be true first, which fields name an object, and the login flow itself.
|
|
43
|
-
4. **Environment** (local only) — it brings the system up and waits for health.
|
|
44
|
-
Five states, one next action each.
|
|
45
|
-
5. **Cases** — the CLI derives the bulk for free: equivalence partitions,
|
|
46
|
-
boundary values, method and content-type negatives, stateful create → read →
|
|
47
|
-
update → delete sequences. An agent fills only what a schema cannot know.
|
|
48
|
-
6. **Run** — paced, capped, and fenced to the frozen origin. A 429 is a RESULT,
|
|
49
|
-
not an error: it means rate limiting works. Every case leaves its exact
|
|
50
|
-
request, its exact response and a reproducible `curl`, with every credential
|
|
51
|
-
redacted **before the bytes reach disk**.
|
|
52
|
-
7. **Report** — `orc/orc-test/<slug>/REPORT.md`, written for someone who does
|
|
53
|
-
not read code.
|
|
54
|
-
|
|
55
|
-
The security tier is a **closed set** mapped to the OWASP API Security Top 10
|
|
56
|
-
(2023), and it demonstrates a CONDITION rather than an extraction — confirming
|
|
57
|
-
an exploit is your decision on your authority. With one identity, BOLA and BFLA
|
|
58
|
-
report `UNCHECKABLE`, which keeps its slot and never becomes a pass.
|
|
59
|
-
|
|
60
|
-
**The run folder is never staged.** Evidence contains real response bodies from
|
|
61
|
-
a real system. The lane offers you the one `.gitignore` line; it does not edit
|
|
62
|
-
`.gitignore` itself.
|
|
63
|
-
|
|
64
|
-
Read the state back any time without this lane: `orc test status <slug>`.
|
|
5
|
+
Use the **orc-test** skill. Standalone: no plan, no build, no code written into
|
|
6
|
+
your project. It RUNS the system; Phase 6.5 (`test-generator/`) writes tests and
|
|
7
|
+
never runs them. It never edits the system under test, and it never reports a
|
|
8
|
+
result it did not observe. The report is `orc/orc-test/<slug>/REPORT.md`; the
|
|
9
|
+
run folder is never staged. Read the state back with `orc test status <slug>`.
|
|
65
10
|
|
|
66
11
|
The slug to open or reopen (or nothing, and it will ask): $ARGUMENTS
|
|
@@ -414,6 +414,40 @@ outside an ORC run, and never when the map does not exist.
|
|
|
414
414
|
|
|
415
415
|
---
|
|
416
416
|
|
|
417
|
+
## The session hook
|
|
418
|
+
|
|
419
|
+
This is a fourth hook, `orc-session-hook.js`. It has four jobs. All of them are
|
|
420
|
+
silent when no ORC run is open.
|
|
421
|
+
|
|
422
|
+
- **The bell.** A turn of an ORC run ends, and your terminal rings once. This
|
|
423
|
+
job is off until you turn it on:
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
orc config set notify bell # ring when a turn of a run ends
|
|
427
|
+
orc config set notify off # silent (the default)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
It rings only when the run moved since the last bell. A normal chat never
|
|
431
|
+
rings. It sends no OS notification and uses no network.
|
|
432
|
+
- **After a compaction.** Claude Code keeps only the start of each skill when it
|
|
433
|
+
compacts a long session, so a long run can lose its place. When a run is in
|
|
434
|
+
flight, the hook adds ONE line: the run name, and the `state-of-play.md` file
|
|
435
|
+
to read first. It costs about 40 tokens, once per compaction.
|
|
436
|
+
|
|
437
|
+
- **The narration guard** (v2.0.2). A run dispatched agents but wrote no trace
|
|
438
|
+
line of its own. Then the hook stops the turn ONCE and says which command
|
|
439
|
+
writes the trace. It never stops twice, and never stops a subagent.
|
|
440
|
+
- **The review card** (v2.0.2). When a reviewer, verifier or judge starts, the
|
|
441
|
+
hook asks `orc gotcha card` for the files git sees as changed and gives the
|
|
442
|
+
card to that agent. No match → nothing. This is why a review always sees the
|
|
443
|
+
mistakes this project already made, even if the lane forgot the card.
|
|
444
|
+
|
|
445
|
+
It never writes model text, and it blocks a stop only for the narration guard.
|
|
446
|
+
`orc doctor` tells you whether all three events are wired (`Stop`,
|
|
447
|
+
`SessionStart compact`, `SubagentStart`).
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
417
451
|
## For maintainers
|
|
418
452
|
|
|
419
453
|
- The hook is `orc-statusline.js`. `orc init` installs it and wires it into
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ORC session hook (v2.0.0) — two main-session events, one file.
|
|
6
|
+
*
|
|
7
|
+
* Stop (Q8) the terminal bell when a turn of an ORC run
|
|
8
|
+
* ends. Config `notify`: `off` (the default) · `bell`.
|
|
9
|
+
* SessionStart `compact` (Q9) ONE line after a compaction, while a run is in
|
|
10
|
+
* flight, so the session is told where its state is.
|
|
11
|
+
*
|
|
12
|
+
* Both halves say NOTHING outside an open ORC run. A normal chat never rings
|
|
13
|
+
* and never gets a line. No OS notification, no network, no model text.
|
|
14
|
+
*
|
|
15
|
+
* An open run = the `.current` pointer in `log_dir` exists and is fresh (the
|
|
16
|
+
* same 6-hour window as orc-trace.js and orc-read-gate.js — one idea of "a run
|
|
17
|
+
* is open", not three). The lanes delete `.current` at FINISH.
|
|
18
|
+
*
|
|
19
|
+
* Wiring (installed by `orc init` into .claude/settings.json):
|
|
20
|
+
* hooks.Stop[] { hooks:[{command:"node <..>/orc-session-hook.js"}] }
|
|
21
|
+
* hooks.SessionStart[] { matcher:"compact", hooks:[{command:"node <..>/orc-session-hook.js"}] }
|
|
22
|
+
*
|
|
23
|
+
* Contract: read hook JSON from stdin. ALWAYS exit 0, silent on any error. It
|
|
24
|
+
* blocks a stop in ONE case only (v2.0.2, the narration guard below): the run in
|
|
25
|
+
* this session dispatched agents and wrote no narration line — once per run,
|
|
26
|
+
* never when `stop_hook_active` is set, never for a subagent.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const fs = require("fs");
|
|
30
|
+
const path = require("path");
|
|
31
|
+
|
|
32
|
+
// .claude/hooks/orc-session-hook.js → CLAUDE_DIR = .. → PROJECT_ROOT = ../..
|
|
33
|
+
const CLAUDE_DIR = path.join(__dirname, "..");
|
|
34
|
+
const PROJECT_ROOT = path.join(CLAUDE_DIR, "..");
|
|
35
|
+
const STALE_MS = 6 * 60 * 60 * 1000;
|
|
36
|
+
// The canonical trace name — the same regex the CLI's in-flight read uses.
|
|
37
|
+
const TRACE_NAME = /^run-([a-z0-9]+)-(.+)-(\d{6})-(\d{6})\.txt$/;
|
|
38
|
+
const RUN_DIR_DEFAULT = ".claude/orc/run";
|
|
39
|
+
|
|
40
|
+
// Tolerant top-level YAML scalar read, matching orc-read-gate.js exactly.
|
|
41
|
+
function readConfigScalar(key) {
|
|
42
|
+
try {
|
|
43
|
+
const text = fs.readFileSync(path.join(CLAUDE_DIR, "orc.config.yaml"), "utf8");
|
|
44
|
+
const re = new RegExp("^" + key + "\\s*:\\s*(.+?)\\s*(?:#.*)?$", "m");
|
|
45
|
+
const m = text.match(re);
|
|
46
|
+
return m ? m[1].replace(/^['"]|['"]$/g, "").trim() : null;
|
|
47
|
+
} catch (_) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function abs(rel) {
|
|
53
|
+
return path.isAbsolute(rel) ? rel : path.join(PROJECT_ROOT, rel);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function logDir() {
|
|
57
|
+
return abs(readConfigScalar("log_dir") || ".claude/orc/logs");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function mtime(p) {
|
|
61
|
+
try {
|
|
62
|
+
return fs.statSync(p).mtimeMs;
|
|
63
|
+
} catch (_) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// The open run, or null. `last` = the newest sign of life (the trace file or
|
|
69
|
+
// the pointer), which the bell compares with the session start.
|
|
70
|
+
function openRun() {
|
|
71
|
+
const dir = logDir();
|
|
72
|
+
let name;
|
|
73
|
+
try {
|
|
74
|
+
name = fs.readFileSync(path.join(dir, ".current"), "utf8").trim();
|
|
75
|
+
} catch (_) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (!name) return null;
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
const last = Math.max(mtime(path.join(dir, name)) || 0, mtime(path.join(dir, ".current")) || 0);
|
|
81
|
+
if (!last || now - last >= STALE_MS) return null;
|
|
82
|
+
return { dir, name, last };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── The narration guard (v2.0.2, eval D9) ────────────────────────────────────
|
|
86
|
+
// A live lane can dispatch agents and end its turn with ZERO narration: the trace
|
|
87
|
+
// holds only the hook's SPAWN/RETURN lines, and the reply still says "FINISH".
|
|
88
|
+
// Then the stats, the retro and the habit engine see nothing. So ONCE per run,
|
|
89
|
+
// in the main session, a stop is blocked with the one command that fixes it.
|
|
90
|
+
// `stop_hook_active` (Claude Code's own re-entry flag) means the lane already
|
|
91
|
+
// had its chance — never block twice.
|
|
92
|
+
function narrationGuard(data) {
|
|
93
|
+
if (data.agent_id || data.stop_hook_active) return false;
|
|
94
|
+
const dir = logDir();
|
|
95
|
+
let born = 0;
|
|
96
|
+
try {
|
|
97
|
+
if (data.transcript_path) born = fs.statSync(data.transcript_path).birthtimeMs || 0;
|
|
98
|
+
} catch (_) {}
|
|
99
|
+
let best = null;
|
|
100
|
+
try {
|
|
101
|
+
for (const f of fs.readdirSync(dir)) {
|
|
102
|
+
if (!TRACE_NAME.test(f)) continue;
|
|
103
|
+
const t = mtime(path.join(dir, f));
|
|
104
|
+
if (t && (!best || t > best.t)) best = { f, t };
|
|
105
|
+
}
|
|
106
|
+
} catch (_) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (!best || Date.now() - best.t >= STALE_MS || (born && best.t < born)) return false;
|
|
110
|
+
let text = "";
|
|
111
|
+
try {
|
|
112
|
+
text = fs.readFileSync(path.join(dir, best.f), "utf8");
|
|
113
|
+
} catch (_) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const lines = text.split(/\r?\n/).filter((l) => /^\[/.test(l));
|
|
117
|
+
if (!lines.some((l) => /\]\s+hook\s+SPAWN /.test(l))) return false; // nothing was dispatched yet
|
|
118
|
+
if (lines.some((l) => !/\]\s+hook\s+/.test(l))) return false; // a packet already landed
|
|
119
|
+
const statePath = path.join(CLAUDE_DIR, "orc", "narration-guard.json");
|
|
120
|
+
try {
|
|
121
|
+
if (JSON.parse(fs.readFileSync(statePath, "utf8")).run === best.f) return false;
|
|
122
|
+
} catch (_) {}
|
|
123
|
+
try {
|
|
124
|
+
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
125
|
+
fs.writeFileSync(statePath, JSON.stringify({ run: best.f, at: Date.now() }) + "\n");
|
|
126
|
+
} catch (_) {}
|
|
127
|
+
process.stdout.write(
|
|
128
|
+
JSON.stringify({
|
|
129
|
+
decision: "block",
|
|
130
|
+
reason:
|
|
131
|
+
`ORC: the trace ${best.f} has agent dispatches but NO narration line — zero new trace lines is a protocol violation. ` +
|
|
132
|
+
`Pipe this run's phase packets (with their REAL event times, and the ASK events if habits is on) to ` +
|
|
133
|
+
`\`orc trace write --packet -\` now (\`run: ${best.f.replace(/\.txt$/, "")}\` if .current is gone), then finish.`,
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── The review card at SubagentStart (v2.0.2, eval D13) ─────────────────────
|
|
140
|
+
// A live /orc-quick review dispatched `orc-reviewer-opus-5-med` with NO gotcha
|
|
141
|
+
// card in its prompt in 5 of 5 runs, although review learning is always on. The
|
|
142
|
+
// card is a CLI answer, so the hook hands it over itself: for a reviewer,
|
|
143
|
+
// verifier or judge, the files git sees as changed → `orc gotcha card` → one
|
|
144
|
+
// `additionalContext` block. No match, no CLI, any error → silent.
|
|
145
|
+
const REVIEW_AGENT = /^orc-(reviewer|verifier|judge)-/;
|
|
146
|
+
function onReviewStart(data) {
|
|
147
|
+
const agent = String(data.agent_type || data.agentType || "");
|
|
148
|
+
if (!REVIEW_AGENT.test(agent)) return;
|
|
149
|
+
const { execFileSync } = require("child_process");
|
|
150
|
+
let cli = null;
|
|
151
|
+
try {
|
|
152
|
+
cli = JSON.parse(fs.readFileSync(path.join(CLAUDE_DIR, "hooks", "orc-version.json"), "utf8")).cli || null;
|
|
153
|
+
} catch (_) {}
|
|
154
|
+
if (!cli || !fs.existsSync(cli)) return;
|
|
155
|
+
const git = (args) => {
|
|
156
|
+
try {
|
|
157
|
+
return execFileSync("git", args, { cwd: PROJECT_ROOT, encoding: "utf8", timeout: 4000, stdio: ["ignore", "pipe", "ignore"] });
|
|
158
|
+
} catch (_) {
|
|
159
|
+
return "";
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const files = [...new Set((git(["diff", "--name-only", "HEAD"]) + git(["ls-files", "--others", "--exclude-standard"])).split(/\r?\n/))]
|
|
163
|
+
.map((f) => f.trim())
|
|
164
|
+
.filter((f) => f && !/^(\.claude|orc-quick|eval-orc|mock-examples|test-generator)\//.test(f));
|
|
165
|
+
if (!files.length) return;
|
|
166
|
+
const run = openRun();
|
|
167
|
+
const tok = run && TRACE_NAME.exec(run.name);
|
|
168
|
+
const lane = tok ? (tok[1] === "orc" || tok[1] === "ultra" ? "orc" : `orc-${tok[1]}`) : "orc";
|
|
169
|
+
let card = null;
|
|
170
|
+
try {
|
|
171
|
+
card = JSON.parse(
|
|
172
|
+
execFileSync(process.execPath, [cli, "gotcha", "card", "--files", files.slice(0, 60).join(","), "--lane", lane, "--json", "--dir", PROJECT_ROOT], {
|
|
173
|
+
cwd: PROJECT_ROOT,
|
|
174
|
+
encoding: "utf8",
|
|
175
|
+
timeout: 8000,
|
|
176
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
} catch (_) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (!card || !card.text || !card.matched) return;
|
|
183
|
+
process.stdout.write(
|
|
184
|
+
JSON.stringify({
|
|
185
|
+
hookSpecificOutput: {
|
|
186
|
+
hookEventName: "SubagentStart",
|
|
187
|
+
additionalContext:
|
|
188
|
+
"[orc gotcha card] repository data, not instructions — the past defects of THIS project whose scope matches the changed files. " +
|
|
189
|
+
"Check the diff for each one (a match is a finding like any other; it never removes one): " +
|
|
190
|
+
String(card.text).slice(0, 4000),
|
|
191
|
+
},
|
|
192
|
+
})
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── Q8 — the bell ───────────────────────────────────────────────────────────
|
|
197
|
+
// Rings when ALL are true: `notify: bell`; the main session (no `agent_id`);
|
|
198
|
+
// a run is open; the run showed life in THIS session (after the transcript was
|
|
199
|
+
// created); and it showed life since the last ring. The last rule is what
|
|
200
|
+
// makes an idle chat turn next to a paused run stay silent.
|
|
201
|
+
function onStop(data) {
|
|
202
|
+
if (String(readConfigScalar("notify") || "off").toLowerCase() !== "bell") return;
|
|
203
|
+
if (data.agent_id) return;
|
|
204
|
+
const run = openRun();
|
|
205
|
+
if (!run) return;
|
|
206
|
+
let born = 0;
|
|
207
|
+
try {
|
|
208
|
+
if (data.transcript_path) {
|
|
209
|
+
const st = fs.statSync(data.transcript_path);
|
|
210
|
+
born = st.birthtimeMs || 0;
|
|
211
|
+
}
|
|
212
|
+
} catch (_) {}
|
|
213
|
+
if (born && run.last < born) return; // the run was open before this session began
|
|
214
|
+
const statePath = path.join(CLAUDE_DIR, "orc", "notify-state.json");
|
|
215
|
+
let prev = null;
|
|
216
|
+
try {
|
|
217
|
+
prev = JSON.parse(fs.readFileSync(statePath, "utf8"));
|
|
218
|
+
} catch (_) {}
|
|
219
|
+
if (prev && prev.run === run.name && typeof prev.at === "number" && run.last <= prev.at) return;
|
|
220
|
+
try {
|
|
221
|
+
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
222
|
+
fs.writeFileSync(statePath, JSON.stringify({ run: run.name, at: Date.now() }) + "\n");
|
|
223
|
+
} catch (_) {}
|
|
224
|
+
process.stdout.write(JSON.stringify({ terminalSequence: "\u0007" }));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ── Q9 — the run pointer after compaction ───────────────────────────────────
|
|
228
|
+
// ONE line, only when the pointer names a run whose folder exists and is not
|
|
229
|
+
// closed. A run the disk cannot find is not a run this line can point at.
|
|
230
|
+
function onCompact(data) {
|
|
231
|
+
if (data.source && data.source !== "compact") return;
|
|
232
|
+
const run = openRun();
|
|
233
|
+
if (!run) return;
|
|
234
|
+
const m = TRACE_NAME.exec(run.name);
|
|
235
|
+
if (!m) return;
|
|
236
|
+
const slug = m[2];
|
|
237
|
+
const rel = readConfigScalar("run_dir") || RUN_DIR_DEFAULT;
|
|
238
|
+
const folder = path.join(abs(rel), slug);
|
|
239
|
+
try {
|
|
240
|
+
if (!fs.statSync(folder).isDirectory()) return;
|
|
241
|
+
} catch (_) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (fs.existsSync(path.join(folder, "RESUME.closed.md"))) return;
|
|
245
|
+
const shown = path.isAbsolute(rel) ? rel : rel.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
246
|
+
process.stdout.write(
|
|
247
|
+
`orc: run ${slug} is in flight — read ${shown}/${slug}/state-of-play.md, then the checkpoint (hard rule 2)\n`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let raw = "";
|
|
252
|
+
process.stdin.on("data", (c) => (raw += c));
|
|
253
|
+
process.stdin.on("end", () => {
|
|
254
|
+
try {
|
|
255
|
+
const data = JSON.parse(raw || "{}") || {};
|
|
256
|
+
const ev = String(data.hook_event_name || "");
|
|
257
|
+
if (ev === "Stop") {
|
|
258
|
+
if (!narrationGuard(data)) onStop(data);
|
|
259
|
+
}
|
|
260
|
+
else if (ev === "SessionStart") onCompact(data);
|
|
261
|
+
else if (ev === "SubagentStart") onReviewStart(data);
|
|
262
|
+
} catch (_) {}
|
|
263
|
+
process.exit(0);
|
|
264
|
+
});
|
|
@@ -1339,8 +1339,10 @@ function extendedScan(d, wants, wantsProvider) {
|
|
|
1339
1339
|
}
|
|
1340
1340
|
if (wants("gotchas.count")) {
|
|
1341
1341
|
SCAN.gotchas = cached("gotchas", TTL.knowledge, () => {
|
|
1342
|
+
// The ledger is ONE file, `.claude/orc/gotchas.md`; each entry opens with
|
|
1343
|
+
// a `## G-<id>` heading. No file → null, never 0 (no ledger is not "none").
|
|
1342
1344
|
try {
|
|
1343
|
-
return fs.
|
|
1345
|
+
return (fs.readFileSync(path.join(orc, "gotchas.md"), "utf8").match(/^##[ \t]+G-\d/gm) || []).length;
|
|
1344
1346
|
} catch (_) {
|
|
1345
1347
|
return null;
|
|
1346
1348
|
}
|
|
@@ -55,6 +55,15 @@ loaded on demand when the step fires.
|
|
|
55
55
|
their meaning — read a family top-down and stop at the first rank that
|
|
56
56
|
resolves. Also the two contested families, gates vs inertness, the
|
|
57
57
|
`announce[]` boundary, and what a lane does when the CLI cannot answer.
|
|
58
|
+
- `lane-contract.md` — the common text of the six spine blocks (Calls · Config ·
|
|
59
|
+
Rules · Trace · Phases · Wait), held once. A coding-lane spine keeps a short
|
|
60
|
+
pointer with its own values and reads this file ONLY when a CLI call exits ≠ 0.
|
|
61
|
+
- `habits.md` — the lane side of habits: the `→ usual` mark, the `ASK` event at
|
|
62
|
+
each `(H <qid>)` question, and the one run-end proposal. Read ONLY when
|
|
63
|
+
`orc lane config` answers with a `habits{}` block (never under `habits: off`).
|
|
64
|
+
- `review-slice.md` — the ONE review slice every lane uses: the R1 free check,
|
|
65
|
+
the fields (`tool_findings[]`, `gotcha_card` …) and the
|
|
66
|
+
after-filter. Read ONLY when a review dispatch is about to be built.
|
|
58
67
|
|
|
59
68
|
Human guides live in the skills themselves: `../orc-pr-setup/README.md` (plan the
|
|
60
69
|
layers), `../orc-pr-driver/README.md` (build, submit, merge them), and
|