cohorte 1.0.0 → 1.1.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/CHANGELOG.md +41 -0
- package/README.md +32 -0
- package/core/agents/implementer.template.md +37 -14
- package/core/agents/release.md +1 -1
- package/core/agents/review.md +43 -17
- package/core/agents/smoke.md +61 -0
- package/core/commands/align-ds.md +1 -0
- package/core/commands/audit.md +9 -5
- package/core/commands/brainstorm.md +7 -4
- package/core/commands/build.md +37 -24
- package/core/commands/doctor.md +15 -1
- package/core/commands/fix.md +16 -10
- package/core/commands/refactor.md +17 -4
- package/core/commands/review.md +42 -21
- package/core/commands/ship.md +7 -3
- package/core/commands/smoke.md +32 -48
- package/core/commands/spec.md +33 -19
- package/core/commands/update-pipeline.md +1 -0
- package/core/templates/agent-handoff.md +7 -13
- package/core/templates/pr-body.md +1 -5
- package/core/templates/review-feedback.md +14 -18
- package/dashboard/dist/assets/{index-DN5OGW9g.css → index-Cj0SpgEY.css} +1 -1
- package/dashboard/dist/assets/index-YvkzH-yF.js +42 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/server/index.js +6 -0
- package/dashboard/server/metrics.js +94 -0
- package/install.ps1 +3 -1
- package/install.sh +3 -0
- package/package.json +1 -1
- package/profile/PIPELINE.template.md +4 -1
- package/profile/SCHEMA.md +31 -16
- package/scripts/kanban-move.sh +88 -0
- package/scripts/validate-core.mjs +118 -0
- package/core/hooks/__pycache__/gate.cpython-312.pyc +0 -0
- package/dashboard/dist/assets/index-CoBuEdy-.js +0 -42
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
model: sonnet
|
|
2
3
|
description: Apply the refactor backlog for one or more domains via the surface implementer agents (TDD-first, parallel across independent surfaces), then re-verify.
|
|
3
4
|
argument-hint: <domain…> (one or more surface keys, "shared", or "all")
|
|
4
5
|
---
|
|
@@ -16,9 +17,18 @@ You are the **lead**. Refactor domain **$ARGUMENTS** to match `PIPELINE.md`, usi
|
|
|
16
17
|
|
|
17
18
|
## 2. Dispatch the surface's implementer agent — TDD-first, stateless
|
|
18
19
|
|
|
19
|
-
Spawn the matching `<surface.agent>` with
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
Spawn the matching `<surface.agent>` with the template below. Keep it **byte-identical across loop
|
|
21
|
+
rounds** (only the final items slot varies — it sits at the end so repeats hit the prompt cache), and
|
|
22
|
+
never paste a diff — the agent computes its own, scoped to its tree:
|
|
23
|
+
|
|
24
|
+
> `subagent_type: <surface.agent>` — "Refactor pass on your surface (no feature spec). Read
|
|
25
|
+
> `PIPELINE.md` first. **Add the missing tests FIRST** (pin current behavior / cover the entry
|
|
26
|
+
> points), watch them pass, **then** refactor to clear each item. Preserve current public behavior
|
|
27
|
+
> unless an item marks it a bug. Migrations stay additive. Need the current state of your tree?
|
|
28
|
+
> Compute it yourself: `git diff <default_branch> -- <surface.path>`. Lint + format before handoff;
|
|
29
|
+
> return the handoff in the format your agent instructions define. Backlog items for YOUR surface
|
|
30
|
+
> (self-contained — clear exactly these, reading only the files they name): <the domain's open
|
|
31
|
+
> `- [ ]` lines verbatim, with exact file paths>."
|
|
22
32
|
|
|
23
33
|
**Parallel when domains are independent:** if the human passed several domains (or `all`), dispatch
|
|
24
34
|
their implementers **concurrently in a single message** — surface trees are disjoint by construction,
|
|
@@ -33,6 +43,9 @@ slices import it, so refactor it alone, first.
|
|
|
33
43
|
## 3. Verify & loop
|
|
34
44
|
|
|
35
45
|
After each agent returns: its surface's `test_cmd`/`lint_cmd`, `commands.typecheck`,
|
|
36
|
-
`commands.format --check
|
|
46
|
+
`commands.format --check` (redirect output to a file and grep it — don't print gate output into your
|
|
47
|
+
context). Then verify each backlog item cleared by checking its `file:line` directly — do NOT re-run
|
|
48
|
+
`/audit` per round (that repeats the repo-wide gates + a review dispatch you don't need); one optional
|
|
49
|
+
final `/audit` once ALL dispatched domains are clean is enough. Check cleared items off in
|
|
37
50
|
`specs/refactor-backlog.md`. Loop until each dispatched domain is clean. Verification is per-domain
|
|
38
51
|
even when the dispatch was parallel — one failing surface loops alone, the others don't redo work.
|
package/core/commands/review.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
model: sonnet
|
|
2
3
|
description: Dispatch the read-only review agent to audit the feature against its frozen spec.
|
|
3
4
|
argument-hint: <feature_id>
|
|
4
5
|
---
|
|
@@ -6,9 +7,7 @@ argument-hint: <feature_id>
|
|
|
6
7
|
You are the **lead**. Dispatch the review for feature **$ARGUMENTS**.
|
|
7
8
|
|
|
8
9
|
> Read `PIPELINE.md` §`vcs.default_branch` (diff base) and the `surfaces`/`contract` fields.
|
|
9
|
-
>
|
|
10
|
-
> Template paths below (`.claude/templates/…`) resolve to `~/.claude/templates/…` when the core is
|
|
11
|
-
> installed globally — read whichever exists.
|
|
10
|
+
> _Skip the re-read if it's already in your context this session and unmodified since._
|
|
12
11
|
>
|
|
13
12
|
> **Kanban** (SCHEMA.md §Kanban): move card `#$ARGUMENTS` → **Review**. No-op silently if no board.
|
|
14
13
|
|
|
@@ -21,33 +20,50 @@ You are the **lead**. Dispatch the review for feature **$ARGUMENTS**.
|
|
|
21
20
|
`git diff <default_branch> --name-only -- . $(for p in <each surface.path>; do printf ':(exclude)%s ' "$p"; done)`.
|
|
22
21
|
Attach the remainder to the most relevant surface's reviewer and say so in its dispatch. A surface whose
|
|
23
22
|
`git diff` comes back empty gets no reviewer.
|
|
23
|
+
- **Stage the hunks** (reviewers are read-only — no Bash — so a staged diff file is the ONLY way they
|
|
24
|
+
can review hunks instead of re-reading whole files). Per touched surface, regenerated every round:
|
|
25
|
+
`git diff <default_branch> -- <surface.path> > specs/reports/$ARGUMENTS.<surface.key>.diff`
|
|
26
|
+
(same gitignored buffer dir as the reports). For the surface that carries the shared remainder,
|
|
27
|
+
append the remainder pathspecs to its command so its `.diff` includes them. Never print a diff into
|
|
28
|
+
your own context — redirect straight to the file.
|
|
24
29
|
|
|
25
30
|
## 2. Dispatch review agents — one per touched surface, IN PARALLEL
|
|
26
31
|
|
|
27
32
|
Spawn ONE `review` agent per surface that has changed files, in a **single message** (one Task call
|
|
28
33
|
each, like `/build`) so they run concurrently — NEVER serially: review wall-clock must be the
|
|
29
|
-
slowest surface, not the sum. A diff touching a single surface ⇒ a single reviewer.
|
|
34
|
+
slowest surface, not the sum. A diff touching a single surface ⇒ a single reviewer.
|
|
35
|
+
|
|
36
|
+
**Small-diff fast path (re-reviews only):** if a surface's staged diff is tiny (≤2 files and ≤~40
|
|
37
|
+
changed lines), touches no contract file, and every open finding it addresses is non-security
|
|
38
|
+
LOW/MEDIUM, skip the dispatch: verify the hunks yourself against the open Remediation items (did the
|
|
39
|
+
prescribed fixes land? — NOT a de-novo audit) and write the same REVIEW REPORT into the §3 flow.
|
|
40
|
+
First-round reviews, contract changes, and security findings always get a full reviewer. For each
|
|
41
|
+
dispatched surface:
|
|
30
42
|
|
|
31
43
|
> `subagent_type: review` — "Review feature `$ARGUMENTS` — **scope: the `<surface.key>` surface
|
|
32
44
|
> only**. Read `PIPELINE.md` first (its flags + §Conventions/§Testing for `<surface.key>`). Spec:
|
|
33
|
-
> `specs/$ARGUMENTS.md` (source of truth). Contract: `<contract.path>/$ARGUMENTS.<ext>`.
|
|
34
|
-
>
|
|
35
|
-
>
|
|
45
|
+
> `specs/$ARGUMENTS.md` (source of truth). Contract: `<contract.path>/$ARGUMENTS.<ext>`. Diff to
|
|
46
|
+
> review: `specs/reports/$ARGUMENTS.<surface.key>.diff` (staged hunks — read it FIRST; open a full
|
|
47
|
+
> source file only when a finding demands it). Check spec conformance first, then correctness,
|
|
36
48
|
> security, conventions, RBAC/mobile-first _if the profile enables them_, and TDD coverage. Emit
|
|
37
|
-
> the REVIEW REPORT
|
|
38
|
-
> (`file:line` · severity · type · concrete fix)."
|
|
49
|
+
> the REVIEW REPORT in the format your agent instructions define — every finding self-sufficient
|
|
50
|
+
> (`file:line` · severity · type · concrete fix). Changed files (`--stat`): <list>."
|
|
39
51
|
|
|
40
|
-
|
|
52
|
+
The staging command in §1 already gave you the wall-clock start (`date +%s` in the same call) — §3's
|
|
53
|
+
metrics line needs it.
|
|
41
54
|
|
|
42
55
|
## 3. Merge & relay the verdict
|
|
43
56
|
|
|
44
57
|
Merge the returned reports into **one** REVIEW REPORT (same template): findings concatenated and
|
|
45
58
|
re-ordered by severity, counts summed, duplicates collapsed, verdict = the worst returned
|
|
46
|
-
(`BLOCK` > `REVISE` > `SHIP`). Append
|
|
47
|
-
(gitignored): `{"ts":"<ISO>","feature":"$ARGUMENTS","phase":"review","
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
non-recursive `specs/*.md` glob, so it's never mistaken for a spec (no phantom card, no bogus stage).
|
|
59
|
+
(`BLOCK` > `REVISE` > `SHIP`). Append ONE metrics line for the batch to `.claude/pipeline-metrics.jsonl`
|
|
60
|
+
(gitignored): `{"ts":"<ISO>","feature":"$ARGUMENTS","phase":"review","seconds":<wall-clock>,"surfaces":{"<key>":"<verdict>:<finding count>",…}}`.
|
|
61
|
+
**Stage the full report to `specs/reports/$ARGUMENTS.md`** (overwrite) — a gitignored buffer so a
|
|
62
|
+
`/fix` after a `/clear` can still read the findings; the `specs/reports/` subfolder is skipped by the
|
|
63
|
+
non-recursive `specs/*.md` glob, so it's never mistaken for a spec (no phantom card, no bogus stage).
|
|
64
|
+
In chat print ONLY: the verdict, the severity-count table, a one-line digest of each CRITICAL/security
|
|
65
|
+
finding, and `Full report: specs/reports/$ARGUMENTS.md` — never echo the findings body into chat (it
|
|
66
|
+
would sit in this session's history, re-sent every turn). Then:
|
|
51
67
|
|
|
52
68
|
- **SHIP** → a SHIP verdict *is* the pipeline's statement that the feature meets its Definition of
|
|
53
69
|
Done, so **tick the DoD**: in `specs/$ARGUMENTS.md` §`Acceptance criteria / DoD`, flip each `- [ ]`
|
|
@@ -60,9 +76,14 @@ non-recursive `specs/*.md` glob, so it's never mistaken for a spec (no phantom c
|
|
|
60
76
|
spec front-matter `reviewed_base: $BASE` plus
|
|
61
77
|
`reviewed_digest: $(git diff $BASE -- . ':(exclude)specs/' | sha256sum | cut -c1-16)` — the fingerprint
|
|
62
78
|
of exactly the source you just reviewed (specs excluded, so DoD ticks + the ship status flip don't
|
|
63
|
-
trip it). Then tell the human they can `/ship` —
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
trip it). Then tell the human they can `/ship` — **recommend a `/clear` first**, the handoff is
|
|
80
|
+
fully on disk. **SHIP with leftover LOW findings** (or LOW+MEDIUM at the human's call) does NOT
|
|
81
|
+
force a fix cycle for nits: park them in `specs/refactor-backlog.md` tagged `deferred:<id>` (NOT as
|
|
82
|
+
open `## Remediation` items, which would re-trigger the fix loop), keep the SHIP verdict and the
|
|
83
|
+
freshness stamp, and let the human ship.
|
|
84
|
+
- **REVISE / BLOCK**, or any CRITICAL/HIGH/security finding → tell the human to run
|
|
85
|
+
**`/fix $ARGUMENTS`** — it appends the report to the spec's `## Remediation` and re-dispatches ONLY
|
|
86
|
+
the surfaces with findings. The full path (`/spec` Mode B then `/build`) remains for findings that
|
|
87
|
+
change the contract in ways that ripple into clean surfaces. _The report is staged to
|
|
88
|
+
`specs/reports/$ARGUMENTS.md`, so you can `/clear` before `/fix` — it reads the findings back from
|
|
89
|
+
disk._
|
package/core/commands/ship.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
model: sonnet
|
|
2
3
|
description: At a SHIP verdict, dispatch the release agent to commit, push, and open the PR (with your confirmation).
|
|
3
4
|
argument-hint: <feature_id>
|
|
4
5
|
---
|
|
@@ -54,9 +55,10 @@ Confirm `specs/$ARGUMENTS.md` was committed as `status: shipped` (part of the re
|
|
|
54
55
|
`shipped` column (SCHEMA.md §Kanban "Move a card") and **append the PR number** so the line reads
|
|
55
56
|
`- [ ] <title> #$ARGUMENTS — PR #<num>`. Take `<num>` from the PR URL (`…/pull/13` ⇒ `13`); **always write
|
|
56
57
|
it when a PR was created** (the `gh` path) — it is what the dashboard turns into a PR link. If only a
|
|
57
|
-
compare URL was emitted (no PR yet), move the card without a number. Then
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
compare URL was emitted (no PR yet), move the card without a number. Then verify with a **grep for
|
|
59
|
+
`#$ARGUMENTS`** on the board (with surrounding heading context — `grep -B20 '#$ARGUMENTS' | grep '^##'`
|
|
60
|
+
or an offset-limited Read around the match): exactly one card, under the `shipped` heading — never
|
|
61
|
+
re-read the whole board into context. No board ⇒ skip silently.
|
|
60
62
|
|
|
61
63
|
## 5. After the PR — CI gate + teardown
|
|
62
64
|
|
|
@@ -66,3 +68,5 @@ skip silently.
|
|
|
66
68
|
`scripts/remove-feature.sh $ARGUMENTS` (add `--drop-db` to also drop the feature db; kept by
|
|
67
69
|
default). It removes the worktree, deletes the merged branch, frees the slot. Never run it before
|
|
68
70
|
the merge is confirmed, and only with the human's go-ahead (the gate will ask anyway).
|
|
71
|
+
- Feature closed — **recommend a `/clear`** before starting the next one; nothing from this session
|
|
72
|
+
is needed again (spec `shipped`, PR merged, board updated).
|
package/core/commands/smoke.md
CHANGED
|
@@ -1,55 +1,39 @@
|
|
|
1
1
|
---
|
|
2
|
+
model: sonnet
|
|
2
3
|
description: Exercise the built feature end-to-end in its worktree — infra up, migrations, contract endpoints, key UI flows, visual check vs design — before /review.
|
|
3
4
|
argument-hint: <feature_id>
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
You are the **lead**.
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
You are the **lead**. Dispatch the smoke run for feature **$ARGUMENTS** — the `smoke` agent actually
|
|
8
|
+
runs it so the bulky output (curl bodies, server logs, screenshots, design payloads) never enters
|
|
9
|
+
your own context, which is re-sent every turn.
|
|
9
10
|
|
|
10
|
-
> Read `PIPELINE.md` §`pipeline-profile`: `
|
|
11
|
-
>
|
|
12
|
-
> §9 acceptance).
|
|
11
|
+
> Read `PIPELINE.md` §`pipeline-profile`: `isolation` (worktree, slot ports, db) and `contract.path`.
|
|
12
|
+
> _Skip the re-read if it's already in your context this session and unmodified since._
|
|
13
13
|
>
|
|
14
|
-
> **Kanban
|
|
15
|
-
|
|
16
|
-
## 1.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
segment) + `<file>` (the `?file=` query) and fetch read-only via `DesignSync get_file(<projectId>,
|
|
41
|
-
<file>)`. Compare layout, states (empty/loading/error/suppressed…), copy language. Note deviations.
|
|
42
|
-
- No browser tooling available ⇒ **say so and skip the visual diff** — never claim a visual check
|
|
43
|
-
you didn't perform.
|
|
44
|
-
|
|
45
|
-
## 4. SMOKE REPORT
|
|
46
|
-
|
|
47
|
-
- One line per check: ✅/❌ · what was exercised · (on ❌) command → expected vs actual.
|
|
48
|
-
- **Stage the full report to `specs/reports/$ARGUMENTS.md`** (overwrite) — the same gitignored buffer
|
|
49
|
-
`/review` uses (subfolder ⇒ skipped by the non-recursive `specs/*.md` glob), so a `/fix` after a
|
|
50
|
-
`/clear` still has the failures.
|
|
51
|
-
- Verdict **PASS** (all green) → tell the human to run `/review $ARGUMENTS`.
|
|
52
|
-
Verdict **FAIL** → the failures are findings: feed them to `/fix $ARGUMENTS`, re-run `/smoke`
|
|
53
|
-
after. _Either way the handoff is on disk — `/clear` before the next command is safe._
|
|
54
|
-
- Append one metrics line to `.claude/pipeline-metrics.jsonl` (see `/build` §4, `phase: "smoke"`).
|
|
55
|
-
- Tear down what you started (kill the dev server); leave shared infra as you found it.
|
|
14
|
+
> **Kanban:** none here — `/review` owns the → **Review** move (running both duplicated it).
|
|
15
|
+
|
|
16
|
+
## 1. Resolve the checkout
|
|
17
|
+
|
|
18
|
+
With `isolation.enabled`: the sibling worktree (`../<slug>-$ARGUMENTS`, its slot's ports + db from
|
|
19
|
+
`.worktrees/slots.tsv`); otherwise the main checkout on the feature branch. Note the epoch
|
|
20
|
+
(`date +%s`) in the same Bash call that reads the slot — §3's metrics line needs it.
|
|
21
|
+
|
|
22
|
+
## 2. Dispatch ONE `smoke` agent
|
|
23
|
+
|
|
24
|
+
> `subagent_type: smoke` — "Smoke-test feature `$ARGUMENTS`. Read `PIPELINE.md` first. Spec:
|
|
25
|
+
> `specs/$ARGUMENTS.md`. Contract: `<contract.path>/$ARGUMENTS.<ext>`. Checkout: `<worktree path or
|
|
26
|
+
> main checkout>` · ports/db: `<slot info, or defaults>`. Bring it up, exercise the contract and the
|
|
27
|
+
> §8 UI flows, stage the full SMOKE REPORT to `specs/reports/$ARGUMENTS.md`, tear down, and return
|
|
28
|
+
> only the verdict + failure lines."
|
|
29
|
+
|
|
30
|
+
The gate hooks fire on the agent's Bash calls too — compose/migrate confirmations still reach the
|
|
31
|
+
human; that's expected.
|
|
32
|
+
|
|
33
|
+
## 3. Relay the verdict
|
|
34
|
+
|
|
35
|
+
- Print the agent's return as-is (verdict + ❌ lines + report path) — it is already minimal.
|
|
36
|
+
- Append ONE metrics line to `.claude/pipeline-metrics.jsonl` (see `/build` §4, `phase: "smoke"`).
|
|
37
|
+
- **PASS** → tell the human to run `/review $ARGUMENTS`. **FAIL** → the failures are findings: feed
|
|
38
|
+
them to `/fix $ARGUMENTS`, re-run `/smoke` after. Either way the report is on disk —
|
|
39
|
+
**recommend a `/clear`** before the next command.
|
package/core/commands/spec.md
CHANGED
|
@@ -20,16 +20,27 @@ Detect the mode from the pasted content:
|
|
|
20
20
|
|
|
21
21
|
## Mode A — new spec (input is a brainstorm return, or empty)
|
|
22
22
|
|
|
23
|
-
1. If empty,
|
|
23
|
+
1. If empty, look for a staged brainstorm return first — `specs/reports/*-brainstorm.md` (where
|
|
24
|
+
`/brainstorm` stages its output); one match ⇒ read it and confirm, several ⇒ ask which. None ⇒
|
|
25
|
+
ask the human to paste the return (or describe the feature) and wait.
|
|
24
26
|
2. Derive a `feature_id` (kebab-case slug). Confirm it.
|
|
27
|
+
2b. **Size budget — a spec is a contract, not a novel.** Target ≤ ~300 lines; hard-think at 500.
|
|
28
|
+
Every implementer re-reads the whole spec on every first build, so each extra line is paid
|
|
29
|
+
`surfaces × dispatches` times. If the feature genuinely needs more, that's the signal it is TWO
|
|
30
|
+
features: propose a split (e.g. `<id>-core` + `<id>-admin`, each independently shippable, the
|
|
31
|
+
second consuming the first's contract) and let the human pick. Trim the usual bloat before
|
|
32
|
+
writing: exhaustive UI walkthroughs (the design brief carries those), restated conventions
|
|
33
|
+
(PIPELINE.md carries those), speculative edge cases nobody asked for.
|
|
25
34
|
3. Walk the human through each section of `specs/_template.md`, **section by section**, with focused
|
|
26
35
|
questions. The critical one is **§5 API CONTRACT** — pin down every endpoint/interface (method, path,
|
|
27
36
|
auth/role, request fields with types/validation, success envelope + data shape, and every error case),
|
|
28
37
|
and name the exact schema/types that will live in the contract file (`contract.path/<id>.<ext>` in the
|
|
29
38
|
profile's `mechanism`). Don't move on until frontend and backend could each build from it with zero
|
|
30
39
|
further questions. _If `contract.enabled` is false, capture the interface precisely in prose instead._
|
|
31
|
-
4.
|
|
32
|
-
|
|
40
|
+
4. Capture the **design brief** content (only if `design.enabled` / the feature has UI): screens,
|
|
41
|
+
states, components, responsive notes — it will be authored to `specs/design/<id>.md` in step 6;
|
|
42
|
+
spec §8 carries only a short summary + the pointer `> full brief: specs/design/<id>.md` (so
|
|
43
|
+
non-design surfaces never re-read the full brief on every dispatch).
|
|
33
44
|
4b. **New-surface heads-up.** If the feature clearly introduces an area no existing `surfaces[].path`
|
|
34
45
|
owns (a new service/app/top-level module), note it in the spec (a line in the relevant task section:
|
|
35
46
|
`> needs new surface: <proposed key/path>`). Don't render agents here — `/build` §1.5 auto-reconciles
|
|
@@ -37,31 +48,34 @@ Detect the mode from the pasted content:
|
|
|
37
48
|
5. When the human validates, **freeze**: write `specs/<id>.md` (`status: frozen`, front-matter filled).
|
|
38
49
|
Create the file — do not ask the human to. **Postcondition:** `grep -q '^status: frozen' specs/<id>.md`
|
|
39
50
|
— if it fails the freeze didn't land; fix it before pointing the human at `/build`.
|
|
40
|
-
6.
|
|
51
|
+
6. Author the **design brief** — `specs/design/<id>.md`, rendered via
|
|
52
|
+
`.claude/templates/design-brief.md` (resolves to `~/.claude/templates/…` on a global install).
|
|
41
53
|
_Only if `design.enabled` / the feature has UI; skip entirely for a backend-only feature._
|
|
42
|
-
- **Write it to `specs/design/<id>.md`** (
|
|
43
|
-
file — do not ask the human to. Keep it in the
|
|
44
|
-
the `specs/*.md` glob that drives the
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
`/build`
|
|
54
|
+
- **Write it to `specs/design/<id>.md`** (the authored artifact, versioned with the spec; spec §8
|
|
55
|
+
holds the summary + pointer). Create the file — do not ask the human to. Keep it in the
|
|
56
|
+
`specs/design/` subfolder, **not** `specs/<id>....md`: the `specs/*.md` glob that drives the
|
|
57
|
+
kanban backfill and `/doctor` is non-recursive, so a brief in the subfolder never gets mistaken
|
|
58
|
+
for a spec (no phantom card, no bogus stage). Overwrite it on every freeze.
|
|
59
|
+
- Print ONLY the path + a one-line summary — never echo the brief into chat (it would sit in this
|
|
60
|
+
session's history; echo it only if the human asks). Tell the human: copy it from
|
|
61
|
+
`specs/design/<id>.md` into the design tool (if any — typically a fresh design project for this
|
|
62
|
+
feature), then run `/build <id>` and hand its design gate the resulting page link(s) — a full
|
|
63
|
+
`https://claude.ai/design/p/<projectId>?file=<file>` link carries its own project + page, no
|
|
64
|
+
profile change needed. (They can also paste the links into the spec's `design_files` themselves.)
|
|
65
|
+
**Recommend a `/clear` before `/build`** — the frozen spec + `specs/design/<id>.md` are the whole
|
|
66
|
+
handoff.
|
|
54
67
|
|
|
55
68
|
## Mode B — review return (input is a REVIEW REPORT)
|
|
56
69
|
|
|
57
|
-
1. Read the report — pasted as input, or (
|
|
58
|
-
where `/review` stages its last report. Identify `feature_id` from its
|
|
70
|
+
1. Read the report — pasted as input, or (whenever nothing is pasted) read from
|
|
71
|
+
`specs/reports/<id>.md`, where `/review` stages its last report. Identify `feature_id` from its
|
|
72
|
+
header; open `specs/<id>.md`.
|
|
59
73
|
2. Append each finding to the spec's **`## Remediation`**, one per line:
|
|
60
74
|
`- [ ] <severity> · <file:line> · <spec-violation|quality|security> · <concrete fix>`
|
|
61
75
|
(Keep prior items; add the new round under a dated/numbered subheading.)
|
|
62
76
|
3. If a finding implies the **contract** must change, update §5 and flag it so the lead re-authors the
|
|
63
77
|
contract file.
|
|
64
78
|
4. Set `status: in-review`. Tell the human to run `/build <id>` to re-dispatch fresh agents.
|
|
65
|
-
|
|
79
|
+
**Recommend a `/clear` before `/build`** — the spec is the whole handoff.
|
|
66
80
|
|
|
67
81
|
In both modes the spec is the single source of truth; agents are stateless and read only it + the diff.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
model: sonnet
|
|
2
3
|
description: Refresh the pipeline core (global ~/.claude, or a repo's bundled .claude) to the latest published cohorte version, then reconcile this repo's generated files to it — /init-pipeline stays one-time.
|
|
3
4
|
argument-hint: [path-to-local-checkout]
|
|
4
5
|
---
|
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
# HANDOFF — <surface> · `<feature_id>`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
<!-- Keep it tight: the lead only acts on mismatches, test failures, remediation ticks, and TODOs.
|
|
4
|
+
Never list files one by one — the lead has `git diff --stat`. -->
|
|
5
5
|
|
|
6
6
|
## Summary
|
|
7
7
|
|
|
8
8
|
<2–4 lines: what you built and the approach>
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Migrations / schema (only if any)
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
## Migrations / schema (if any)
|
|
15
|
-
|
|
16
|
-
- `<name>` — <additive change> · run with <PIPELINE.md commands.migrate>
|
|
12
|
+
- `<name>` — <additive change>
|
|
17
13
|
|
|
18
14
|
## Tests
|
|
19
15
|
|
|
20
|
-
- Added: <test files>
|
|
21
16
|
- Run: <this surface's test_cmd> · result: <pass/fail + counts>
|
|
22
17
|
|
|
23
|
-
## Contract
|
|
18
|
+
## Contract mismatches / assumptions
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
- Mismatches / assumptions: <none, or describe — DO NOT edit the contract; report instead>
|
|
20
|
+
<none, or describe — NEVER edit the contract; report here instead>
|
|
27
21
|
|
|
28
22
|
## Remediation addressed (fix loops only)
|
|
29
23
|
|
|
@@ -31,4 +25,4 @@ Commit/diff base: <default_branch...HEAD or "uncommitted working tree">
|
|
|
31
25
|
|
|
32
26
|
## TODO / not done
|
|
33
27
|
|
|
34
|
-
- <anything deferred, blocked, or out of scope>
|
|
28
|
+
- <anything deferred, blocked, or out of scope — or "none">
|
|
@@ -6,16 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
<2–4 lines: what this ships and the value, from the spec goal>
|
|
8
8
|
|
|
9
|
-
### Contract
|
|
10
|
-
|
|
11
|
-
<the interface + contract types added/changed — from spec §5 (omit if contract.enabled is false)>
|
|
12
|
-
|
|
13
9
|
### Changes
|
|
14
10
|
|
|
15
11
|
> One bullet per surface (from `PIPELINE.md` §surfaces), plus the shared contract.
|
|
16
12
|
|
|
17
13
|
- **<surface.key>:** <what changed>
|
|
18
|
-
- **Shared:** `<contract.path>/<feature_id>.<ext>`
|
|
14
|
+
- **Shared:** `<contract.path>/<feature_id>.<ext>` <(new/changed types: names only; omit if contract.enabled is false)>
|
|
19
15
|
|
|
20
16
|
### Tests
|
|
21
17
|
|
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
# REVIEW REPORT
|
|
2
2
|
|
|
3
|
+
<!-- Emitted-report shape. Everything in an HTML comment is guidance — do NOT emit it.
|
|
4
|
+
Verdict rules live in the review agent's instructions (SHIP = no CRITICAL/security;
|
|
5
|
+
REVISE = ≥1 CRITICAL; BLOCK = security vulnerability). -->
|
|
6
|
+
|
|
3
7
|
feature_id: <feature_id>
|
|
4
8
|
Feature branch: <feature_branch_prefix><feature_id>
|
|
5
9
|
Commit SHA: <first 12 chars>
|
|
6
10
|
|
|
7
|
-
| Severity | Count |
|
|
8
|
-
| -------- | ----- |
|
|
9
|
-
| CRITICAL | 0 |
|
|
10
|
-
| HIGH | 0 |
|
|
11
|
-
| MEDIUM | 0 |
|
|
12
|
-
| LOW | 0 |
|
|
11
|
+
| Severity | Count |
|
|
12
|
+
| -------- | ----- |
|
|
13
|
+
| CRITICAL | 0 |
|
|
14
|
+
| HIGH | 0 |
|
|
15
|
+
| MEDIUM | 0 |
|
|
16
|
+
| LOW | 0 |
|
|
13
17
|
|
|
14
18
|
Verdict: <SHIP | REVISE | BLOCK>
|
|
15
19
|
|
|
16
|
-
## Verdict rules
|
|
17
|
-
|
|
18
|
-
- **SHIP** — no CRITICAL and no security issue. Cleared for the human's manual QA + `/ship`.
|
|
19
|
-
- **REVISE** — one or more CRITICAL (spec violation / correctness). Must fix.
|
|
20
|
-
- **BLOCK** — a security vulnerability. Must fix immediately.
|
|
21
|
-
|
|
22
20
|
## Findings
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
<!-- Every finding self-sufficient for a stateless agent; order by severity; "None." if none.
|
|
23
|
+
The line format pastes straight into the spec's `## Remediation`. -->
|
|
26
24
|
|
|
27
25
|
- **[CRITICAL]** `<surface.path>/...:42` · spec-violation · <what's wrong vs spec §X> → **Fix:** <concrete change>
|
|
28
26
|
- **[HIGH]** `<path>:88` · quality · <issue> → **Fix:** <concrete change>
|
|
29
27
|
- **[BLOCK/security]** `<path>:line` · security · <vuln> → **Fix:** <concrete change>
|
|
30
28
|
|
|
31
|
-
Each finding line format (so it pastes straight into the spec's `## Remediation`):
|
|
32
|
-
`[<SEVERITY>] <file:line> · <spec-violation|quality|security> · <problem> → Fix: <concrete fix>`
|
|
33
|
-
|
|
34
29
|
## Notes
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
<!-- ONLY the RBAC / mobile-first assessment when the profile enables them; omit the section
|
|
32
|
+
otherwise. Never list things verified clean. -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--bg: #0e0f13;--panel: #16181f;--panel-2: #1c1f28;--border: #262a35;--text: #e6e8ee;--muted: #8b90a0;--accent: #6ea8fe;--ok: #3fb950;--warn: #d9a441;--bad: #f85149;--dev: #a371f7;--mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-family:var(--mono);font-size:14px}.app{min-height:100vh}.topbar{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;border-bottom:1px solid var(--border);position:sticky;top:0;z-index:20;background:#0e0f13e6;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.brand{font-weight:600;letter-spacing:.2px;display:flex;align-items:center;gap:8px}.dot{width:9px;height:9px;border-radius:50%;background:var(--accent);box-shadow:0 0 10px var(--accent)}.muted{color:var(--muted)}.small{font-size:12px}.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:16px;padding:20px;max-width:1100px;margin:0 auto}@media(max-width:720px){.grid{grid-template-columns:1fr}}.panel{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:16px 18px}.panel h2{margin:0 0 12px;font-size:13px;text-transform:uppercase;letter-spacing:1px;color:var(--muted)}.panel.placeholder{opacity:.7}.panel.error{grid-column:1 / -1;border-color:var(--bad);color:var(--bad)}.panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.panel-head h2{margin:0}.badge{font-size:11px;padding:3px 9px;border-radius:999px;border:1px solid var(--border);white-space:nowrap}.badge.ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent);background:color-mix(in srgb,var(--ok) 12%,transparent)}.badge.warn{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent)}.badge.bad{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 40%,transparent);background:color-mix(in srgb,var(--bad) 12%,transparent)}.badge.dev{color:var(--dev);border-color:color-mix(in srgb,var(--dev) 40%,transparent);background:color-mix(in srgb,var(--dev) 12%,transparent)}.badge.neutral{color:var(--muted)}.rows{display:flex;flex-direction:column;gap:2px}.row{display:flex;justify-content:space-between;gap:12px;padding:6px 0;border-bottom:1px dashed var(--border)}.row:last-child{border-bottom:none}.row-label{color:var(--muted)}.row-value{text-align:right}.row-value.strong{font-weight:600}.row-value.mono{font-family:var(--mono);font-size:12px}.actions{display:flex;align-items:center;gap:10px;margin-top:16px}.fresh-hint{margin:14px 0 0;padding-top:12px;border-top:1px dashed var(--border)}.fresh-hint strong{color:var(--accent)}button{font-family:var(--mono);font-size:13px;padding:7px 12px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text);cursor:pointer}button:disabled{opacity:.4;cursor:not-allowed}button.primary{background:color-mix(in srgb,var(--accent) 22%,var(--panel-2));border-color:color-mix(in srgb,var(--accent) 40%,transparent)}button.ghost{background:transparent}button:not(:disabled):hover{border-color:var(--accent)}.topbar-right{display:flex;align-items:center;gap:12px}.span2{grid-column:span 2}@media(max-width:720px){.span2{grid-column:1 / -1}}.summary{display:flex;gap:6px;flex-wrap:wrap}.checks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.check{display:flex;gap:10px;padding:9px 0;border-bottom:1px solid var(--border)}.check:last-child{border-bottom:none}.check.skip{opacity:.55}.check-icon{flex:none;width:20px;height:20px;border-radius:6px;display:grid;place-items:center;font-size:12px;font-weight:700;margin-top:1px}.check-icon.ok{color:var(--ok);background:color-mix(in srgb,var(--ok) 15%,transparent)}.check-icon.warn{color:var(--warn);background:color-mix(in srgb,var(--warn) 15%,transparent)}.check-icon.bad{color:var(--bad);background:color-mix(in srgb,var(--bad) 15%,transparent)}.check-icon.skip{color:var(--muted);background:var(--panel-2)}.check-body{flex:1;min-width:0}.check-line{display:flex;gap:10px;justify-content:space-between;flex-wrap:wrap}.check-label{font-weight:600}.check-detail{color:var(--muted);text-align:right}.check-fix{margin-top:4px;font-size:12px;color:var(--muted)}.check-fix code{color:var(--accent);background:var(--panel-2);padding:1px 6px;border-radius:5px}.surfaces{display:flex;flex-direction:column;gap:10px}.surface{border:1px solid var(--border);border-radius:9px;padding:10px 12px;background:var(--panel-2)}.surface-top{display:flex;align-items:center;gap:8px}.surface-key{font-weight:600}.surface-meta{display:flex;justify-content:space-between;gap:10px;margin-top:4px;font-size:12px}.surface-tools{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.tool{font-size:11px;color:var(--muted);border:1px solid var(--border);border-radius:5px;padding:1px 6px}.chip{font-size:11px;padding:1px 8px;border-radius:999px;border:1px solid var(--border)}.chip.design{color:var(--dev);border-color:color-mix(in srgb,var(--dev) 40%,transparent)}.chip.model-sonnet{color:var(--accent)}.chip.model-haiku{color:var(--ok)}.chip.model-inherit{color:var(--warn)}.fleet{max-width:1100px;margin:0 auto;padding:20px}.core-banner{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;background:linear-gradient(180deg,var(--panel-2),var(--panel));border:1px solid var(--border);border-radius:12px;padding:14px 18px;margin-bottom:20px}.cb-left{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.cb-title{text-transform:uppercase;letter-spacing:1px;font-size:12px;color:var(--muted)}.cb-version{font-weight:600;font-size:15px}.cb-actions{display:flex;gap:8px}.fleet-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:14px;flex-wrap:wrap}.fleet-head h2{margin:0;font-size:14px;display:flex;align-items:center;gap:8px}.add-wrap{flex:1;max-width:560px}.add-form{display:flex;gap:8px}.path-input{flex:1;font-family:var(--mono);font-size:13px;padding:7px 12px;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:8px}.path-input:focus{outline:none;border-color:var(--accent)}.path-input.invalid{border-color:var(--bad)}.add-error{margin-top:6px;font-size:12px;color:var(--bad);word-break:break-word}.fleet-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}.project-card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:14px 16px;cursor:pointer;transition:border-color .12s,transform .12s}.project-card:hover{border-color:var(--accent);transform:translateY(-1px)}.project-card.gone{opacity:.6;cursor:default}.pc-head{display:flex;align-items:center;justify-content:space-between}.pc-name{font-weight:600}.pc-path{margin:2px 0 10px}.pc-badges{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px}.pc-health{display:flex;align-items:center;gap:5px}.pc-counts{margin-left:auto}.icon-btn{border:none;background:transparent;color:var(--muted);padding:2px 6px;border-radius:6px;font-size:13px}.icon-btn:hover{color:var(--bad);background:var(--panel-2)}.pill{font-size:11px;min-width:20px;text-align:center;padding:1px 7px;border-radius:999px;font-weight:600}.pill.ok{color:var(--ok);background:color-mix(in srgb,var(--ok) 14%,transparent)}.pill.warn{color:var(--warn);background:color-mix(in srgb,var(--warn) 14%,transparent)}.pill.bad{color:var(--bad);background:color-mix(in srgb,var(--bad) 14%,transparent)}.pill.neutral{color:var(--muted);background:var(--panel-2)}.detail-crumb{grid-column:1 / -1;margin-bottom:-4px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.detail-tools{display:flex;gap:8px;flex-wrap:wrap}.tool-btn{font-size:12px;padding:5px 10px;border:1px solid color-mix(in srgb,var(--accent) 35%,var(--border));color:var(--accent);background:transparent}.tool-btn:hover{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent)}.confirm-text p{margin:0 0 8px;font-size:13px;line-height:1.6}.confirm-text code{background:var(--panel-2);padding:1px 5px;border-radius:4px;color:var(--accent)}.warn-line{color:var(--warn)!important;background:color-mix(in srgb,var(--warn) 10%,transparent);border-radius:8px;padding:8px 10px}.warn-line code{color:var(--text)!important}.danger-ghost{background:transparent;border:1px solid color-mix(in srgb,var(--bad) 40%,var(--border));color:var(--bad);font-size:12px;padding:5px 10px}.danger-ghost:hover{background:color-mix(in srgb,var(--bad) 12%,transparent);border-color:var(--bad)}button.danger{background:color-mix(in srgb,var(--bad) 20%,var(--panel-2));border-color:color-mix(in srgb,var(--bad) 45%,transparent);color:#ffd7d3}button.danger:hover{border-color:var(--bad)}.reset-list{margin:8px 0;padding-left:18px;font-size:13px;line-height:1.7}.reset-list code{color:var(--accent)}.reset-note{font-size:12.5px;color:var(--muted);background:var(--panel-2);border-radius:8px;padding:10px 12px}.reset-note code{color:var(--text)}.reset-check{display:flex;align-items:center;gap:8px;margin:12px 0 0;font-size:13px}.reset-check code{color:var(--accent)}.board-scroll{max-height:500px;overflow:auto}.board{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.col{background:var(--bg);border:1px solid var(--border);border-radius:9px;padding:8px;min-width:140px}.col-head{display:flex;justify-content:space-between;font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);padding:2px 4px 8px;position:sticky;top:0;background:var(--bg);z-index:1}.col-shipped{opacity:.85}.col-other{border-color:color-mix(in srgb,var(--warn) 40%,var(--border))}.spec-card{background:var(--panel-2);border:1px solid var(--border);border-radius:7px;padding:8px 9px;margin-bottom:7px}.spec-card.bad{border-color:color-mix(in srgb,var(--warn) 45%,transparent)}.spec-title{font-size:13px;font-weight:600}.spec-meta,.spec-branch{margin-top:3px}@media(max-width:640px){.board{grid-template-columns:repeat(2,1fr)}}.kanban-board{display:flex;gap:10px}.kanban-col{flex:0 0 210px;background:var(--bg);border:1px solid var(--border);border-radius:9px;padding:8px}.kanban-col.empty{opacity:.5}.kanban-card{background:var(--panel-2);border:1px solid var(--border);border-radius:7px;padding:8px 9px;margin-bottom:7px}.kanban-card.done{opacity:.6}.kanban-card.done .kc-text{text-decoration:line-through}.kc-text{font-size:12.5px;line-height:1.4}.kc-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.kc-tag{font-size:10px;color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent);border-radius:4px;padding:1px 5px}.kc-pr{font-size:10px;border-radius:4px;padding:1px 5px;text-decoration:none;border:1px solid var(--border);color:var(--muted)}a.kc-pr:hover{filter:brightness(1.25)}.kc-pr.state-open{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent);background:color-mix(in srgb,var(--ok) 12%,transparent)}.kc-pr.state-merged{color:var(--dev);border-color:color-mix(in srgb,var(--dev) 40%,transparent);background:color-mix(in srgb,var(--dev) 12%,transparent)}.kc-pr.state-closed{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 40%,transparent);background:color-mix(in srgb,var(--bad) 12%,transparent)}.kc-pr.draft{color:var(--muted);border-color:var(--border);background:var(--panel-2)}.kc-status{font-size:10px;margin-top:5px;color:var(--muted);text-transform:capitalize}.kc-status.state-open{color:var(--ok)}.kc-status.state-merged{color:var(--dev)}.kc-status.state-closed{color:var(--bad)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;display:grid;place-items:center;z-index:50;padding:20px}.modal{background:var(--panel);border:1px solid var(--border);border-radius:12px;width:min(720px,100%);max-height:80vh;display:flex;flex-direction:column;padding:18px}.modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.modal-head h3{margin:0;font-size:15px}.modal-actions{display:flex;gap:8px;margin-top:14px}.cmd{background:#000;color:var(--accent);padding:10px 12px;border-radius:8px;font-size:13px;overflow-x:auto}.run-log{background:#000;color:#d6d9e0;padding:12px;border-radius:8px;font-size:12.5px;line-height:1.5;overflow:auto;white-space:pre-wrap;word-break:break-word;flex:1;min-height:200px;max-height:55vh;margin:0}.picker{max-height:74vh}.picker-path{background:var(--panel-2);border:1px solid var(--border);border-radius:7px;padding:7px 10px;margin-bottom:10px;word-break:break-all}.picker-list{flex:1;overflow:auto;border:1px solid var(--border);border-radius:8px;padding:6px;min-height:220px;max-height:48vh}.picker-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:transparent;border:none;border-radius:6px;padding:7px 9px;color:var(--text);font-size:13px}.picker-row:hover{background:var(--panel-2);border-color:transparent}.picker-row.up{color:var(--muted)}.picker-icon{color:var(--muted);width:14px}.picker-row .badge.small{font-size:10px;padding:0 6px;margin-left:auto}.picker-empty{padding:12px}.add-form .ghost[type=button]{white-space:nowrap}
|
|
1
|
+
:root{--bg: #0e0f13;--panel: #16181f;--panel-2: #1c1f28;--border: #262a35;--text: #e6e8ee;--muted: #8b90a0;--accent: #6ea8fe;--ok: #3fb950;--warn: #d9a441;--bad: #f85149;--dev: #a371f7;--mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-family:var(--mono);font-size:14px}.app{min-height:100vh}.topbar{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;border-bottom:1px solid var(--border);position:sticky;top:0;z-index:20;background:#0e0f13e6;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.brand{font-weight:600;letter-spacing:.2px;display:flex;align-items:center;gap:8px}.dot{width:9px;height:9px;border-radius:50%;background:var(--accent);box-shadow:0 0 10px var(--accent)}.muted{color:var(--muted)}.small{font-size:12px}.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:16px;padding:20px;max-width:1100px;margin:0 auto}@media(max-width:720px){.grid{grid-template-columns:1fr}}.panel{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:16px 18px}.panel h2{margin:0 0 12px;font-size:13px;text-transform:uppercase;letter-spacing:1px;color:var(--muted)}.panel.placeholder{opacity:.7}.panel.error{grid-column:1 / -1;border-color:var(--bad);color:var(--bad)}.panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.panel-head h2{margin:0}.badge{font-size:11px;padding:3px 9px;border-radius:999px;border:1px solid var(--border);white-space:nowrap}.badge.ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent);background:color-mix(in srgb,var(--ok) 12%,transparent)}.badge.warn{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent)}.badge.bad{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 40%,transparent);background:color-mix(in srgb,var(--bad) 12%,transparent)}.badge.dev{color:var(--dev);border-color:color-mix(in srgb,var(--dev) 40%,transparent);background:color-mix(in srgb,var(--dev) 12%,transparent)}.badge.neutral{color:var(--muted)}.rows{display:flex;flex-direction:column;gap:2px}.row{display:flex;justify-content:space-between;gap:12px;padding:6px 0;border-bottom:1px dashed var(--border)}.row:last-child{border-bottom:none}.row-label{color:var(--muted)}.row-value{text-align:right}.row-value.strong{font-weight:600}.row-value.mono{font-family:var(--mono);font-size:12px}.actions{display:flex;align-items:center;gap:10px;margin-top:16px}.fresh-hint{margin:14px 0 0;padding-top:12px;border-top:1px dashed var(--border)}.fresh-hint strong{color:var(--accent)}button{font-family:var(--mono);font-size:13px;padding:7px 12px;border-radius:8px;border:1px solid var(--border);background:var(--panel-2);color:var(--text);cursor:pointer}button:disabled{opacity:.4;cursor:not-allowed}button.primary{background:color-mix(in srgb,var(--accent) 22%,var(--panel-2));border-color:color-mix(in srgb,var(--accent) 40%,transparent)}button.ghost{background:transparent}button:not(:disabled):hover{border-color:var(--accent)}.topbar-right{display:flex;align-items:center;gap:12px}.span2{grid-column:span 2}@media(max-width:720px){.span2{grid-column:1 / -1}}.summary{display:flex;gap:6px;flex-wrap:wrap}.checks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.check{display:flex;gap:10px;padding:9px 0;border-bottom:1px solid var(--border)}.check:last-child{border-bottom:none}.check.skip{opacity:.55}.check-icon{flex:none;width:20px;height:20px;border-radius:6px;display:grid;place-items:center;font-size:12px;font-weight:700;margin-top:1px}.check-icon.ok{color:var(--ok);background:color-mix(in srgb,var(--ok) 15%,transparent)}.check-icon.warn{color:var(--warn);background:color-mix(in srgb,var(--warn) 15%,transparent)}.check-icon.bad{color:var(--bad);background:color-mix(in srgb,var(--bad) 15%,transparent)}.check-icon.skip{color:var(--muted);background:var(--panel-2)}.check-body{flex:1;min-width:0}.check-line{display:flex;gap:10px;justify-content:space-between;flex-wrap:wrap}.check-label{font-weight:600}.check-detail{color:var(--muted);text-align:right}.check-fix{margin-top:4px;font-size:12px;color:var(--muted)}.check-fix code{color:var(--accent);background:var(--panel-2);padding:1px 6px;border-radius:5px}.surfaces{display:flex;flex-direction:column;gap:10px}.surface{border:1px solid var(--border);border-radius:9px;padding:10px 12px;background:var(--panel-2)}.surface-top{display:flex;align-items:center;gap:8px}.surface-key{font-weight:600}.surface-meta{display:flex;justify-content:space-between;gap:10px;margin-top:4px;font-size:12px}.surface-tools{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.tool{font-size:11px;color:var(--muted);border:1px solid var(--border);border-radius:5px;padding:1px 6px}.chip{font-size:11px;padding:1px 8px;border-radius:999px;border:1px solid var(--border)}.chip.design{color:var(--dev);border-color:color-mix(in srgb,var(--dev) 40%,transparent)}.chip.model-sonnet{color:var(--accent)}.chip.model-haiku{color:var(--ok)}.chip.model-inherit{color:var(--warn)}.fleet{max-width:1100px;margin:0 auto;padding:20px}.core-banner{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;background:linear-gradient(180deg,var(--panel-2),var(--panel));border:1px solid var(--border);border-radius:12px;padding:14px 18px;margin-bottom:20px}.cb-left{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.cb-title{text-transform:uppercase;letter-spacing:1px;font-size:12px;color:var(--muted)}.cb-version{font-weight:600;font-size:15px}.cb-actions{display:flex;gap:8px}.fleet-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:14px;flex-wrap:wrap}.fleet-head h2{margin:0;font-size:14px;display:flex;align-items:center;gap:8px}.add-wrap{flex:1;max-width:560px}.add-form{display:flex;gap:8px}.path-input{flex:1;font-family:var(--mono);font-size:13px;padding:7px 12px;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:8px}.path-input:focus{outline:none;border-color:var(--accent)}.path-input.invalid{border-color:var(--bad)}.add-error{margin-top:6px;font-size:12px;color:var(--bad);word-break:break-word}.fleet-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}.project-card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:14px 16px;cursor:pointer;transition:border-color .12s,transform .12s}.project-card:hover{border-color:var(--accent);transform:translateY(-1px)}.project-card.gone{opacity:.6;cursor:default}.pc-head{display:flex;align-items:center;justify-content:space-between}.pc-name{font-weight:600}.pc-path{margin:2px 0 10px}.pc-badges{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px}.pc-health{display:flex;align-items:center;gap:5px}.pc-counts{margin-left:auto}.icon-btn{border:none;background:transparent;color:var(--muted);padding:2px 6px;border-radius:6px;font-size:13px}.icon-btn:hover{color:var(--bad);background:var(--panel-2)}.pill{font-size:11px;min-width:20px;text-align:center;padding:1px 7px;border-radius:999px;font-weight:600}.pill.ok{color:var(--ok);background:color-mix(in srgb,var(--ok) 14%,transparent)}.pill.warn{color:var(--warn);background:color-mix(in srgb,var(--warn) 14%,transparent)}.pill.bad{color:var(--bad);background:color-mix(in srgb,var(--bad) 14%,transparent)}.pill.neutral{color:var(--muted);background:var(--panel-2)}.detail-crumb{grid-column:1 / -1;margin-bottom:-4px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.detail-tools{display:flex;gap:8px;flex-wrap:wrap}.tool-btn{font-size:12px;padding:5px 10px;border:1px solid color-mix(in srgb,var(--accent) 35%,var(--border));color:var(--accent);background:transparent}.tool-btn:hover{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent)}.confirm-text p{margin:0 0 8px;font-size:13px;line-height:1.6}.confirm-text code{background:var(--panel-2);padding:1px 5px;border-radius:4px;color:var(--accent)}.warn-line{color:var(--warn)!important;background:color-mix(in srgb,var(--warn) 10%,transparent);border-radius:8px;padding:8px 10px}.warn-line code{color:var(--text)!important}.danger-ghost{background:transparent;border:1px solid color-mix(in srgb,var(--bad) 40%,var(--border));color:var(--bad);font-size:12px;padding:5px 10px}.danger-ghost:hover{background:color-mix(in srgb,var(--bad) 12%,transparent);border-color:var(--bad)}button.danger{background:color-mix(in srgb,var(--bad) 20%,var(--panel-2));border-color:color-mix(in srgb,var(--bad) 45%,transparent);color:#ffd7d3}button.danger:hover{border-color:var(--bad)}.reset-list{margin:8px 0;padding-left:18px;font-size:13px;line-height:1.7}.reset-list code{color:var(--accent)}.reset-note{font-size:12.5px;color:var(--muted);background:var(--panel-2);border-radius:8px;padding:10px 12px}.reset-note code{color:var(--text)}.reset-check{display:flex;align-items:center;gap:8px;margin:12px 0 0;font-size:13px}.reset-check code{color:var(--accent)}.board-scroll{max-height:500px;overflow:auto}.board{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.col{background:var(--bg);border:1px solid var(--border);border-radius:9px;padding:8px;min-width:140px}.col-head{display:flex;justify-content:space-between;font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);padding:2px 4px 8px;position:sticky;top:0;background:var(--bg);z-index:1}.col-shipped{opacity:.85}.col-other{border-color:color-mix(in srgb,var(--warn) 40%,var(--border))}.spec-card{background:var(--panel-2);border:1px solid var(--border);border-radius:7px;padding:8px 9px;margin-bottom:7px}.spec-card.bad{border-color:color-mix(in srgb,var(--warn) 45%,transparent)}.spec-title{font-size:13px;font-weight:600}.spec-meta,.spec-branch{margin-top:3px}@media(max-width:640px){.board{grid-template-columns:repeat(2,1fr)}}.kanban-board{display:flex;gap:10px}.kanban-col{flex:0 0 210px;background:var(--bg);border:1px solid var(--border);border-radius:9px;padding:8px}.kanban-col.empty{opacity:.5}.kanban-card{background:var(--panel-2);border:1px solid var(--border);border-radius:7px;padding:8px 9px;margin-bottom:7px}.kanban-card.done{opacity:.6}.kanban-card.done .kc-text{text-decoration:line-through}.kc-text{font-size:12.5px;line-height:1.4}.kc-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.kc-tag{font-size:10px;color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent);border-radius:4px;padding:1px 5px}.kc-pr{font-size:10px;border-radius:4px;padding:1px 5px;text-decoration:none;border:1px solid var(--border);color:var(--muted)}a.kc-pr:hover{filter:brightness(1.25)}.kc-pr.state-open{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent);background:color-mix(in srgb,var(--ok) 12%,transparent)}.kc-pr.state-merged{color:var(--dev);border-color:color-mix(in srgb,var(--dev) 40%,transparent);background:color-mix(in srgb,var(--dev) 12%,transparent)}.kc-pr.state-closed{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 40%,transparent);background:color-mix(in srgb,var(--bad) 12%,transparent)}.kc-pr.draft{color:var(--muted);border-color:var(--border);background:var(--panel-2)}.kc-status{font-size:10px;margin-top:5px;color:var(--muted);text-transform:capitalize}.kc-status.state-open{color:var(--ok)}.kc-status.state-merged{color:var(--dev)}.kc-status.state-closed{color:var(--bad)}.metrics-list{display:flex;flex-direction:column;gap:12px}.metric-feature{background:var(--bg);border:1px solid var(--border);border-radius:9px;padding:10px 12px}.mf-head{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-bottom:8px}.mf-name{font-weight:600}.mf-badges{display:flex;gap:6px;flex-wrap:wrap}.phase-bars{display:flex;flex-direction:column;gap:4px}.phase-row{display:grid;grid-template-columns:56px 1fr 90px;align-items:center;gap:10px}.phase-label{color:var(--muted);font-size:12px}.phase-track{height:12px;border-radius:4px;background:var(--panel-2);overflow:hidden}.phase-fill{display:block;height:100%;min-width:2px;border-radius:4px;background:color-mix(in srgb,var(--accent) 65%,var(--panel-2))}.phase-value{text-align:right;white-space:nowrap}.surface-table{width:100%;border-collapse:collapse;margin-top:10px;font-size:12px}.surface-table th{text-align:left;color:var(--muted);font-weight:400;text-transform:uppercase;letter-spacing:.6px;font-size:10px;padding:4px 8px 6px 0;border-bottom:1px dashed var(--border)}.surface-table td{padding:5px 8px 5px 0;border-bottom:1px dashed var(--border)}.surface-table tr:last-child td{border-bottom:none}.st-key{font-weight:600}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;display:grid;place-items:center;z-index:50;padding:20px}.modal{background:var(--panel);border:1px solid var(--border);border-radius:12px;width:min(720px,100%);max-height:80vh;display:flex;flex-direction:column;padding:18px}.modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.modal-head h3{margin:0;font-size:15px}.modal-actions{display:flex;gap:8px;margin-top:14px}.cmd{background:#000;color:var(--accent);padding:10px 12px;border-radius:8px;font-size:13px;overflow-x:auto}.run-log{background:#000;color:#d6d9e0;padding:12px;border-radius:8px;font-size:12.5px;line-height:1.5;overflow:auto;white-space:pre-wrap;word-break:break-word;flex:1;min-height:200px;max-height:55vh;margin:0}.picker{max-height:74vh}.picker-path{background:var(--panel-2);border:1px solid var(--border);border-radius:7px;padding:7px 10px;margin-bottom:10px;word-break:break-all}.picker-list{flex:1;overflow:auto;border:1px solid var(--border);border-radius:8px;padding:6px;min-height:220px;max-height:48vh}.picker-row{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:transparent;border:none;border-radius:6px;padding:7px 9px;color:var(--text);font-size:13px}.picker-row:hover{background:var(--panel-2);border-color:transparent}.picker-row.up{color:var(--muted)}.picker-icon{color:var(--muted);width:14px}.picker-row .badge.small{font-size:10px;padding:0 6px;margin-left:auto}.picker-empty{padding:12px}.add-form .ghost[type=button]{white-space:nowrap}
|