@andresmassello/uscha 1.40.2 → 1.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/bin/uscha.js +19 -7
- package/package.json +1 -1
- package/uscha-kit/.claude/skills/uscha-adr-refine/SKILL.md +2 -2
- package/uscha-kit/.claude/skills/uscha-devloop/SKILL.md +3 -1
- package/uscha-kit/.claude/skills/uscha-devloop/qa_ledger.py +729 -155
- package/uscha-kit/.claude/skills/uscha-mirador/SKILL.md +22 -7
- package/uscha-kit/.claude/skills/uscha-mirador/mirador-render.py +44 -5
- package/uscha-kit/.claude/skills/uscha-mirador/mirador-watch.ps1 +1 -1
- package/uscha-kit/.claude/skills/uscha-mirador/mirador-watch.sh +1 -1
- package/uscha-kit/.claude/skills/uscha-mirador/mirador.template.html +666 -586
- package/uscha-kit/.claude-plugin/plugin.json +1 -1
- package/uscha-kit/.codex-plugin/plugin.json +1 -1
- package/uscha-kit/CHANGELOG-1.41.0.md +18 -0
- package/uscha-kit/CHANGELOG-1.41.1.md +53 -0
- package/uscha-kit/CHANGELOG-1.41.2.md +34 -0
- package/uscha-kit/CHANGELOG-1.41.3.md +30 -0
- package/uscha-kit/CHANGELOG-1.42.0.md +41 -0
- package/uscha-kit/CHANGELOG-1.43.0.md +37 -0
- package/uscha-kit/INSTALL.md +120 -101
- package/uscha-kit/README.md +24 -13
- package/uscha-kit/VERSION +1 -1
- package/uscha-kit/WORKBENCH.md +19 -5
- package/uscha-kit/hooks/block-approved-writes.py +25 -0
- package/uscha-kit/install-uscha.py +534 -267
- package/uscha-kit/skills/uscha-adr-refine/SKILL.md +2 -2
- package/uscha-kit/skills/uscha-devloop/SKILL.md +3 -1
- package/uscha-kit/skills/uscha-devloop/qa_ledger.py +729 -155
- package/uscha-kit/skills/uscha-mirador/SKILL.md +22 -7
- package/uscha-kit/skills/uscha-mirador/mirador-render.py +44 -5
- package/uscha-kit/skills/uscha-mirador/mirador-watch.ps1 +1 -1
- package/uscha-kit/skills/uscha-mirador/mirador-watch.sh +1 -1
- package/uscha-kit/skills/uscha-mirador/mirador.template.html +666 -586
- package/uscha-kit/templates/CONSTITUTION.md +4 -4
- package/uscha-kit/templates/docs/adr/README.md +19 -19
- package/uscha-kit/tests/ledger-integrity-regressions.py +136 -0
- package/uscha-kit/tests/smoke-engine.sh +1312 -29
- package/uscha-kit/uscha.config.json +1 -1
- package/uscha-kit/workbench-doctor.sh +47 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "uscha",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.43.0",
|
|
5
5
|
"displayName": "Uscha",
|
|
6
6
|
"description": "Spec-driven development for LLM coding agents: 8 skills (discovery, adr-refine, reverse-discovery, characterize, devloop, sysdoc, rubric, mirador) + a stdlib measurement engine (qa_ledger.py, 29 subcommands + universal installer + npm/npx router). Facts block, guesses advise; the human approves.",
|
|
7
7
|
"author": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# uscha-kit 1.41.0 — safety release
|
|
2
|
+
|
|
3
|
+
Significant backwards-compatible release covering WU1–WU7.
|
|
4
|
+
|
|
5
|
+
- **WU1:** measured `pr-ready`, fail-closed Ruff/JUnit schemas, and validated counters.
|
|
6
|
+
- **WU2:** safe init, authoritative doctor, portable active Claude hook, marketplace preflight, and staged rollback.
|
|
7
|
+
- **WU3:** evidence-bearing PF/SD/SCR closure, config validation, and monotonic iterations/counters.
|
|
8
|
+
- **WU4:** integration readiness heterogeneous-event false-green prevention, unknown escalation repo rejection, and Spanish ADR label folding.
|
|
9
|
+
- **WU5:** ADR templates use AC IDs; the resolved constitution blocker example includes `--escape-analysis`.
|
|
10
|
+
- **WU6:** npm router probes usable Python >=3.8 before one installer invocation with no retry; workbench-doctor uses portable Python and the current skill roster.
|
|
11
|
+
- **WU7:** complete Claude installation transaction with rollback across managed skills, hook, settings, and marker; T77 covers existing and absent marker rollback.
|
|
12
|
+
- **P0 hardening:** Mirador script/DOM injection removed; structured static reports including Clippy fail closed; stale JUnit evidence cannot satisfy `pr-ready`.
|
|
13
|
+
- **P1 installer hardening:** init preflights all targets and rejects symlinks; Codex restores marketplace state during rollback; hook matcher and malformed Claude settings are validated.
|
|
14
|
+
- **P1 ledger hardening:** readiness configuration is validated completely and PF/SD/SCR closure is immutable after its first resolution.
|
|
15
|
+
- **Documentation truth-pass:** exact 29-command reference, npx-first Codex/Claude adoption, eight-skill inventory, completed EN twins, and refreshed diagrams.
|
|
16
|
+
- Smoke suite: **351/351 green**.
|
|
17
|
+
|
|
18
|
+
Known boundary: Codex and Claude targets are independently transactional; `--target both` remains sequential rather than cross-target atomic.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# uscha-kit 1.41.1 — adversarial-review hardening (2026-07-11)
|
|
2
|
+
|
|
3
|
+
An independent adversarial review of the 1.41.0 "safety hardening" release (4 parallel
|
|
4
|
+
reviewers, each tasked to REFUTE the safety claims) confirmed three real defects — two of
|
|
5
|
+
them in the engine's core "measured beats narrated" promise. Fixed here, each with a
|
|
6
|
+
regression check that fails without the fix. Smoke suite: 355/355.
|
|
7
|
+
|
|
8
|
+
## Fixes
|
|
9
|
+
|
|
10
|
+
### 1 — `pr-ready` accepted a JUnit that LIES (HIGH, core-promise)
|
|
11
|
+
`_junit_counts` read `tests`/`failures`/`errors` from the `<testsuite>` **attributes** and
|
|
12
|
+
never reconciled them against the actual `<testcase>`/`<failure>`/`<error>` **elements**. A
|
|
13
|
+
report declaring `failures="0"` while containing a real `<failure>` element read as all-green
|
|
14
|
+
and could satisfy `pr-ready`. Fix: honor the child elements, fail-closed —
|
|
15
|
+
`failures = max(attr, element_failures)`, same for errors. A present failure can no longer be
|
|
16
|
+
attribute-declared away. Attribute-only summary suites (no `<testcase>` elements — the form
|
|
17
|
+
many emitters legitimately use) keep their counts, so real adapters are unaffected.
|
|
18
|
+
`qa_ledger.py:_junit_counts`. Regression: smoke **T69b**.
|
|
19
|
+
|
|
20
|
+
### 2 — integration readiness trusted the single last event (MEDIUM-HIGH, core-promise)
|
|
21
|
+
The integration dimension read `integ_steps[-1]`, so a trailing green test-only step masked
|
|
22
|
+
an earlier FAILING integration gate (dim → 1.0). Fix: green now requires **0 open gated
|
|
23
|
+
findings across the latest record per integration tool** AND the latest test event passing —
|
|
24
|
+
so a failing gate is not masked, while a same-tool re-run that clears the gate is still seen.
|
|
25
|
+
`qa_ledger.py:cmd_readiness`. Regression: smoke **T69c**. (The 1.41.0 CHANGELOG claimed WU4
|
|
26
|
+
fixed this; the code still used `integ_steps[-1]` — the claim was inaccurate.)
|
|
27
|
+
|
|
28
|
+
### 3 — Codex install rollback destroyed the pre-existing plugin (HIGH, data loss)
|
|
29
|
+
`install_codex` gated its restore on `swapped` (only true after BOTH the backup-move and the
|
|
30
|
+
install-move succeeded), then the `finally` deleted the backup unconditionally. If the
|
|
31
|
+
`stage → plugin_root` swap failed after the original was moved to backup (a real Windows AV /
|
|
32
|
+
locked-handle failure on reinstall), the restore was skipped and the `finally` deleted the
|
|
33
|
+
only surviving copy — silently. Fix: gate the restore on the **backup existing** (not on
|
|
34
|
+
`swapped`), and drop the backup only on SUCCESS (never in `finally`), so a failure restores
|
|
35
|
+
the original and a hard interrupt leaves it intact. Mirrors the Claude path, which already did
|
|
36
|
+
this. `install-uscha.py:install_codex`. Regression: smoke **T77b**. (This is exactly the
|
|
37
|
+
"rollback leaves partial state" category 1.41.0 claimed to close — it closed it for Claude,
|
|
38
|
+
not Codex.)
|
|
39
|
+
|
|
40
|
+
## Honest limits (not fixed here, by design)
|
|
41
|
+
- A JUnit `<testsuite tests="3"/>` with ZERO `<testcase>` elements is still credited as 3
|
|
42
|
+
tests. This is the same trust the engine extends to any tool-emitted summary (a coverage %
|
|
43
|
+
in a coverage report), and closing it would reject the legitimate attribute-only reports
|
|
44
|
+
many emitters produce. The defense against a **forged** bare report is the "evidence
|
|
45
|
+
captured by execution" invariant (the SKILL runs the real test command; the agent does not
|
|
46
|
+
hand-write the XML) + the human merge gate — not per-report forgery detection.
|
|
47
|
+
|
|
48
|
+
## Also
|
|
49
|
+
- `docs/skills-referencia.html` + `-EN.html`: stale "24 subcommands" → 29 (truth-pass).
|
|
50
|
+
|
|
51
|
+
## Note on the test suite
|
|
52
|
+
The installer/npm smoke checks hardcode the version string, so a version bump requires
|
|
53
|
+
updating those literals (done here). A follow-up could have them read `VERSION` dynamically.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# uscha-kit 1.41.2 — mirador launch UX (2026-07-18)
|
|
2
|
+
|
|
3
|
+
A usability release for the mirador (the bird's-eye dashboard). No engine measurement
|
|
4
|
+
logic changed; this makes the mirador honest about "not ready" and trivial to launch from
|
|
5
|
+
inside a running project — "nada de magia oculta". Smoke suite: 357/357.
|
|
6
|
+
|
|
7
|
+
## Fixes
|
|
8
|
+
|
|
9
|
+
### 1 — "NOT READY" no longer reads as "hasn't started" (readiness title)
|
|
10
|
+
The mirador mapped the `NOT READY` band (score 0–49) to a fixed title `"Todavia no arranca"`
|
|
11
|
+
("hasn't started yet"). But a project at, say, readiness 22 HAS started — it simply lacks
|
|
12
|
+
enough **measured** evidence. The wording contradicted the score right next to it. Fix: the
|
|
13
|
+
`NOT READY` title is now score-aware — `"Todavia sin evidencia medida"` only at score 0, and
|
|
14
|
+
`"En construccion -- evidencia insuficiente"` above 0. The dead fixed entry was removed from
|
|
15
|
+
`_MIRADOR_TITLE` so the old wording cannot reappear. `qa_ledger.py:cmd_dashboard`.
|
|
16
|
+
Regression: smoke **T78**.
|
|
17
|
+
|
|
18
|
+
## Launch UX
|
|
19
|
+
|
|
20
|
+
### 2 — `mirador-render.py` self-resolves its siblings
|
|
21
|
+
`--engine` (the `qa_ledger.py` path) and `--template` (the mirador HTML) now default to the
|
|
22
|
+
renderer's **sibling** skill files. From any project you can run the renderer — or
|
|
23
|
+
`/uscha-mirador` — with just `--ledger`, no long absolute paths. `mirador-render.py:main`.
|
|
24
|
+
|
|
25
|
+
### 3 — the rendered mirador opens itself, and always prints where it is
|
|
26
|
+
After writing `mirador.html` the renderer opens it in the default browser (best-effort:
|
|
27
|
+
`os.startfile` on Windows, `open`/`xdg-open` elsewhere — never fails on headless/CI) and
|
|
28
|
+
prints the **absolute path** on an `OPEN IT:` line. A new `--no-open` flag suppresses the
|
|
29
|
+
auto-open; the live-watch loop (`mirador-watch.sh`/`.ps1`) and the smoke suite pass it so
|
|
30
|
+
they never spawn browser tabs on every refresh. `mirador-render.py`.
|
|
31
|
+
|
|
32
|
+
## Note on the test suite
|
|
33
|
+
The installer/npm smoke checks still hardcode the version string, so this bump updated those
|
|
34
|
+
literals (T44, T66/T67 assertions). A follow-up could have them read `VERSION` dynamically.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# uscha-kit 1.41.3 — mirador live-view no longer spams browser tabs (2026-07-18)
|
|
2
|
+
|
|
3
|
+
A hotfix for a regression shipped in 1.41.2. Smoke suite: 358/358.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
### mirador-render auto-open + `--refresh` spawned a new browser tab every cycle (HIGH, regression)
|
|
8
|
+
1.41.2 made `mirador-render.py` auto-open the rendered file in the browser. But the live
|
|
9
|
+
second-screen view (`mirador-watch`, and any render with `--refresh N`) injects a
|
|
10
|
+
`<meta http-equiv="refresh">` so a single open tab **reloads itself** every N seconds — and
|
|
11
|
+
the renderer is re-invoked each cycle. Auto-opening on every invocation therefore spawned a
|
|
12
|
+
**new browser tab on every refresh** (30s → a wall of tabs), making the machine unusable while
|
|
13
|
+
a watch loop ran. The `--no-open` flag was not enough on its own: a watch process started
|
|
14
|
+
before 1.41.2 calls the renderer without it.
|
|
15
|
+
|
|
16
|
+
Fix: auto-open is now suppressed whenever `--refresh > 0` (live mode) — the meta-refresh owns
|
|
17
|
+
the reload, in one tab. Auto-open remains for a genuine **one-shot** render (`/uscha-mirador`
|
|
18
|
+
with no `--refresh`), and `--no-open` still suppresses it everywhere. The `OPEN IT: <abs path>`
|
|
19
|
+
line is always printed, so the live view is one manual open away and never hidden.
|
|
20
|
+
`mirador-render.py:main`. Regression: smoke **T79** (live → 0 opens, one-shot → 1, `--no-open`
|
|
21
|
+
→ 0).
|
|
22
|
+
|
|
23
|
+
Because the renderer is a fresh subprocess each cycle, a running watch loop picks up this fix
|
|
24
|
+
on its **next** render with no restart — and for a link/junction skill install (the renderer
|
|
25
|
+
lives in this repo), no reinstall either. A copy-mode install needs a reinstall to get the
|
|
26
|
+
fixed file.
|
|
27
|
+
|
|
28
|
+
## Note on the test suite
|
|
29
|
+
The installer/npm smoke checks still hardcode the version string, so this bump updated those
|
|
30
|
+
literals. A follow-up could have them read `VERSION` dynamically.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# uscha-kit 1.42.0 — the mirador answers "how's it going / what's blocking / what's next" (2026-07-18)
|
|
2
|
+
|
|
3
|
+
Until now the mirador showed the project's SKELETON — the phase trail, the counters, the
|
|
4
|
+
invariant names — but a real early-stage project rendered as a wall of empty-looking cards
|
|
5
|
+
that left you with "sabor a nada": you could not tell, at a glance, how it was going, what was
|
|
6
|
+
blocking it, or what to do next. This release makes the mirador lead with exactly those three
|
|
7
|
+
answers — and every one of them is **measured**, not narrated. Smoke suite: 359/359.
|
|
8
|
+
|
|
9
|
+
## The status story (hero block)
|
|
10
|
+
|
|
11
|
+
A three-line block sits under the verdict, each line derived purely from fields the engine
|
|
12
|
+
already emits in `dashboard --json` (no new engine logic, still model-agnostic):
|
|
13
|
+
|
|
14
|
+
- **Cómo viene** — the measured sub-scores, verbatim: e.g. `coverage 0% · simplicity FAIL`.
|
|
15
|
+
- **Qué lo traba** — the hard blockers, each traceable to a measured field: failing gates
|
|
16
|
+
(sub-scores reading FAIL/MISS), the readiness cap (`readiness.sub`), open discovery intake
|
|
17
|
+
(production findings / spec doubts / spec change requests), and expired/malformed ADR
|
|
18
|
+
experiments. A failing gate is NOT double-reported as its flipped CONSTITUTION invariant.
|
|
19
|
+
When nothing blocks, it says so and names the dimensions still lacking measured evidence.
|
|
20
|
+
- **Qué sigue** — the active phase in the derived FSM plus its method and execution hint
|
|
21
|
+
(`tier` / `model` / `effort`), so the operator sees the next concrete move.
|
|
22
|
+
|
|
23
|
+
`mirador.template.html:renderStatus`. Regression: smoke **T80**.
|
|
24
|
+
|
|
25
|
+
## Empty cards earn their place
|
|
26
|
+
|
|
27
|
+
Cards no longer render as dead space when a real project has nothing for them yet:
|
|
28
|
+
|
|
29
|
+
- **The 6 layers of truth** (`capas`) — the engine never feeds this for a real project (it was
|
|
30
|
+
demo-only), so the whole card now HIDES when empty instead of showing an empty grid.
|
|
31
|
+
- **Specifications / ADRs / QA loops** — when empty, show a one-line hint of what fills them
|
|
32
|
+
and in which phase, instead of a blank list or a bare `0/0`.
|
|
33
|
+
|
|
34
|
+
## Safety
|
|
35
|
+
All status/hint DOM is built with `textContent` / `createTextNode` (no `innerHTML`), so the
|
|
36
|
+
1.41.0 Mirador XSS hardening still holds — smoke P0-A (script-context escaping, no HTML sinks)
|
|
37
|
+
stays green.
|
|
38
|
+
|
|
39
|
+
## Note on the test suite
|
|
40
|
+
The installer/npm smoke checks still hardcode the version string, so this bump updated those
|
|
41
|
+
literals. A follow-up could have them read `VERSION` dynamically.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# uscha-kit 1.43.0 — `uscha mirador`: one command, no python, no paths (2026-07-18)
|
|
2
|
+
|
|
3
|
+
Adoption fix. Bringing up the mirador for a running project meant typing
|
|
4
|
+
`python <long-skill-path>/mirador-render.py --ledger QA-LEDGER.json` — friction that pushed
|
|
5
|
+
users away. The kit already had an npm/npx router (`bin/uscha.js`) forwarding to
|
|
6
|
+
`install-uscha.py`; it was missing one verb. Smoke suite: 361/361.
|
|
7
|
+
|
|
8
|
+
## New: the `mirador` verb
|
|
9
|
+
|
|
10
|
+
From the root of any project that has a `QA-LEDGER.json`:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
uscha mirador # render + open the dashboard
|
|
14
|
+
uscha mirador --watch # live second-screen view (auto-refresh, one tab)
|
|
15
|
+
npx @andresmassello/uscha mirador # same, zero install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
No python, no paths, no flags required. The verb:
|
|
19
|
+
- resolves the renderer inside the kit (either skill-tree layout), which self-resolves its own
|
|
20
|
+
engine + template siblings;
|
|
21
|
+
- defaults the ledger to the `QA-LEDGER.json` convention in the current directory
|
|
22
|
+
(`--ledger` to point elsewhere);
|
|
23
|
+
- one-shot renders and opens the file; `--watch` opens ONE self-reloading tab and re-renders
|
|
24
|
+
every `--interval` seconds (default 30) WITHOUT re-opening — no browser-tab spam (honors the
|
|
25
|
+
1.41.3 live-mode rule);
|
|
26
|
+
- fails clearly (exit 1) when the ledger is missing, instead of a stack trace.
|
|
27
|
+
|
|
28
|
+
`install-uscha.py:cmd_mirador` (exposed through the existing `bin/uscha.js` router).
|
|
29
|
+
Regression: smoke **T81**.
|
|
30
|
+
|
|
31
|
+
## Docs
|
|
32
|
+
`INSTALL.md` gains a "See the dashboard (mirador)" section; the uscha-mirador `SKILL.md`
|
|
33
|
+
leads its human/terminal path with `uscha mirador`.
|
|
34
|
+
|
|
35
|
+
## Note on the test suite
|
|
36
|
+
The installer/npm smoke checks still hardcode the version string, so this bump updated those
|
|
37
|
+
literals. A follow-up could have them read `VERSION` dynamically.
|
package/uscha-kit/INSTALL.md
CHANGED
|
@@ -1,101 +1,120 @@
|
|
|
1
|
-
# Install Uscha
|
|
2
|
-
|
|
3
|
-
Uscha installs as a machine-level helper for coding agents. The recommended path
|
|
4
|
-
is npm/npx because it works the same on a fresh Codex or Claude Code machine.
|
|
5
|
-
|
|
6
|
-
## Quick path
|
|
7
|
-
|
|
8
|
-
### Codex Desktop
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npx --yes @andresmassello/uscha@latest version
|
|
12
|
-
npx --yes @andresmassello/uscha@latest install --target codex --dry-run
|
|
13
|
-
npx --yes @andresmassello/uscha@latest install --target codex
|
|
14
|
-
npx --yes @andresmassello/uscha@latest doctor --target codex
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Then restart Codex or open a new thread. The installer registers Uscha as a
|
|
18
|
-
personal local plugin under `~/plugins/uscha` and updates
|
|
19
|
-
`~/.agents/plugins/marketplace.json`.
|
|
20
|
-
|
|
21
|
-
### Claude Code
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npx --yes @andresmassello/uscha@latest install --target claude --dry-run
|
|
25
|
-
npx --yes @andresmassello/uscha@latest install --target claude
|
|
26
|
-
npx --yes @andresmassello/uscha@latest doctor --target claude
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
This installs the `uscha-*` skills and
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
npx --yes @andresmassello/uscha@latest install --target both
|
|
36
|
-
npx --yes @andresmassello/uscha@latest
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
npx --yes @andresmassello/uscha@latest init --repo .
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
`
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
/
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
1
|
+
# Install Uscha
|
|
2
|
+
|
|
3
|
+
Uscha installs as a machine-level helper for coding agents. The recommended path
|
|
4
|
+
is npm/npx because it works the same on a fresh Codex or Claude Code machine.
|
|
5
|
+
|
|
6
|
+
## Quick path
|
|
7
|
+
|
|
8
|
+
### Codex Desktop
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx --yes @andresmassello/uscha@latest version
|
|
12
|
+
npx --yes @andresmassello/uscha@latest install --target codex --dry-run
|
|
13
|
+
npx --yes @andresmassello/uscha@latest install --target codex
|
|
14
|
+
npx --yes @andresmassello/uscha@latest doctor --target codex
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then restart Codex or open a new thread. The installer registers Uscha as a
|
|
18
|
+
personal local plugin under `~/plugins/uscha` and updates
|
|
19
|
+
`~/.agents/plugins/marketplace.json`. It preflights that marketplace before replacing the plugin tree and writes the install marker last.
|
|
20
|
+
|
|
21
|
+
### Claude Code
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx --yes @andresmassello/uscha@latest install --target claude --dry-run
|
|
25
|
+
npx --yes @andresmassello/uscha@latest install --target claude
|
|
26
|
+
npx --yes @andresmassello/uscha@latest doctor --target claude
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This installs the `uscha-*` skills and registers a portable Python `PreToolUse` hook under `~/.claude` while preserving unrelated `settings.json` entries. Restart or reload Claude Code after installing.
|
|
30
|
+
|
|
31
|
+
### Same machine uses both
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx --yes @andresmassello/uscha@latest install --target both --dry-run
|
|
35
|
+
npx --yes @andresmassello/uscha@latest install --target both
|
|
36
|
+
npx --yes @andresmassello/uscha@latest doctor --target both
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Prepare a project repo
|
|
40
|
+
|
|
41
|
+
After the machine install, initialize each project where Uscha should govern the
|
|
42
|
+
workflow:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx --yes @andresmassello/uscha@latest init --repo . --dry-run
|
|
46
|
+
npx --yes @andresmassello/uscha@latest init --repo .
|
|
47
|
+
# Existing differing files are preserved; use --force only to replace them deliberately.
|
|
48
|
+
npx --yes @andresmassello/uscha@latest init --repo . --force
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`init` exits nonzero and reports conflicts for differing `uscha.config.json`, `CLAUDE.md`, `CONSTITUTION.md`, or `.gitattributes`; `--dry-run` performs the same conflict check without writing.
|
|
52
|
+
|
|
53
|
+
Project state stays in the project: `uscha.config.json`, `QA-LEDGER.json`,
|
|
54
|
+
`ACCEPTANCE.md`, and approved golden fixtures when used.
|
|
55
|
+
|
|
56
|
+
## See the dashboard (mirador)
|
|
57
|
+
|
|
58
|
+
From the root of any project that has a `QA-LEDGER.json`, one command renders the mirador and
|
|
59
|
+
opens it — no python, no paths:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx --yes @andresmassello/uscha@latest mirador # one glance: render + open
|
|
63
|
+
npx --yes @andresmassello/uscha@latest mirador --watch # live second-screen view (auto-refresh)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It defaults to the `QA-LEDGER.json` convention in the current directory (pass `--ledger` to
|
|
67
|
+
point elsewhere) and prints the absolute path it wrote. `--watch` re-renders every `--interval`
|
|
68
|
+
seconds (default 30) into one self-reloading tab.
|
|
69
|
+
|
|
70
|
+
## Requirements
|
|
71
|
+
|
|
72
|
+
| Requirement | Why |
|
|
73
|
+
|-------------|-----|
|
|
74
|
+
| Node.js + npm | Runs the universal `npx` entrypoint. |
|
|
75
|
+
| Python 3.8+ | Runs the canonical stdlib installer and engine. |
|
|
76
|
+
| Git | Used by the method and by project setup checks. |
|
|
77
|
+
| Codex Desktop and/or Claude Code | The agent runtime you want to install Uscha into. |
|
|
78
|
+
|
|
79
|
+
No `pip install` is required. The engine is Python stdlib-only.
|
|
80
|
+
|
|
81
|
+
## Other install options
|
|
82
|
+
|
|
83
|
+
| Option | Use when | Tradeoff |
|
|
84
|
+
|--------|----------|----------|
|
|
85
|
+
| `npx @andresmassello/uscha@latest ...` | Normal install/update on any machine. | Requires npm registry access. |
|
|
86
|
+
| Git checkout + `python uscha-kit/install-uscha.py ...` | Developing Uscha itself or testing unreleased changes. | You must clone/pull the repo yourself. |
|
|
87
|
+
| `--mode link` from a checkout | This machine develops the kit and installed skills should follow local edits. | Links are great for development, risky for normal users. |
|
|
88
|
+
| Claude Code plugin commands | You specifically want Claude Code's native plugin flow. | Codex still needs the npm/git installer path. |
|
|
89
|
+
| Manual copy | Debugging the installer. | Easy to drift; not recommended for adoption. |
|
|
90
|
+
|
|
91
|
+
Development checkout example:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/andresmassello/uscha.git
|
|
95
|
+
cd uscha
|
|
96
|
+
python uscha-kit/install-uscha.py install --target both --mode link --dry-run
|
|
97
|
+
python uscha-kit/install-uscha.py install --target both --mode link
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Claude Code plugin option:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
/plugin marketplace add andresmassello/uscha
|
|
104
|
+
/plugin install uscha@uscha
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Update and verify
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm view @andresmassello/uscha version
|
|
111
|
+
npx --yes @andresmassello/uscha@latest version
|
|
112
|
+
npx --yes @andresmassello/uscha@latest install --target both
|
|
113
|
+
npx --yes @andresmassello/uscha@latest doctor --target both
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`doctor` exits 1 for any unhealthy target in either text or `--json` mode. It checks installed skill presence, manifest/marketplace or hook registration, marker, and version; it does not measure file-content integrity.
|
|
117
|
+
|
|
118
|
+
If `npm view` returns `404` immediately after a new release, wait a few minutes:
|
|
119
|
+
npm search/dist-tags can propagate before the package metadata endpoint used by
|
|
120
|
+
`npx`. Do not republish the same version while propagation is in progress.
|
package/uscha-kit/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# uscha-kit
|
|
2
2
|
|
|
3
|
-
**Kit version:** v1.
|
|
3
|
+
**Kit version:** v1.43.0 <!-- uscha:version -->
|
|
4
4
|
|
|
5
5
|
Spec-driven orchestrator + multi-repo QA for Claude Code, with a deterministic ledger.
|
|
6
6
|
**Eight skills** (`uscha-discovery`, `uscha-adr-refine`, `uscha-devloop`, `uscha-sysdoc`, `uscha-reverse-discovery`,
|
|
@@ -130,8 +130,11 @@ BEFORE touching anything.
|
|
|
130
130
|
| test count | `cargo nextest run` + copy (see note) | `reports/junit.xml` (wrapped JUnit supported) |
|
|
131
131
|
| clippy | `cargo clippy --message-format=json > reports/clippy.json` | `reports/clippy.json` (JSONL: error→HIGH · warning→MEDIUM · `code:null` compile-error→HIGH; summaries without span ignored) |
|
|
132
132
|
|
|
133
|
-
`ingest-gate` with explicit `--clippy` or by type.
|
|
134
|
-
|
|
133
|
+
`ingest-gate` with explicit `--clippy` or by type. Its JSONL evidence is fail-closed:
|
|
134
|
+
each nonblank line must be a UTF-8 Cargo JSON object with a string `reason`; malformed
|
|
135
|
+
records or malformed compiler diagnostics are rejected before ledger mutation. An empty
|
|
136
|
+
file plus valid Cargo summaries and span-less diagnostic summaries remain clean/noise.
|
|
137
|
+
The inline `#[cfg(test)]` tests count as prod LOC (documented limitation); `tests/` = integration.
|
|
135
138
|
**Watch out for junit**: nextest does NOT emit JUnit by default — you have to enable it in
|
|
136
139
|
`.config/nextest.toml` (`[profile.default.junit] path = "junit.xml"`) and the file
|
|
137
140
|
lands in `target/nextest/default/junit.xml`; copy it to `reports/junit.xml`
|
|
@@ -166,6 +169,13 @@ BEFORE touching anything.
|
|
|
166
169
|
Bazel/make) belongs to the per-repo adapter — the kit only requires that the reports exist.
|
|
167
170
|
`cmake-build-*` (any CLion profile) and `_deps` are excluded from the LOC.
|
|
168
171
|
|
|
172
|
+
**Text-report boundary:** mypy, tsc, and clang-tidy ingest only their recognized diagnostic
|
|
173
|
+
lines. Their legitimate clean/noise forms include status/success text, tool summaries, and
|
|
174
|
+
(for clang-tidy) passed-through compiler output, so a nonempty unmatched line is not safely
|
|
175
|
+
distinguishable from a clean report. The kit deliberately does **not** invent fail-closed
|
|
176
|
+
heuristics for those text formats; use their structured output where a fail-closed schema is
|
|
177
|
+
required.
|
|
178
|
+
|
|
169
179
|
Kotlin/JVM with Gradle (`type: gradle`, kit 1.9.0) — **Kotlin over Maven already
|
|
170
180
|
works with `type: maven`** (`.kt` has always counted; JaCoCo/Surefire don't
|
|
171
181
|
distinguish JVM language). This type is for the common Gradle case:
|
|
@@ -287,7 +297,7 @@ claude --add-dir ../backend-api --add-dir ../mobile-app
|
|
|
287
297
|
Inside Claude Code, invoke the orchestrator (with the ADR/PLAN ready or ask it for one):
|
|
288
298
|
|
|
289
299
|
```
|
|
290
|
-
/
|
|
300
|
+
/uscha-devloop
|
|
291
301
|
```
|
|
292
302
|
|
|
293
303
|
The skill handles the phases on its own: plan → coverage gate → (characterization if needed)
|
|
@@ -327,7 +337,7 @@ result, not on effort spent**:
|
|
|
327
337
|
|
|
328
338
|
```bash
|
|
329
339
|
python3 $QL readiness --acceptance ACCEPTANCE.md
|
|
330
|
-
python3 $QL readiness --json # consumed by
|
|
340
|
+
python3 $QL readiness --json # consumed by uscha-sysdoc (traffic-light widget)
|
|
331
341
|
python3 $QL execution-policy --phase qa # one-line methodology/model/effort routing
|
|
332
342
|
python3 $QL production-finding --repo backend-api --severity HIGH --title "..." --evidence "..."
|
|
333
343
|
python3 $QL spec-doubt --repo backend-api --kind spec-wrong --note "..." --evidence "..."
|
|
@@ -371,7 +381,7 @@ python3 $QL rebuild --mode baseline --config uscha.config.json # → REBUILD-B
|
|
|
371
381
|
# SPEC/ADR/ACCEPTANCE, PRESERVING the tests, and run the suite.
|
|
372
382
|
# 3) score the regenerated tree against the baseline
|
|
373
383
|
python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json # exit 0 = COVERS
|
|
374
|
-
python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json --json # consumed by
|
|
384
|
+
python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json --json # consumed by uscha-sysdoc
|
|
375
385
|
```
|
|
376
386
|
|
|
377
387
|
- Dimensions/weights: tests 60, acceptance 20, coverage 15, surface 5. The dominant signal
|
|
@@ -388,7 +398,7 @@ The **Simplicity** invariant of the CONSTITUTION made a deterministic gate: it s
|
|
|
388
398
|
```bash
|
|
389
399
|
git diff --unified=0 <base> | python3 $QL simplicity-check --config uscha.config.json
|
|
390
400
|
python3 $QL simplicity-check --from-git --base main # uses git for you
|
|
391
|
-
python3 $QL simplicity-check --diff changes.diff --json # consumed by
|
|
401
|
+
python3 $QL simplicity-check --diff changes.diff --json # consumed by uscha-sysdoc / CI
|
|
392
402
|
```
|
|
393
403
|
|
|
394
404
|
- Dimensions/weights: diff_size 35, nesting 30, net_growth 20, fan_out 8, blob 7
|
|
@@ -403,10 +413,11 @@ python3 $QL simplicity-check --diff changes.diff --json # consumed by sys
|
|
|
403
413
|
|
|
404
414
|
## Ledger subcommands
|
|
405
415
|
|
|
406
|
-
`doctor
|
|
407
|
-
converged
|
|
408
|
-
|
|
409
|
-
|
|
416
|
+
`doctor - rubric-ingest - init - snapshot - check-coverage - log-step - ingest-gate - phase -
|
|
417
|
+
converged - oscillation - escalate - resolve-escalation - log-gate - flag-blocker -
|
|
418
|
+
production-finding - spec-doubt - spec-change-request - regression-check - summary - readiness -
|
|
419
|
+
execution-policy - dashboard - rebuild - simplicity-check - waste-check - pit-check - gate-check -
|
|
420
|
+
spec-check - golden-diff` - the exact current `qa_ledger.py` parser surface; each supports `--help`.
|
|
410
421
|
|
|
411
422
|
The **fact gates** (golden-diff, gate-check, pit-check, simplicity) are PERSISTED with
|
|
412
423
|
`log-gate`: a fail blocks convergence and caps readiness ≤65 via the ledger. A CONSTITUTION
|
|
@@ -453,5 +464,5 @@ Inside Claude Code, ask it:
|
|
|
453
464
|
List the active rules from CLAUDE.md and the available skills.
|
|
454
465
|
```
|
|
455
466
|
|
|
456
|
-
The protocol rules and the commands
|
|
457
|
-
|
|
467
|
+
The protocol rules and the commands `/uscha-discovery`, `/uscha-adr-refine`,
|
|
468
|
+
`/uscha-devloop`, and `/uscha-sysdoc` should appear. (For the machine's toolchain: `bash uscha-kit/workbench-doctor.sh`.)
|
package/uscha-kit/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
uscha-kit 1.
|
|
1
|
+
uscha-kit 1.43.0
|
package/uscha-kit/WORKBENCH.md
CHANGED
|
@@ -18,11 +18,23 @@ los linters del static gate, drivers) es el *adapter* del proyecto y vive en el
|
|
|
18
18
|
| **Python 3.8+** | corre `qa_ledger.py` (stdlib pura, sin dependencias) | `python3` en PATH |
|
|
19
19
|
| **git** | versionado | 2.x, con `user.name`/`user.email` |
|
|
20
20
|
| **gh** (GitHub CLI) | crear repo / abrir PR | opcional pero recomendado |
|
|
21
|
-
| **skills del kit** | `discovery`, `adr-refine`, `
|
|
21
|
+
| **skills del kit (8)** | `uscha-discovery`, `uscha-adr-refine`, `uscha-devloop`, `uscha-sysdoc`, `uscha-reverse-discovery`, `uscha-characterize`, `uscha-rubric`, `uscha-mirador` | instalados por `npx` en Codex y/o Claude Code |
|
|
22
22
|
| **skills de QA** | `code-review`, `judgment-day`, `improve` | tus skills globales (el dev-loop los **orquesta**, no los trae) |
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
|
+
## Camino feliz: instalar Uscha con npx
|
|
27
|
+
|
|
28
|
+
Uscha instala los skills y la configuracion para Codex, Claude Code o ambos:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx --yes @andresmassello/uscha@latest version
|
|
32
|
+
npx --yes @andresmassello/uscha@latest install --target both
|
|
33
|
+
npx --yes @andresmassello/uscha@latest doctor --target both
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`--target codex` o `--target claude` limita la instalacion a un solo entorno. Este es el camino recomendado y portable.
|
|
37
|
+
|
|
26
38
|
## 2. Instalar Claude Code
|
|
27
39
|
|
|
28
40
|
**Native installer (recomendado — no requiere Node, se auto-actualiza):**
|
|
@@ -87,6 +99,8 @@ gh auth login # habilita gh repo create / gh pr
|
|
|
87
99
|
|
|
88
100
|
## 5. Instalar los skills del kit
|
|
89
101
|
|
|
102
|
+
**Manual, avanzado/legacy (solo Claude Code; preferi `npx` arriba):**
|
|
103
|
+
|
|
90
104
|
**Global (todos los repos):**
|
|
91
105
|
|
|
92
106
|
```bash
|
|
@@ -102,14 +116,14 @@ cp -r uscha-kit/.claude/skills <repo>/.claude/
|
|
|
102
116
|
cp uscha-kit/uscha.config.json <repo>/ # config en la raíz del repo
|
|
103
117
|
```
|
|
104
118
|
|
|
105
|
-
**Verificar:**
|
|
106
|
-
`/adr-refine`, `/
|
|
119
|
+
**Verificar:** abra `claude` y mire `/help`: deberian aparecer `/uscha-discovery`,
|
|
120
|
+
`/uscha-adr-refine`, `/uscha-devloop`, `/uscha-sysdoc` y las otras cuatro skills del kit. O `ls ~/.claude/skills`.
|
|
107
121
|
|
|
108
122
|
---
|
|
109
123
|
|
|
110
124
|
## 6. Los skills de QA externos (dependencia)
|
|
111
125
|
|
|
112
|
-
El `
|
|
126
|
+
El `uscha-devloop` **orquesta** `code-review` / `judgment-day` / `improve` — **no los empaqueta**.
|
|
113
127
|
Tienen que estar en `~/.claude/skills/` (tus skills globales). Si usás otros nombres,
|
|
114
128
|
editá `qa_tools_order` en `uscha.config.json`. Si no los tenés, el loop no encuentra
|
|
115
129
|
las tools de juicio (igual corre el static gate determinístico).
|
|
@@ -173,6 +187,6 @@ claude whoami # cuenta autenticada
|
|
|
173
187
|
- [ ] `python3 --version` ≥ 3.8
|
|
174
188
|
- [ ] git configurado (`user.name` / `user.email`)
|
|
175
189
|
- [ ] `gh auth login` hecho (si vas a abrir PRs)
|
|
176
|
-
- [ ] `/discovery` `/adr-refine` `/
|
|
190
|
+
- [ ] `/uscha-discovery` `/uscha-adr-refine` `/uscha-devloop` `/uscha-sysdoc` aparecen en `/help`
|
|
177
191
|
- [ ] `code-review` / `judgment-day` / `improve` presentes (o `qa_tools_order` ajustado)
|
|
178
192
|
- [ ] `uscha.config.json` en la raíz del repo
|