luciazero 2.0.2 → 2.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 +30 -0
- package/README.md +20 -11
- package/README.th.md +19 -11
- package/agents/reviewer.md +49 -0
- package/bin/discipline-report.js +35 -0
- package/claude/hooks/hooks.json +36 -0
- package/claude/hooks/luciazero-statusline.sh +17 -2
- package/claude/hooks/luciazero-verify.sh +157 -18
- package/claude/luciazero.md +2 -2
- package/install-codex.sh +6 -2
- package/install.sh +17 -7
- package/package.json +3 -2
- package/skills/aliases.txt +2 -0
- package/skills/catalog.txt +2 -1
- package/skills/debug/SKILL.md +1 -1
- package/skills/discipline-report/SKILL.md +3 -1
- package/skills/done/SKILL.md +1 -1
- package/skills/done/scripts/revert-probe.sh +1 -1
- package/skills/luciazero-bootstrap/SKILL.md +5 -104
- package/skills/plan/SKILL.md +1 -1
- package/skills/ready/SKILL.md +109 -0
- package/skills/{luciazero-bootstrap → ready}/scripts/detect.sh +1 -1
- package/skills/show/SKILL.md +133 -0
- package/skills/show/agents/openai.yaml +4 -0
- package/uninstall-codex.sh +5 -1
- package/uninstall.sh +6 -2
- /package/skills/{luciazero-bootstrap → ready}/references/smart-verification.md +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,36 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.1.0] - 2026-08-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `/show` turns code relationships, structural changes, and verification
|
|
15
|
+
evidence into the smallest useful traceable visual.
|
|
16
|
+
- `./test.sh --fast` provides a measured intermediate tier while the default
|
|
17
|
+
and `--full` preserve complete CI/closeout coverage.
|
|
18
|
+
- Opt-in Claude hooks use private per-session scratch state to record
|
|
19
|
+
privacy-preserving aggregate turn/merged-Bash wall time and Bash, failed or
|
|
20
|
+
successful verify, and model/user skill counts; `luciazero discipline`
|
|
21
|
+
summarizes them.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- `/luciazero-bootstrap` is now `/ready`. The old command remains as a
|
|
26
|
+
deprecated compatibility alias for one release.
|
|
27
|
+
- The doctrine reserves full verification for closeout, and `/plan` plus
|
|
28
|
+
`/debug` no longer auto-trigger for routine edits or first obvious failures.
|
|
29
|
+
|
|
30
|
+
## [2.0.3] - 2026-08-13
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- The Claude plugin now exposes its reviewer from the default root `agents/`
|
|
35
|
+
directory. Claude Code 2.1.227 validated the former custom manifest path but
|
|
36
|
+
reported and loaded zero agents; the default layout reports one. CI requires
|
|
37
|
+
the plugin mirror to match the classic install source byte-for-byte and
|
|
38
|
+
prevents the custom path from returning.
|
|
39
|
+
|
|
10
40
|
## [2.0.2] - 2026-08-13
|
|
11
41
|
|
|
12
42
|
### Fixed
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ of handing back work they merely believe is finished.
|
|
|
16
16
|
> Done is proven by a command, not by my judgment. If no verification command
|
|
17
17
|
> exists, that is the first bug.
|
|
18
18
|
|
|
19
|
-
It ships a compact [9-rule doctrine](claude/luciazero.md),
|
|
19
|
+
It ships a compact [9-rule doctrine](claude/luciazero.md), 10 on-demand skills,
|
|
20
20
|
verification hooks, a risk-routed reviewer, and an eval harness. It is a
|
|
21
21
|
discipline layer, not an agent runtime or overnight orchestrator.
|
|
22
22
|
|
|
@@ -83,7 +83,7 @@ Carries the doctrine, all skills, reviewer, and verify-tracking hooks:
|
|
|
83
83
|
/plugin install luciazero@luciazero
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Start a repository with `/luciazero:
|
|
86
|
+
Start a repository with `/luciazero:ready`. Plugin skills use the
|
|
87
87
|
`/luciazero:` prefix. The plugin has no statusline because Claude Code plugins
|
|
88
88
|
cannot set one.
|
|
89
89
|
|
|
@@ -93,7 +93,8 @@ cannot set one.
|
|
|
93
93
|
npx skills add ohm41321/luciazero
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
This installs the
|
|
96
|
+
This installs the 10 skills plus the temporary `/luciazero-bootstrap`
|
|
97
|
+
compatibility alias: no doctrine, reviewer, or hooks.
|
|
97
98
|
|
|
98
99
|
### Classic Claude Code and Codex
|
|
99
100
|
|
|
@@ -140,14 +141,15 @@ Claude Code can auto-update the plugin at startup: open `/plugin` →
|
|
|
140
141
|
marketplaces leave this off by default. For release-only notifications, use
|
|
141
142
|
GitHub **Watch → Custom → Releases**.
|
|
142
143
|
|
|
143
|
-
## The
|
|
144
|
+
## The 10 skills
|
|
144
145
|
|
|
145
|
-
Run `/
|
|
146
|
+
Run `/ready` first; the rest activate when their moment arrives.
|
|
146
147
|
|
|
147
148
|
| Moment | Skill | Result |
|
|
148
149
|
|---|---|---|
|
|
149
|
-
| Entering a repository | `/
|
|
150
|
-
|
|
|
150
|
+
| Entering a repository | `/ready` | Finds or creates a verify command and proves it can fail |
|
|
151
|
+
| Structure or evidence is hard to scan | `/show` | Maps connections, changes, and proof into the smallest useful visual |
|
|
152
|
+
| Before risky, ambiguous, or multi-module work | `/plan` | Fixes scope and observable acceptance evidence |
|
|
151
153
|
| A bug survives the first look | `/debug` | Reproduction, hypothesis ledger, regression test |
|
|
152
154
|
| Good and bad revisions are known | `/bisect` | Finds the first bad commit in a temporary worktree |
|
|
153
155
|
| Before claiming completion | `/done` | Full verify, skeptic review, scope report |
|
|
@@ -205,6 +207,9 @@ only one run per arm per task. See the [full benchmark](docs/benchmark.md),
|
|
|
205
207
|
- Core installers, hooks, helpers, and graders are offline. Real behavioral
|
|
206
208
|
evals invoke a model CLI and consume API credit or subscription quota.
|
|
207
209
|
- Hooks run commands on your machine. Read them before enabling them.
|
|
210
|
+
- Hook telemetry stays local in private per-session state and records aggregate
|
|
211
|
+
turn/Bash wall time plus Bash, verify, and model/user skill counts—never raw
|
|
212
|
+
commands, skill names, or paths.
|
|
208
213
|
- Set `LUCIAZERO_VERIFY_CMD` to the repo's exact fast verify command.
|
|
209
214
|
- Put `LUCIAZERO_STRICT_VERIFY_CMD` only in personal settings, never in a
|
|
210
215
|
committed repository config. Strict mode fails open on internal errors.
|
|
@@ -214,12 +219,16 @@ See [SECURITY.md](SECURITY.md) for the complete trust boundary.
|
|
|
214
219
|
## Development
|
|
215
220
|
|
|
216
221
|
```bash
|
|
217
|
-
./test.sh
|
|
222
|
+
./test.sh --fast # intermediate loop: core doctrine/hooks/report/Relay checks
|
|
223
|
+
./test.sh # closeout/CI: full eval, packaging, and install coverage
|
|
218
224
|
```
|
|
219
225
|
|
|
220
|
-
The
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
The fast tier is the default intermediate check for this repository; use a
|
|
227
|
+
more targeted command when changing a component it does not cover. The default
|
|
228
|
+
full tier (also `./test.sh --full`) covers scripts, hook state, Relay, bisect,
|
|
229
|
+
plugin/npm manifests, self-proving eval graders, and sandboxed install →
|
|
230
|
+
reinstall → uninstall for Claude Code and Codex. CI and `/done` use the full
|
|
231
|
+
tier.
|
|
223
232
|
|
|
224
233
|
More detail:
|
|
225
234
|
|
package/README.th.md
CHANGED
|
@@ -17,7 +17,7 @@ Luciazero ทำให้ coding agent รันลูป `วางแผน
|
|
|
17
17
|
> ถ้ายังไม่มีคำสั่งตรวจ นั่นคือบั๊กแรก
|
|
18
18
|
|
|
19
19
|
ภายในมี [doctrine 9 ข้อ](claude/luciazero.md) ที่สั้น, skill แบบเรียกเมื่อจำเป็น
|
|
20
|
-
|
|
20
|
+
10 ตัว, hook ติดตามการ verify, reviewer ที่ route ตามความเสี่ยง และ eval harness
|
|
21
21
|
นี่คือชั้นวินัย ไม่ใช่ agent runtime หรือระบบ orchestration สำหรับรันงานข้ามคืน
|
|
22
22
|
|
|
23
23
|
## ดูการทำงานใน 15 วินาที
|
|
@@ -81,7 +81,7 @@ fingerprint เก่า (5/6) ตัวเลขเหล่านี้เป
|
|
|
81
81
|
/plugin install luciazero@luciazero
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
เริ่ม repo ด้วย `/luciazero:
|
|
84
|
+
เริ่ม repo ด้วย `/luciazero:ready` ชื่อ skill แบบ plugin มี prefix
|
|
85
85
|
`/luciazero:` และไม่มี statusline เพราะ Claude Code plugin ตั้งค่านี้ไม่ได้
|
|
86
86
|
|
|
87
87
|
### เฉพาะ skill — agent ที่รองรับ
|
|
@@ -90,7 +90,8 @@ fingerprint เก่า (5/6) ตัวเลขเหล่านี้เป
|
|
|
90
90
|
npx skills add ohm41321/luciazero
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
ช่องทางนี้ติดตั้งเฉพาะ skill
|
|
93
|
+
ช่องทางนี้ติดตั้งเฉพาะ skill 10 ตัว พร้อม alias `/luciazero-bootstrap`
|
|
94
|
+
ชั่วคราว ไม่มี doctrine, reviewer หรือ hook
|
|
94
95
|
|
|
95
96
|
### Classic Claude Code และ Codex
|
|
96
97
|
|
|
@@ -136,14 +137,15 @@ Claude Code อัปเดต plugin ตอนเริ่มโปรแกร
|
|
|
136
137
|
ภายนอกจะปิดตัวเลือกนี้เป็นค่าเริ่มต้น ถ้าต้องการเพียงการแจ้งเตือน release ให้ใช้
|
|
137
138
|
GitHub **Watch → Custom → Releases**
|
|
138
139
|
|
|
139
|
-
## Skill ทั้ง
|
|
140
|
+
## Skill ทั้ง 10 ตัว
|
|
140
141
|
|
|
141
|
-
รัน `/
|
|
142
|
+
รัน `/ready` ก่อนหนึ่งครั้ง ที่เหลือใช้เมื่อถึงจังหวะของมัน
|
|
142
143
|
|
|
143
144
|
| จังหวะ | Skill | ผลลัพธ์ |
|
|
144
145
|
|---|---|---|
|
|
145
|
-
| เข้า repository | `/
|
|
146
|
-
|
|
|
146
|
+
| เข้า repository | `/ready` | หาหรือสร้างคำสั่ง verify และพิสูจน์ว่าแดงได้ |
|
|
147
|
+
| โครงสร้างหรือหลักฐานไล่อ่านยาก | `/show` | แสดงความเชื่อมโยง สิ่งที่เปลี่ยน และหลักฐานด้วยภาพที่เล็กที่สุด |
|
|
148
|
+
| ก่อนงานเสี่ยง กำกวม หรือแตะหลาย module | `/plan` | ล็อก scope และหลักฐานยอมรับที่สังเกตได้ |
|
|
147
149
|
| บั๊กที่มองรอบแรกไม่ออก | `/debug` | Reproduction, hypothesis ledger, regression test |
|
|
148
150
|
| รู้ revision ดีและเสีย | `/bisect` | หา first bad commit ใน worktree ชั่วคราว |
|
|
149
151
|
| ก่อนบอกว่าเสร็จ | `/done` | Full verify, skeptic review และรายงาน scope |
|
|
@@ -200,6 +202,9 @@ pilot มีเพียง 1 run ต่อ arm ต่อ task ดู [ผลเ
|
|
|
200
202
|
- Installer, hook, helper และ grader หลักรัน offline ส่วน behavioral eval จริง
|
|
201
203
|
เรียก model CLI และใช้เครดิต API หรือโควตา subscription
|
|
202
204
|
- Hook รันคำสั่งบนเครื่อง ควรอ่านก่อนเปิดใช้
|
|
205
|
+
- Telemetry ของ hook อยู่ใน private state แยกตาม session ภายในเครื่อง เก็บเวลา
|
|
206
|
+
wall time ของ turn/Bash และจำนวน Bash, verify, skill ที่ model/user เรียก
|
|
207
|
+
โดยไม่เก็บ command, ชื่อ skill หรือ path ดิบ
|
|
203
208
|
- ตั้ง `LUCIAZERO_VERIFY_CMD` เป็นคำสั่ง verify ระดับเร็วที่ exact ของ repo
|
|
204
209
|
- ใส่ `LUCIAZERO_STRICT_VERIFY_CMD` ใน personal settings เท่านั้น ห้าม commit ลง
|
|
205
210
|
config ของ repository; strict mode จะ fail open เมื่อเกิด internal error
|
|
@@ -209,12 +214,15 @@ pilot มีเพียง 1 run ต่อ arm ต่อ task ดู [ผลเ
|
|
|
209
214
|
## พัฒนา repo นี้
|
|
210
215
|
|
|
211
216
|
```bash
|
|
212
|
-
./test.sh
|
|
217
|
+
./test.sh --fast # loop ระหว่างทำ: ตรวจ doctrine/hook/report/Relay ส่วนหลัก
|
|
218
|
+
./test.sh # ปิดงาน/CI: ตรวจ eval, packaging และ install แบบเต็ม
|
|
213
219
|
```
|
|
214
220
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
221
|
+
fast tier เป็นคำสั่งระหว่างทำงานของ repo นี้; ถ้าแก้ส่วนที่ fast tier ไม่ครอบคลุม
|
|
222
|
+
ให้ใช้คำสั่ง targeted ของส่วนนั้น ส่วน full tier (`./test.sh` หรือ
|
|
223
|
+
`./test.sh --full`) ครอบคลุม script, state ของ hook, Relay, bisect, manifest ของ
|
|
224
|
+
plugin/npm, eval grader ที่พิสูจน์ตัวเองได้ และ install → reinstall → uninstall
|
|
225
|
+
แบบ sandbox ทั้ง Claude Code และ Codex โดย CI และ `/done` ใช้ full tier
|
|
218
226
|
|
|
219
227
|
อ่านต่อ:
|
|
220
228
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Risk-routed adversarial code reviewer with general, security, and contract focus modes. Spawn before declaring a risky change done, or when asked to review a diff, branch, or PR. Tries to refute the change, reads callers and consumers, and never edits files. If the harness offers a built-in adversarial review command, prefer it; use this agent when none exists or an independent focused pass is wanted.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are an adversarial code reviewer. Your job is to **refute** the change, not to approve it. Hunt for a real problem; praise is noise and is forbidden. An empty result after a genuine search is better than an invented finding.
|
|
9
|
+
|
|
10
|
+
## Input
|
|
11
|
+
|
|
12
|
+
You are given a diff, branch, PR, or changed-file list and an optional `focus`: `general` (default), `security`, or `contract`. If given a branch or nothing specific, derive the diff (`git diff`, `git diff main...HEAD`, `git show`). Read enough surrounding code to judge every hunk, then search call sites, consumers, schemas, and tests that still rely on the old behavior.
|
|
13
|
+
|
|
14
|
+
## What to hunt
|
|
15
|
+
|
|
16
|
+
Automated checks already cover the happy path. Hunt what they do not:
|
|
17
|
+
|
|
18
|
+
- **Edge cases** — empty input, zero, negative, unicode, max length, first/last element, concurrent access
|
|
19
|
+
- **Error paths** — what happens when the call fails, the file is missing, the network drops; are errors swallowed?
|
|
20
|
+
- **Changed contracts** — public API shape, serialized formats, DB schema, config keys: does anything else consume the old shape?
|
|
21
|
+
- **Unintended diff content** — files touched by accident, debug prints, commented-out code, secrets, dependency pins loosened
|
|
22
|
+
- **Resource discipline** — leaks (handles, connections, subscriptions), missing cleanup on the error path
|
|
23
|
+
- **Test honesty** — do the new/changed tests actually fail if the change is reverted? Tests that assert nothing, or were weakened to pass, are findings.
|
|
24
|
+
- **Security** — injection via interpolated input, path traversal, secrets in code or logs
|
|
25
|
+
|
|
26
|
+
## Focus routes
|
|
27
|
+
|
|
28
|
+
- `security`: map every changed trust boundary from input to sensitive sink. Check validation, encoding, authorization, failure defaults, path containment, command/query construction, secret handling, and error disclosure. Read endpoint wiring and permission callers—not only the changed function.
|
|
29
|
+
- `contract`: identify the old externally observable shape, then search all in-repo consumers, fixtures, docs, serializers, migrations, and compatibility shims. Treat silent default changes and parse/format drift as contracts too.
|
|
30
|
+
- `general`: apply the whole checklist with extra attention to error paths, state transitions, concurrency, and resource cleanup.
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
- **Verify before reporting.** Read the actual code for each suspected finding. A finding you did not confirm against the source is speculation — drop it or mark it explicitly as unverified.
|
|
35
|
+
- Run cheap read-only commands when they settle a question (`git log` for context, the test suite if it is fast). Never edit, never commit, never push.
|
|
36
|
+
- No style or formatting nits unless they change meaning.
|
|
37
|
+
- Stay inside the diff's causal scope; a defect in an unchanged consumer broken by the diff is in scope. Pre-existing unrelated problems go in one short "outside scope" line at the end.
|
|
38
|
+
|
|
39
|
+
## Output
|
|
40
|
+
|
|
41
|
+
One line per finding, most severe first:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
path:line — severity — problem. Concrete fix.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Severity: `blocker` (exploitable security, data loss, or fundamentally wrong result) / `major` (breaks a supported contract, permission boundary, or material edge case) / `minor` (works now, but has a concrete fragility).
|
|
48
|
+
|
|
49
|
+
If, after a genuine hunt, nothing survives verification: report exactly `No findings.` plus one sentence on what you checked. Do **not** invent findings to seem useful — a false finding costs more than an empty report.
|
package/bin/discipline-report.js
CHANGED
|
@@ -56,12 +56,20 @@ function parseLine(line) {
|
|
|
56
56
|
if (Number.isNaN(timestamp.valueOf()) || typeof row.project_id !== "string" || typeof row.project !== "string") {
|
|
57
57
|
return { malformed: true };
|
|
58
58
|
}
|
|
59
|
+
let telemetry = null;
|
|
60
|
+
if (row.telemetry && typeof row.telemetry === "object") {
|
|
61
|
+
const keys = ["turn_ms", "bash_ms", "bash_count", "verify_count", "skill_count"];
|
|
62
|
+
if (keys.every((key) => Number.isSafeInteger(row.telemetry[key]) && row.telemetry[key] >= 0)) {
|
|
63
|
+
telemetry = Object.fromEntries(keys.map((key) => [key, row.telemetry[key]]));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
59
66
|
return {
|
|
60
67
|
timestamp,
|
|
61
68
|
event: row.event,
|
|
62
69
|
project: row.project,
|
|
63
70
|
projectId: row.project_id,
|
|
64
71
|
verifyMode: ["regex", "exact", "strict"].includes(row.verify_mode) ? row.verify_mode : "unknown",
|
|
72
|
+
telemetry,
|
|
65
73
|
legacy: false,
|
|
66
74
|
};
|
|
67
75
|
}
|
|
@@ -75,6 +83,7 @@ function parseLine(line) {
|
|
|
75
83
|
project: match[3],
|
|
76
84
|
projectId: `legacy-${crypto.createHash("sha256").update(match[3]).digest("hex").slice(0, 12)}`,
|
|
77
85
|
verifyMode: "unknown",
|
|
86
|
+
telemetry: null,
|
|
78
87
|
legacy: true,
|
|
79
88
|
};
|
|
80
89
|
}
|
|
@@ -111,10 +120,23 @@ if (options.project) {
|
|
|
111
120
|
|
|
112
121
|
const counts = { "stop-clean": 0, nudge: 0, "strict-block": 0 };
|
|
113
122
|
const modes = { regex: 0, exact: 0, strict: 0, unknown: 0 };
|
|
123
|
+
const telemetry = {
|
|
124
|
+
measured_turns: 0, turn_ms: 0, bash_ms: 0, non_bash_ms: 0,
|
|
125
|
+
bash_count: 0, verify_count: 0, skill_count: 0,
|
|
126
|
+
};
|
|
114
127
|
const projects = new Map();
|
|
115
128
|
for (const row of rows) {
|
|
116
129
|
counts[row.event] += 1;
|
|
117
130
|
modes[row.verifyMode] = (modes[row.verifyMode] || 0) + 1;
|
|
131
|
+
if (row.telemetry) {
|
|
132
|
+
telemetry.measured_turns += 1;
|
|
133
|
+
telemetry.turn_ms += row.telemetry.turn_ms;
|
|
134
|
+
telemetry.bash_ms += row.telemetry.bash_ms;
|
|
135
|
+
telemetry.non_bash_ms += Math.max(0, row.telemetry.turn_ms - row.telemetry.bash_ms);
|
|
136
|
+
telemetry.bash_count += row.telemetry.bash_count;
|
|
137
|
+
telemetry.verify_count += row.telemetry.verify_count;
|
|
138
|
+
telemetry.skill_count += row.telemetry.skill_count;
|
|
139
|
+
}
|
|
118
140
|
const current = projects.get(row.projectId) || {
|
|
119
141
|
project: row.project,
|
|
120
142
|
project_id: row.projectId,
|
|
@@ -160,6 +182,7 @@ const report = {
|
|
|
160
182
|
legacy_records: legacyRecords,
|
|
161
183
|
outcomes: counts,
|
|
162
184
|
verify_modes: modes,
|
|
185
|
+
telemetry,
|
|
163
186
|
top_nudged_projects: topNudged,
|
|
164
187
|
recommendations,
|
|
165
188
|
};
|
|
@@ -182,6 +205,18 @@ console.log(` Clean stops: ${String(counts["stop-clean"]).padStart(5)} (${per
|
|
|
182
205
|
console.log(` Nudges: ${String(counts.nudge).padStart(5)} (${percent(counts.nudge)})`);
|
|
183
206
|
console.log(` Strict blocks: ${String(counts["strict-block"]).padStart(5)} (${percent(counts["strict-block"])})`);
|
|
184
207
|
console.log("");
|
|
208
|
+
console.log("Latency Telemetry:");
|
|
209
|
+
if (telemetry.measured_turns === 0) {
|
|
210
|
+
console.log(" No measured turns (new hooks collect this locally).");
|
|
211
|
+
} else {
|
|
212
|
+
const average = (value) => Math.round(value / telemetry.measured_turns);
|
|
213
|
+
console.log(` Measured turns: ${telemetry.measured_turns}`);
|
|
214
|
+
console.log(` Average turn: ${average(telemetry.turn_ms)} ms`);
|
|
215
|
+
console.log(` Average Bash time: ${average(telemetry.bash_ms)} ms`);
|
|
216
|
+
console.log(` Average non-Bash: ${average(telemetry.non_bash_ms)} ms`);
|
|
217
|
+
console.log(` Bash / verify / skill calls: ${telemetry.bash_count} / ${telemetry.verify_count} / ${telemetry.skill_count}`);
|
|
218
|
+
}
|
|
219
|
+
console.log("");
|
|
185
220
|
console.log("Top Nudged Repositories:");
|
|
186
221
|
if (topNudged.length === 0) console.log(" None in the selected period.");
|
|
187
222
|
for (const [index, item] of topNudged.entries()) {
|
package/claude/hooks/hooks.json
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
|
+
"UserPromptSubmit": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{ "type": "command", "command": "LUCIAZERO_CHANNEL=plugin ${CLAUDE_PLUGIN_ROOT}/claude/hooks/luciazero-verify.sh prompt" }
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"UserPromptExpansion": [
|
|
11
|
+
{
|
|
12
|
+
"hooks": [
|
|
13
|
+
{ "type": "command", "command": "LUCIAZERO_CHANNEL=plugin ${CLAUDE_PLUGIN_ROOT}/claude/hooks/luciazero-verify.sh skill-prompt" }
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"PreToolUse": [
|
|
18
|
+
{
|
|
19
|
+
"matcher": "Bash",
|
|
20
|
+
"hooks": [
|
|
21
|
+
{ "type": "command", "command": "LUCIAZERO_CHANNEL=plugin ${CLAUDE_PLUGIN_ROOT}/claude/hooks/luciazero-verify.sh bash-start" }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
3
25
|
"PostToolUse": [
|
|
4
26
|
{
|
|
5
27
|
"matcher": "Edit|Write|NotebookEdit",
|
|
@@ -12,6 +34,20 @@
|
|
|
12
34
|
"hooks": [
|
|
13
35
|
{ "type": "command", "command": "LUCIAZERO_CHANNEL=plugin ${CLAUDE_PLUGIN_ROOT}/claude/hooks/luciazero-verify.sh bash" }
|
|
14
36
|
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"matcher": "Skill",
|
|
40
|
+
"hooks": [
|
|
41
|
+
{ "type": "command", "command": "LUCIAZERO_CHANNEL=plugin ${CLAUDE_PLUGIN_ROOT}/claude/hooks/luciazero-verify.sh skill" }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"PostToolUseFailure": [
|
|
46
|
+
{
|
|
47
|
+
"matcher": "Bash",
|
|
48
|
+
"hooks": [
|
|
49
|
+
{ "type": "command", "command": "LUCIAZERO_CHANNEL=plugin ${CLAUDE_PLUGIN_ROOT}/claude/hooks/luciazero-verify.sh bash-failure" }
|
|
50
|
+
]
|
|
15
51
|
}
|
|
16
52
|
],
|
|
17
53
|
"Stop": [
|
|
@@ -16,7 +16,7 @@ set -u
|
|
|
16
16
|
IN="$(cat 2>/dev/null || true)"
|
|
17
17
|
|
|
18
18
|
LINE="$(printf '%s' "${IN}" | python3 -c '
|
|
19
|
-
import json, os, sys, time, hashlib
|
|
19
|
+
import json, os, sys, time, hashlib, stat
|
|
20
20
|
|
|
21
21
|
try:
|
|
22
22
|
d = json.load(sys.stdin)
|
|
@@ -27,9 +27,24 @@ model = ((d.get("model") or {}).get("display_name")) or "claude"
|
|
|
27
27
|
cwd = ((d.get("workspace") or {}).get("current_dir")) or d.get("cwd") or os.getcwd()
|
|
28
28
|
|
|
29
29
|
key = hashlib.md5(cwd.encode()).hexdigest()[:12]
|
|
30
|
-
|
|
30
|
+
uid = os.getuid() if hasattr(os, "getuid") else "unknown"
|
|
31
|
+
base = os.path.join(os.environ.get("TMPDIR", "/tmp"), f"luciazero-verify-state-{uid}")
|
|
32
|
+
try:
|
|
33
|
+
info = os.lstat(base)
|
|
34
|
+
if stat.S_ISLNK(info.st_mode) or not stat.S_ISDIR(info.st_mode):
|
|
35
|
+
raise OSError("unsafe state base")
|
|
36
|
+
if hasattr(os, "getuid") and info.st_uid != os.getuid():
|
|
37
|
+
raise OSError("wrong state owner")
|
|
38
|
+
if stat.S_IMODE(info.st_mode) & 0o077:
|
|
39
|
+
raise OSError("state base is not private")
|
|
40
|
+
except OSError:
|
|
41
|
+
state = None
|
|
42
|
+
else:
|
|
43
|
+
state = os.path.join(base, key)
|
|
31
44
|
|
|
32
45
|
def mtime(name):
|
|
46
|
+
if state is None:
|
|
47
|
+
return None
|
|
33
48
|
try:
|
|
34
49
|
return os.path.getmtime(os.path.join(state, name))
|
|
35
50
|
except OSError:
|