@orchestrator-claude/definitions 3.31.0 → 3.31.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/adversarial-reviewer.md +1 -1
- package/agents/reviewer.md +3 -1
- package/hooks/dangling-guard.ts +148 -10
- package/hooks/gate-guardian.ts +177 -40
- package/hooks/lib/api-client.ts +419 -38
- package/hooks/lib/capability-scanner.ts +640 -0
- package/hooks/lib/finops-parser.ts +247 -0
- package/hooks/lib/gate-logic.ts +7 -7
- package/hooks/lib/git-checkpoint.ts +20 -20
- package/hooks/lib/observations-helper.ts +104 -0
- package/hooks/lib/sprint-context.ts +102 -0
- package/hooks/mailbox-listener.ts +139 -25
- package/hooks/post-compact.ts +137 -11
- package/hooks/session-start.ts +416 -47
- package/hooks/sprint-registry.ts +6 -5
- package/hooks/subagent-start.ts +27 -15
- package/hooks/subagent-stop.ts +72 -13
- package/hooks/user-prompt.ts +43 -15
- package/hooks/workflow-guard.ts +96 -37
- package/manifest.json +52 -36
- package/package.json +1 -1
- package/skills/backlog-synthesis/SKILL.md +1 -1
- package/skills/orchestrator/SKILL.md +17 -0
- package/skills/release/SKILL.md +41 -0
- package/skills/workflow-status/SKILL.md +1 -1
- package/hooks/pre-agent-dispatch.ts +0 -57
- package/hooks/verification-before-completion.ts +0 -97
package/manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "orchestrator-definitions/v1",
|
|
3
3
|
"namespace": "orchestrator",
|
|
4
|
-
"version": "3.31.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "3.31.2",
|
|
5
|
+
"generatedAt": "2026-06-25T14:31:07.105Z",
|
|
6
6
|
"definitions": {
|
|
7
7
|
"agents": [
|
|
8
8
|
{
|
|
9
9
|
"slug": "adversarial-reviewer",
|
|
10
10
|
"file": "agents/adversarial-reviewer.md",
|
|
11
11
|
"version": "1.0.0",
|
|
12
|
-
"checksum": "sha256:
|
|
12
|
+
"checksum": "sha256:1ef78465016dab1cb1a615494a2008bcb210757e64584dfd291768b178f96293",
|
|
13
13
|
"supersedes": null,
|
|
14
14
|
"metadata": {}
|
|
15
15
|
},
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
"slug": "reviewer",
|
|
146
146
|
"file": "agents/reviewer.md",
|
|
147
147
|
"version": "1.0.0",
|
|
148
|
-
"checksum": "sha256:
|
|
148
|
+
"checksum": "sha256:9486f431017050ee188314a6f0225dbb654bf9202d5377be5b71fa77e7422046",
|
|
149
149
|
"supersedes": null,
|
|
150
150
|
"metadata": {}
|
|
151
151
|
},
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
"slug": "backlog-synthesis",
|
|
212
212
|
"file": "skills/backlog-synthesis/SKILL.md",
|
|
213
213
|
"version": "1.0.0",
|
|
214
|
-
"checksum": "sha256:
|
|
214
|
+
"checksum": "sha256:e077bbf16cfbb6a79fbda114df884066b57b93fff83d5d0bffdace46f62ae964",
|
|
215
215
|
"supersedes": null,
|
|
216
216
|
"metadata": {}
|
|
217
217
|
},
|
|
@@ -299,7 +299,7 @@
|
|
|
299
299
|
"slug": "orchestrator",
|
|
300
300
|
"file": "skills/orchestrator/SKILL.md",
|
|
301
301
|
"version": "1.0.0",
|
|
302
|
-
"checksum": "sha256:
|
|
302
|
+
"checksum": "sha256:89cd6fe31a0a8626bada2eb99e2c74118127174f662466b09813a74b16b58694",
|
|
303
303
|
"supersedes": null,
|
|
304
304
|
"metadata": {}
|
|
305
305
|
},
|
|
@@ -347,7 +347,7 @@
|
|
|
347
347
|
"slug": "release",
|
|
348
348
|
"file": "skills/release/SKILL.md",
|
|
349
349
|
"version": "1.0.0",
|
|
350
|
-
"checksum": "sha256:
|
|
350
|
+
"checksum": "sha256:97e132fc96b1a0c65d77f3ad209dd1a23e9518a29eb775529f4e1cb6ea248c26",
|
|
351
351
|
"supersedes": null,
|
|
352
352
|
"metadata": {}
|
|
353
353
|
},
|
|
@@ -403,7 +403,7 @@
|
|
|
403
403
|
"slug": "workflow-status",
|
|
404
404
|
"file": "skills/workflow-status/SKILL.md",
|
|
405
405
|
"version": "1.0.0",
|
|
406
|
-
"checksum": "sha256:
|
|
406
|
+
"checksum": "sha256:7390c8d966110f5e0f8935b61363c6252cde5674423355742a5ebe8c76b790ad",
|
|
407
407
|
"supersedes": null,
|
|
408
408
|
"metadata": {}
|
|
409
409
|
}
|
|
@@ -413,7 +413,7 @@
|
|
|
413
413
|
"slug": "dangling-guard",
|
|
414
414
|
"file": "hooks/dangling-guard.ts",
|
|
415
415
|
"version": "1.0.0",
|
|
416
|
-
"checksum": "sha256:
|
|
416
|
+
"checksum": "sha256:795ab6cb17039f6fd503d484a49a9bfe1b8a4b735098a9499bd679e534296da1",
|
|
417
417
|
"supersedes": null,
|
|
418
418
|
"metadata": {}
|
|
419
419
|
},
|
|
@@ -421,7 +421,7 @@
|
|
|
421
421
|
"slug": "gate-guardian",
|
|
422
422
|
"file": "hooks/gate-guardian.ts",
|
|
423
423
|
"version": "1.0.0",
|
|
424
|
-
"checksum": "sha256:
|
|
424
|
+
"checksum": "sha256:d4098999b3f4cf28f9bc309f6355a00aaa4d9df90b66c17ec32f27bd20d55bf9",
|
|
425
425
|
"supersedes": null,
|
|
426
426
|
"metadata": {}
|
|
427
427
|
},
|
|
@@ -429,7 +429,23 @@
|
|
|
429
429
|
"slug": "api-client",
|
|
430
430
|
"file": "hooks/lib/api-client.ts",
|
|
431
431
|
"version": "1.0.0",
|
|
432
|
-
"checksum": "sha256:
|
|
432
|
+
"checksum": "sha256:fdac374cfabb58865d676e24157d15bc9d81cdabf62a5a6d28c66e9a95fdf69e",
|
|
433
|
+
"supersedes": null,
|
|
434
|
+
"metadata": {}
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
"slug": "capability-scanner",
|
|
438
|
+
"file": "hooks/lib/capability-scanner.ts",
|
|
439
|
+
"version": "1.0.0",
|
|
440
|
+
"checksum": "sha256:f366c0afdcc06224d2e80566b3e5eaf6e06cf9af3b80c10d3c9acae4690f1c97",
|
|
441
|
+
"supersedes": null,
|
|
442
|
+
"metadata": {}
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
"slug": "finops-parser",
|
|
446
|
+
"file": "hooks/lib/finops-parser.ts",
|
|
447
|
+
"version": "1.0.0",
|
|
448
|
+
"checksum": "sha256:4acdcd904dd956c0375b11ebfbadca904b51635033c64d10f96f721235247c55",
|
|
433
449
|
"supersedes": null,
|
|
434
450
|
"metadata": {}
|
|
435
451
|
},
|
|
@@ -437,7 +453,7 @@
|
|
|
437
453
|
"slug": "gate-logic",
|
|
438
454
|
"file": "hooks/lib/gate-logic.ts",
|
|
439
455
|
"version": "1.0.0",
|
|
440
|
-
"checksum": "sha256:
|
|
456
|
+
"checksum": "sha256:d3fe80209e5a8267214c314ef7f6fad474764fddb9d398c660e33071ee604a7a",
|
|
441
457
|
"supersedes": null,
|
|
442
458
|
"metadata": {}
|
|
443
459
|
},
|
|
@@ -445,31 +461,39 @@
|
|
|
445
461
|
"slug": "git-checkpoint",
|
|
446
462
|
"file": "hooks/lib/git-checkpoint.ts",
|
|
447
463
|
"version": "1.0.0",
|
|
448
|
-
"checksum": "sha256:
|
|
464
|
+
"checksum": "sha256:9a001448abbb96d974af14db0a93763426a6409aaa68fb338547795f493ac636",
|
|
449
465
|
"supersedes": null,
|
|
450
466
|
"metadata": {}
|
|
451
467
|
},
|
|
452
468
|
{
|
|
453
|
-
"slug": "
|
|
454
|
-
"file": "hooks/
|
|
469
|
+
"slug": "observations-helper",
|
|
470
|
+
"file": "hooks/lib/observations-helper.ts",
|
|
455
471
|
"version": "1.0.0",
|
|
456
|
-
"checksum": "sha256:
|
|
472
|
+
"checksum": "sha256:76b531c227e616582a0a2989d19e60e3fe86bfc02a2dee12e32a8b7acfe18faf",
|
|
457
473
|
"supersedes": null,
|
|
458
474
|
"metadata": {}
|
|
459
475
|
},
|
|
460
476
|
{
|
|
461
|
-
"slug": "
|
|
462
|
-
"file": "hooks/
|
|
477
|
+
"slug": "sprint-context",
|
|
478
|
+
"file": "hooks/lib/sprint-context.ts",
|
|
463
479
|
"version": "1.0.0",
|
|
464
|
-
"checksum": "sha256:
|
|
480
|
+
"checksum": "sha256:fc681215c9a41615d8d902e0a39f18406d6e130780d7408ed264fbfc9eab8f1c",
|
|
465
481
|
"supersedes": null,
|
|
466
482
|
"metadata": {}
|
|
467
483
|
},
|
|
468
484
|
{
|
|
469
|
-
"slug": "
|
|
470
|
-
"file": "hooks/
|
|
485
|
+
"slug": "mailbox-listener",
|
|
486
|
+
"file": "hooks/mailbox-listener.ts",
|
|
487
|
+
"version": "1.0.0",
|
|
488
|
+
"checksum": "sha256:8112646bf356b209e986af38d2f9e8f71a01a38947540af76611ccc0725a718d",
|
|
489
|
+
"supersedes": null,
|
|
490
|
+
"metadata": {}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"slug": "post-compact",
|
|
494
|
+
"file": "hooks/post-compact.ts",
|
|
471
495
|
"version": "1.0.0",
|
|
472
|
-
"checksum": "sha256:
|
|
496
|
+
"checksum": "sha256:966ca9cf9dc32fc1b31e28fb36fdfc4732cd785bbbef7909de6d10ab1a79aec9",
|
|
473
497
|
"supersedes": null,
|
|
474
498
|
"metadata": {}
|
|
475
499
|
},
|
|
@@ -477,7 +501,7 @@
|
|
|
477
501
|
"slug": "session-start",
|
|
478
502
|
"file": "hooks/session-start.ts",
|
|
479
503
|
"version": "1.0.0",
|
|
480
|
-
"checksum": "sha256:
|
|
504
|
+
"checksum": "sha256:c8adea2c3cdfd0eebfe488d81260fb0eed26e88a231586b4af6174efebe87781",
|
|
481
505
|
"supersedes": null,
|
|
482
506
|
"metadata": {}
|
|
483
507
|
},
|
|
@@ -485,7 +509,7 @@
|
|
|
485
509
|
"slug": "sprint-registry",
|
|
486
510
|
"file": "hooks/sprint-registry.ts",
|
|
487
511
|
"version": "1.0.0",
|
|
488
|
-
"checksum": "sha256:
|
|
512
|
+
"checksum": "sha256:340e40adc35b75c1b09bdc5b9166272098e52db7a91e6d870ba7cd6ccba8b4ab",
|
|
489
513
|
"supersedes": null,
|
|
490
514
|
"metadata": {}
|
|
491
515
|
},
|
|
@@ -493,7 +517,7 @@
|
|
|
493
517
|
"slug": "subagent-start",
|
|
494
518
|
"file": "hooks/subagent-start.ts",
|
|
495
519
|
"version": "1.0.0",
|
|
496
|
-
"checksum": "sha256:
|
|
520
|
+
"checksum": "sha256:1c9ea66ec85376d7a40b943d3b8b44c602faedad809df0419d85d8e454664a24",
|
|
497
521
|
"supersedes": null,
|
|
498
522
|
"metadata": {}
|
|
499
523
|
},
|
|
@@ -501,7 +525,7 @@
|
|
|
501
525
|
"slug": "subagent-stop",
|
|
502
526
|
"file": "hooks/subagent-stop.ts",
|
|
503
527
|
"version": "1.0.0",
|
|
504
|
-
"checksum": "sha256:
|
|
528
|
+
"checksum": "sha256:569408e36602087ccc8ada1f61de3a365fe92a4705332913094a6160cacee753",
|
|
505
529
|
"supersedes": null,
|
|
506
530
|
"metadata": {}
|
|
507
531
|
},
|
|
@@ -509,15 +533,7 @@
|
|
|
509
533
|
"slug": "user-prompt",
|
|
510
534
|
"file": "hooks/user-prompt.ts",
|
|
511
535
|
"version": "1.0.0",
|
|
512
|
-
"checksum": "sha256:
|
|
513
|
-
"supersedes": null,
|
|
514
|
-
"metadata": {}
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
"slug": "verification-before-completion",
|
|
518
|
-
"file": "hooks/verification-before-completion.ts",
|
|
519
|
-
"version": "1.0.0",
|
|
520
|
-
"checksum": "sha256:83fc4baf7a5117cd6c0368592fc1ee254d1b138f0a38f88c554c72aa63713279",
|
|
536
|
+
"checksum": "sha256:93e247dffd5609cf9c179f653bf072be19e4c94d11bf420743046795e68cf9d3",
|
|
521
537
|
"supersedes": null,
|
|
522
538
|
"metadata": {}
|
|
523
539
|
},
|
|
@@ -525,7 +541,7 @@
|
|
|
525
541
|
"slug": "workflow-guard",
|
|
526
542
|
"file": "hooks/workflow-guard.ts",
|
|
527
543
|
"version": "1.0.0",
|
|
528
|
-
"checksum": "sha256:
|
|
544
|
+
"checksum": "sha256:b70edb5d65d370ce230b1666171230c58c9f425e9cbb49687f08d236bc164e2c",
|
|
529
545
|
"supersedes": null,
|
|
530
546
|
"metadata": {}
|
|
531
547
|
}
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@ cat .claude/agent-memory/orchestrator/MEMORY.md 2>/dev/null || echo "(empty)"
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
### Step 2: Query Active Workflows
|
|
21
|
-
Use MCP tool
|
|
21
|
+
Use MCP tool listWorkflowDefinitions or getStatus to check active workflow state.
|
|
22
22
|
|
|
23
23
|
### Step 3: Cross-Reference and Synthesize
|
|
24
24
|
Look for:
|
|
@@ -83,6 +83,23 @@ Sub-agents MUST persist artifacts to MinIO via `artifactStore` (universal rule,
|
|
|
83
83
|
|
|
84
84
|
<!-- TODO S182 (OQ-4): per-phase agent override (.phases[n].agent) deferred — S182 will resolve permissive vs registry-validated vs KnownAgent-enum strategy after agent list complete -->
|
|
85
85
|
|
|
86
|
+
#### 2c.1 Implementer-specific dispatch addenda (TD-S188-002)
|
|
87
|
+
|
|
88
|
+
When dispatching `implementer` (phase=`implement`), the generic template above is **insufficient**. The S188 implement phase surfaced an ambiguity: the implementer interpreted `createCheckpoint` as requiring a git commit beforehand, producing 4 unsolicited commits per dispatch (commit prefix also leaked from BACKLOG context: `feat(s186)` instead of `feat(s188)`). To prevent recurrence, append the following **commit policy block** to every implementer dispatch prompt:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
[Commit Policy]
|
|
92
|
+
- createCheckpoint (mcp__orchestrator-tools__createCheckpoint) is a PostgreSQL state snapshot per RFC-012. It is INDEPENDENT of git. You do NOT need to commit before calling it. Calling createCheckpoint with no uncommitted changes is the normal path.
|
|
93
|
+
- Commit policy for this dispatch: <one of>
|
|
94
|
+
a) "DO NOT commit — orchestrator owns the closure commit at review gate."
|
|
95
|
+
b) "Commit per-phase using prefix `<feat|fix|refactor>(s<N>): <subject>` — confirm prefix before commit." (use when implement phase exceeds 80k tokens or spans multiple fases)
|
|
96
|
+
- If you commit, the prefix MUST be: `<feat|fix|refactor>(s<CURRENT_SESSION>):` — do NOT infer from BACKLOG examples or previous session context.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Substitute `<CURRENT_SESSION>` with the active session number (e.g., `s189`) and pick **exactly one** of (a) or (b) — never leave both options visible. The block goes **after** `[Task]` and **before** the artifactStore instruction.
|
|
100
|
+
|
|
101
|
+
If the orchestrator (main) wants to own all commits, prefer option (a) + call `createCheckpoint` itself after the implement phase completes — do NOT delegate that call to implementer.
|
|
102
|
+
|
|
86
103
|
### 2d. Gate Check
|
|
87
104
|
|
|
88
105
|
After each sub-agent completes, present the artifact summary and ask for approval:
|
package/skills/release/SKILL.md
CHANGED
|
@@ -250,6 +250,46 @@ git commit -m "chore: sync definitions manifest checksums"
|
|
|
250
250
|
|
|
251
251
|
**REGRA:** Nunca faca release com definitions alteradas sem manifest actualizado. Isso causa uma release extra desnecessaria (como aconteceu no v3.9.3 -> v3.9.4).
|
|
252
252
|
|
|
253
|
+
## Secret Audit (Quarterly — TD-S188-003)
|
|
254
|
+
|
|
255
|
+
Release CI/CD depende de 3 secrets em `.github/workflows/release.yml`:
|
|
256
|
+
|
|
257
|
+
| Secret | Purpose | Notas |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `NPM_TOKEN` | Publica `@orchestrator-claude/*` packages | type=Automation (bypassa 2FA em CI). 404 PUT durante publish = token issue, NÃO scope-missing (S186 hard rule). |
|
|
260
|
+
| `DOCKER_PASSWORD` | Login Docker Hub (user `cmac01`) | NÃO confundir com `DOCKER_TOKEN`. S186 release quebrou porque release.yml linhas 40+83 referenciavam o nome errado. Cross-reference `grep DOCKER_ release.yml` antes de instruir user a regerar secret. |
|
|
261
|
+
| `DOCKER_USERNAME` | Docker Hub user identifier | Raramente roda; muda só se conta migrar. |
|
|
262
|
+
|
|
263
|
+
**Hard rule:** Antes de QUALQUER release, audite idade dos 3 secrets críticos. Se algum > 90 dias, **bloqueie release** e rotacione primeiro.
|
|
264
|
+
|
|
265
|
+
### Comando de audit
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Lista timestamp + idade em dias dos 3 secrets críticos do release.yml
|
|
269
|
+
gh secret list --json name,updatedAt | jq -r \
|
|
270
|
+
'.[] | select(.name | IN("NPM_TOKEN","DOCKER_PASSWORD","DOCKER_USERNAME")) |
|
|
271
|
+
"\(.name)\tupdated \(.updatedAt)\tage \(((now - (.updatedAt | fromdateiso8601)) / 86400 | floor))d"'
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Output esperado (idade < 90d em todos):
|
|
275
|
+
```
|
|
276
|
+
DOCKER_PASSWORD updated 2026-02-10T... age 92d ← ROTACIONAR
|
|
277
|
+
DOCKER_USERNAME updated 2025-08-15T... age 271d ← stable, mas confirme válido
|
|
278
|
+
NPM_TOKEN updated 2026-04-20T... age 23d ← OK
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Rotação de secret expirante
|
|
282
|
+
|
|
283
|
+
1. **Pause release** — NÃO execute `release.sh`.
|
|
284
|
+
2. Regere o secret na origem:
|
|
285
|
+
- `NPM_TOKEN`: https://www.npmjs.com/settings/<user>/tokens (Generate New → Automation type)
|
|
286
|
+
- `DOCKER_PASSWORD`: Docker Hub → Account Settings → Security → New Access Token
|
|
287
|
+
3. Atualize no GitHub: `gh secret set <NAME> --body "<new-value>"` (executar do CWD repo)
|
|
288
|
+
4. Re-rode comando de audit acima — confirmar `updatedAt` fresco (idade < 1d).
|
|
289
|
+
5. Proceda com release.
|
|
290
|
+
|
|
291
|
+
**Histórico:** S186 release pipeline broke porque DOCKER_PASSWORD estava ausente (incorretamente referenciado como `DOCKER_TOKEN` em `release.yml` linhas 40+83). Aprendizagem capturada em hard rules S185→S188 carryover (BACKLOG).
|
|
292
|
+
|
|
253
293
|
## Checklist Pre-Release
|
|
254
294
|
|
|
255
295
|
- [ ] CHANGELOG.md atualizado com todas as mudancas
|
|
@@ -259,3 +299,4 @@ git commit -m "chore: sync definitions manifest checksums"
|
|
|
259
299
|
- [ ] Na branch main
|
|
260
300
|
- [ ] Dry-run executado e revisado
|
|
261
301
|
- [ ] Definitions manifest sincronizado (se houve alteracao em definitions)
|
|
302
|
+
- [ ] **Secret audit executado** — nenhum dos 3 secrets críticos (`NPM_TOKEN`, `DOCKER_PASSWORD`, `DOCKER_USERNAME`) > 90 dias (ver seção "Secret Audit")
|
|
@@ -14,7 +14,7 @@ All workflow state is in **PostgreSQL** via MCP tools. NEVER read `.orchestrator
|
|
|
14
14
|
| Tool | What it returns |
|
|
15
15
|
|------|----------------|
|
|
16
16
|
| `getStatus` | Current workflow: phase, status, pending action |
|
|
17
|
-
| `
|
|
17
|
+
| `listWorkflowDefinitions` | All workflow type definitions (phases, modes) |
|
|
18
18
|
| `getNextAction` | Next pending action (agent + status) |
|
|
19
19
|
| `getInvocations` | Agent invocation history |
|
|
20
20
|
| `getMetrics` | Workflow metrics (duration, counts) |
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pre-agent-dispatch.ts — PreToolUse hook for Agent tool (RFC-027 Sprint 4)
|
|
3
|
-
*
|
|
4
|
-
* Warns when dispatching known agents without subagent_type.
|
|
5
|
-
* Non-blocking: always exits 0.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { log, readStdin, getField, outputContext } from "./lib/api-client.js";
|
|
9
|
-
|
|
10
|
-
const HOOK = "PRE-AGENT-DISPATCH";
|
|
11
|
-
|
|
12
|
-
const KNOWN_AGENTS = [
|
|
13
|
-
"implementer",
|
|
14
|
-
"planner",
|
|
15
|
-
"specifier",
|
|
16
|
-
"reviewer",
|
|
17
|
-
"task-generator",
|
|
18
|
-
"researcher",
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const KNOWN_AGENTS_REGEX = new RegExp(
|
|
22
|
-
`\\b(${KNOWN_AGENTS.join("|")})\\b`,
|
|
23
|
-
"i"
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
async function main(): Promise<void> {
|
|
27
|
-
const stdin = await readStdin();
|
|
28
|
-
const toolInput = getField(stdin, "tool_input") || "";
|
|
29
|
-
const subagentType =
|
|
30
|
-
getField(stdin, "tool_input.subagent_type") ||
|
|
31
|
-
getField(stdin, "tool_input.subagentType") ||
|
|
32
|
-
"";
|
|
33
|
-
|
|
34
|
-
// If subagent_type is present, no warning needed
|
|
35
|
-
if (subagentType) {
|
|
36
|
-
log(HOOK, `Agent dispatched with subagent_type="${subagentType}", OK`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Check if prompt mentions a known agent
|
|
41
|
-
const prompt =
|
|
42
|
-
getField(stdin, "tool_input.prompt") ||
|
|
43
|
-
getField(stdin, "tool_input.description") ||
|
|
44
|
-
(typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput));
|
|
45
|
-
|
|
46
|
-
const match = prompt.match(KNOWN_AGENTS_REGEX);
|
|
47
|
-
if (match) {
|
|
48
|
-
const detected = match[1].toLowerCase();
|
|
49
|
-
outputContext(
|
|
50
|
-
HOOK,
|
|
51
|
-
`[WARN] Agent dispatched without subagent_type. Known agent detected: "${detected}". Add subagent_type for proper frontmatter loading.`
|
|
52
|
-
);
|
|
53
|
-
log(HOOK, `WARN: known agent "${detected}" without subagent_type`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
main().catch(() => process.exit(0));
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* verification-before-completion.ts — PreToolUse[Bash] hook
|
|
3
|
-
*
|
|
4
|
-
* Injects a verification reminder when the model is about to run
|
|
5
|
-
* `git commit` or `git push`. Does NOT block — only adds context.
|
|
6
|
-
*
|
|
7
|
-
* Principle: Evidence before claims, always.
|
|
8
|
-
* Source: verification-before-completion skill (superpowers 5.0.7)
|
|
9
|
-
*
|
|
10
|
-
* Flow:
|
|
11
|
-
* 1. readStdin() → extract bash command
|
|
12
|
-
* 2. commandMatchesGitOp() → check for commit/push
|
|
13
|
-
* 3. If match → output allow + context reminder
|
|
14
|
-
* 4. If no match → silent pass-through (no output)
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { log, readStdin, getField, outputPreToolUse } from "./lib/api-client.js";
|
|
18
|
-
|
|
19
|
-
const HOOK = "VERIFICATION-REMINDER";
|
|
20
|
-
|
|
21
|
-
// ─────────────────────────────────────────────────────────────
|
|
22
|
-
// Dependency injection interface (enables testing without IO)
|
|
23
|
-
// ─────────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
export interface HookDeps {
|
|
26
|
-
readStdin: () => Promise<Record<string, unknown>>;
|
|
27
|
-
output: (opts: { decision: "allow" | "deny"; reason?: string; context?: string }) => void;
|
|
28
|
-
log: (prefix: string, msg: string) => void;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const defaultDeps: HookDeps = {
|
|
32
|
-
readStdin,
|
|
33
|
-
output: outputPreToolUse,
|
|
34
|
-
log,
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// ─────────────────────────────────────────────────────────────
|
|
38
|
-
// Pure helpers (exported for testing)
|
|
39
|
-
// ─────────────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Returns true when the bash command string contains a git commit or git push
|
|
43
|
-
* operation. Handles common variations: `git commit`, `git push`, multi-command
|
|
44
|
-
* pipelines (`&&`, `;`), and quoted forms.
|
|
45
|
-
*/
|
|
46
|
-
export function commandMatchesGitOp(command: string): boolean {
|
|
47
|
-
return /git\s+(commit|push)/.test(command);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ─────────────────────────────────────────────────────────────
|
|
51
|
-
// Core logic (exported for testing)
|
|
52
|
-
// ─────────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
export async function mainWithDeps(deps: HookDeps): Promise<void> {
|
|
55
|
-
const { readStdin, output, log } = deps;
|
|
56
|
-
|
|
57
|
-
const stdin = await readStdin();
|
|
58
|
-
|
|
59
|
-
// Extract the bash command from the tool input envelope
|
|
60
|
-
const command =
|
|
61
|
-
(getField(stdin, "tool_input.command") as string | undefined) ||
|
|
62
|
-
(getField(stdin, "command") as string | undefined) ||
|
|
63
|
-
"";
|
|
64
|
-
|
|
65
|
-
if (!commandMatchesGitOp(command)) {
|
|
66
|
-
// Silent pass-through — not a git commit/push, nothing to do
|
|
67
|
-
log(HOOK, `PASS (no git op): ${command.slice(0, 60)}`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
log(HOOK, `REMIND git op detected: ${command.slice(0, 80)}`);
|
|
72
|
-
|
|
73
|
-
// Allow the command but inject a verification reminder as context.
|
|
74
|
-
// This hook NEVER blocks — it only nudges the model to verify first.
|
|
75
|
-
output({
|
|
76
|
-
decision: "allow",
|
|
77
|
-
context: [
|
|
78
|
-
"[VERIFICATION-REMINDER] You are about to run a git commit/push.",
|
|
79
|
-
"Before proceeding, confirm:",
|
|
80
|
-
" 1. Tests pass — run the test command and paste the output.",
|
|
81
|
-
" 2. Lint clean — run the lint command and confirm 0 errors.",
|
|
82
|
-
" 3. Build succeeds — run the build command and confirm exit 0.",
|
|
83
|
-
" 4. All acceptance criteria have matching test evidence.",
|
|
84
|
-
"Evidence before claims. No shortcuts for verification.",
|
|
85
|
-
].join("\n"),
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ─────────────────────────────────────────────────────────────
|
|
90
|
-
// Entry point (production use)
|
|
91
|
-
// ─────────────────────────────────────────────────────────────
|
|
92
|
-
|
|
93
|
-
async function main(): Promise<void> {
|
|
94
|
-
await mainWithDeps(defaultDeps);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
main().catch(() => process.exit(0));
|