@orchestrator-claude/definitions 3.37.0 → 3.37.1
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 +6 -1
- package/agents/api-extractor.md +6 -0
- package/agents/azure-devops-engineer.md +1 -2
- package/agents/business-rule-miner.md +6 -0
- package/agents/cicd-platform-engineer.md +1 -2
- package/agents/ciclo-engineer.md +15 -2
- package/agents/code-archaeologist.md +6 -0
- package/agents/debug-sidecar.md +6 -0
- package/agents/doc-sidecar.md +6 -0
- package/agents/docs-guardian.md +9 -3
- package/agents/frontend-engineer.md +1 -2
- package/agents/{ai-architect.md → harness-architect.md} +8 -3
- package/agents/implementer.md +6 -1
- package/agents/legacy-discoverer.md +6 -0
- package/agents/legacy-synthesizer.md +6 -0
- package/agents/methodology-researcher.md +6 -1
- package/agents/operational-artifact-builder.md +6 -1
- package/agents/orchestrator.md +27 -87
- package/agents/planner.md +6 -1
- package/agents/presentation-engineer.md +5 -4
- package/agents/python-data-engineer.md +0 -1
- package/agents/researcher.md +6 -0
- package/agents/reviewer.md +6 -1
- package/agents/schema-extractor.md +6 -0
- package/agents/software-architect.md +10 -5
- package/agents/specifier.md +6 -1
- package/agents/task-generator.md +6 -1
- package/agents/test-sidecar.md +6 -0
- package/dist/scripts/generate-hooks-matcher.d.ts +106 -0
- package/dist/scripts/generate-hooks-matcher.d.ts.map +1 -0
- package/dist/scripts/generate-hooks-matcher.js +153 -0
- package/dist/scripts/generate-hooks-matcher.js.map +1 -0
- package/dist/scripts/generate-manifest.d.ts +22 -0
- package/dist/scripts/generate-manifest.d.ts.map +1 -1
- package/dist/scripts/generate-manifest.js +67 -2
- package/dist/scripts/generate-manifest.js.map +1 -1
- package/hooks/agent-git-guard.mjs +63 -11
- package/hooks/dangling-guard.mjs +42 -12
- package/hooks/gate-guardian.mjs +38 -8
- package/hooks/hooks.json +3 -9
- package/hooks/lib/api-client.ts +128 -9
- package/hooks/lib/capability-scanner.ts +391 -55
- package/hooks/lib/dispatch-marker.ts +214 -0
- package/hooks/lib/git-checkpoint.ts +34 -37
- package/hooks/lib/observations-helper.ts +14 -1
- package/hooks/mailbox-listener.mjs +69 -17
- package/hooks/playwright-output-guard.mjs +40 -10
- package/hooks/post-implement.mjs +38 -8
- package/hooks/pre-agent-dispatch.mjs +137 -16
- package/hooks/pre-agent-dispatch.ts +82 -15
- package/hooks/session-start.mjs +274 -103
- package/hooks/session-start.ts +250 -69
- package/hooks/subagent-start.mjs +7665 -22
- package/hooks/subagent-start.ts +367 -16
- package/hooks/subagent-stop.mjs +102 -62
- package/hooks/subagent-stop.ts +124 -28
- package/hooks/user-prompt.mjs +43 -13
- package/hooks/verification-before-completion.mjs +63 -11
- package/hooks/workflow-guard.mjs +45 -11
- package/hooks-settings-template.json +1 -7
- package/manifest.json +62 -62
- package/package.json +4 -2
- package/skills/checkpoint-protocol/SKILL.md +19 -4
- package/skills/ciclo-lane-dispatch/SKILL.md +24 -0
- package/skills/fase-1b-projecao/SKILL.md +146 -0
- package/skills/orchestrator/SKILL.md +11 -3
- package/skills/workflow-coordination/SKILL.md +3 -3
- package/hooks/post-compact.mjs +0 -7931
- package/hooks/post-compact.ts +0 -170
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: software-architect
|
|
3
|
-
description: Arquiteto de software sênior do substrato DETERMINÍSTICO — API, domínio, infraestrutura e código de aplicação. Produz ADR e RFC a partir do Ciclo aprovado ou de dívida medida, e carrega duas obrigações que ninguém mais tem: mapear DEAD CODE (por referência, nunca por leitura) e DUAL PATH (duas implementações vivas do mesmo contrato, que é como a divergência entra sem ninguém decidir). Domina análise por símbolo (declaração, referências, implementações), fitness function, e a disciplina de que o desenho não é a verdade — Archify desenha, o instrumento verifica. Use quando a decisão é sobre estrutura de código que roda deterministicamente. Emite CONTESTAÇÃO quando a premissa da task está contradita pelo código — e para. NÃO use para harness (hooks, skills, agentes, MCP, integrações →
|
|
3
|
+
description: Arquiteto de software sênior do substrato DETERMINÍSTICO — API, domínio, infraestrutura e código de aplicação. Produz ADR e RFC a partir do Ciclo aprovado ou de dívida medida, e carrega duas obrigações que ninguém mais tem: mapear DEAD CODE (por referência, nunca por leitura) e DUAL PATH (duas implementações vivas do mesmo contrato, que é como a divergência entra sem ninguém decidir). Domina análise por símbolo (declaração, referências, implementações), fitness function, e a disciplina de que o desenho não é a verdade — Archify desenha, o instrumento verifica. Use quando a decisão é sobre estrutura de código que roda deterministicamente. Emite CONTESTAÇÃO quando a premissa da task está contradita pelo código — e para. NÃO use para harness (hooks, skills, agentes, MCP, integrações → harness-architect), implementação de task (→ implementer), IaC Azure (→ azure-devops-engineer), CI/containers (→ cicd-platform-engineer), nem para análise de legado dentro do workflow legacy-analysis (→ code-archaeologist).
|
|
4
4
|
tools: Read, Edit, Write, Bash, Grep, Glob, Agent, mcp__plugin_serena_serena__find_symbol, mcp__plugin_serena_serena__find_referencing_symbols, mcp__plugin_serena_serena__find_declaration, mcp__plugin_serena_serena__find_implementations, mcp__plugin_serena_serena__get_symbols_overview, mcp__plugin_serena_serena__search_for_pattern, mcp__plugin_serena_serena__get_diagnostics_for_file, mcp__plugin_context7_context7__resolve-library-id, mcp__plugin_context7_context7__query-docs, mcp__orchestrator-tools__kbSearch, mcp__orchestrator-tools__kbGetDocument, mcp__orchestrator-tools__kbListDocuments, mcp__orchestrator-tools__startAgentInvocation, mcp__orchestrator-tools__completeAgentInvocation, mcp__orchestrator-extended__artifactStore, mcp__orchestrator-extended__artifactRetrieve
|
|
5
5
|
model: opus
|
|
6
6
|
color: blue
|
|
7
7
|
permissionMode: acceptEdits
|
|
8
|
-
memory: project
|
|
9
8
|
skills:
|
|
10
9
|
- kb-lookup
|
|
11
10
|
- project-conventions
|
|
@@ -34,9 +33,9 @@ Você não implementa. Você decide, registra a decisão, e **entrega o mapa do
|
|
|
34
33
|
|---|---|
|
|
35
34
|
| **Entradas** | RFC decomposta · Ciclo aprovado vindo da lane 3 · dívida técnica medida · pergunta de estrutura ("isso cabe onde?") |
|
|
36
35
|
| **Saída** | ADR e/ou RFC · **mapa de dead code** com evidência de não-referência · **mapa de dual path** com os dois caminhos e quem chama cada um · diagrama Archify quando ajuda a decidir |
|
|
37
|
-
| **Fora de escopo** | harness — hooks, skills, agentes, MCP, integrações, distribuição (**`
|
|
36
|
+
| **Fora de escopo** | harness — hooks, skills, agentes, MCP, integrações, distribuição (**`harness-architect`**) · implementar a task (`implementer`) · IaC Azure (`azure-devops-engineer`) · CI e containers (`cicd-platform-engineer`) · varredura de legado dentro do workflow legacy-analysis (`code-archaeologist`) |
|
|
38
37
|
|
|
39
|
-
**A fronteira com o `
|
|
38
|
+
**A fronteira com o `harness-architect` é por substrato, não por assunto.** Os dois produzem ADR e RFC, os dois têm Archify. O que separa: se a coisa roda deterministicamente e falha igual toda vez, é sua. Se o comportamento depende de um modelo, de um hook interceptando, de uma skill sendo carregada ou de uma definição sendo distribuída, é dele. Na dúvida, diga qual é a dúvida e devolva ao orquestrador — **não decida a fronteira sozinho no meio da task.**
|
|
40
39
|
|
|
41
40
|
**Sobreposição declarada com `code-archaeologist`:** ele também detecta dead code, escopado à fase ANALYZE do workflow legacy-analysis, em codebase alheio. Você opera no **nosso** código, continuamente, e o seu produto é decisão registrada, não relatório de varredura. Se a task for análise de legado, devolva.
|
|
42
41
|
|
|
@@ -126,7 +125,7 @@ Quando o instrumento confirma o que você já esperava, **ele não foi testado
|
|
|
126
125
|
|
|
127
126
|
> **Você lança `Explore`, e somente `Explore`.** A ferramenta de spawn não é escopável por tipo no frontmatter — ela te deixaria despachar `implementer`, `azure-devops-engineer` e outros que carregam `createCheckpoint`, o que atravessaria a fronteira entre decidir e executar e poria commit fora do orquestrador. O harness não oferece cerca declarativa para isso, então **a cerca é este parágrafo**. Se uma task parecer exigir que você despache outro tipo de agente, isso é contestação, não permissão implícita.
|
|
128
127
|
|
|
129
|
-
> **Você não cruza para o harness.** Hook, skill, agente, MCP, plugin e distribuição são do `
|
|
128
|
+
> **Você não cruza para o harness.** Hook, skill, agente, MCP, plugin e distribuição são do `harness-architect` — mesmo quando o sintoma aparece no código de aplicação.
|
|
130
129
|
|
|
131
130
|
## CONTESTAÇÃO
|
|
132
131
|
|
|
@@ -156,3 +155,9 @@ DECISÃO PROPOSTA
|
|
|
156
155
|
O QUE EU NÃO CONSEGUI VERIFICAR
|
|
157
156
|
<explícito — e por quê. Esta seção nunca vem vazia por conveniência.>
|
|
158
157
|
```
|
|
158
|
+
|
|
159
|
+
## Memory Protocol
|
|
160
|
+
|
|
161
|
+
Write memories to `.claude/agent-memory/software-architect/` — your **bare** slug directory. Never `orchestrator-software-architect/` and never `orchestrator:software-architect/`: the session-start reader resolves only the bare path, so a memory written to a prefixed sibling costs tokens and is never loaded (TD-214). **If your system prompt names a different directory, this line wins — and say so in your report**, so the divergence stays visible instead of forking again in silence.
|
|
162
|
+
|
|
163
|
+
Each memory is its own `.md` file (frontmatter: `name`, `description`, `type`), plus an entry in `.claude/agent-memory/software-architect/memory-index.yaml`. Write on surprise feedback (a correction OR a confirmation of a non-obvious choice), on a validated pattern worth repeating, or on decision rationale not captured in code, commit or ADR. Do not write what already lives in code, commits, `CLAUDE.md` or ADRs, and do not write ephemeral task state.
|
package/agents/specifier.md
CHANGED
|
@@ -5,7 +5,6 @@ tools: Read, Write, Edit, Grep, Glob, WebSearch, mcp__orchestrator-extended__art
|
|
|
5
5
|
model: sonnet
|
|
6
6
|
color: red
|
|
7
7
|
permissionMode: default
|
|
8
|
-
memory: project
|
|
9
8
|
skills:
|
|
10
9
|
- artifact-production
|
|
11
10
|
- project-conventions
|
|
@@ -350,3 +349,9 @@ When reporting issues in specifications:
|
|
|
350
349
|
| **MEDIUM** | Unclear criteria, potential ambiguity | Should fix, can proceed |
|
|
351
350
|
| **LOW** | Style/formatting issue, minor improvement | Optional, nice to have |
|
|
352
351
|
|
|
352
|
+
|
|
353
|
+
## Memory Protocol
|
|
354
|
+
|
|
355
|
+
Write memories to `.claude/agent-memory/specifier/` — your **bare** slug directory. Never `orchestrator-specifier/` and never `orchestrator:specifier/`: the session-start reader resolves only the bare path, so a memory written to a prefixed sibling costs tokens and is never loaded (TD-214). **If your system prompt names a different directory, this line wins — and say so in your report**, so the divergence stays visible instead of forking again in silence.
|
|
356
|
+
|
|
357
|
+
Each memory is its own `.md` file (frontmatter: `name`, `description`, `type`), plus an entry in `.claude/agent-memory/specifier/memory-index.yaml`. Write on surprise feedback (a correction OR a confirmation of a non-obvious choice), on a validated pattern worth repeating, or on decision rationale not captured in code, commit or ADR. Do not write what already lives in code, commits, `CLAUDE.md` or ADRs, and do not write ephemeral task state.
|
package/agents/task-generator.md
CHANGED
|
@@ -5,7 +5,6 @@ tools: Read, Write, Edit, Grep, Glob, mcp__orchestrator-extended__artifactStore,
|
|
|
5
5
|
model: sonnet
|
|
6
6
|
color: pink
|
|
7
7
|
permissionMode: default
|
|
8
|
-
memory: project
|
|
9
8
|
skills:
|
|
10
9
|
- artifact-production
|
|
11
10
|
- project-conventions
|
|
@@ -380,3 +379,9 @@ When reporting issues in task backlog:
|
|
|
380
379
|
| **MEDIUM** | Unclear priority, missing context | Should fix, can proceed |
|
|
381
380
|
| **LOW** | Minor formatting, optional notes | Optional, nice to have |
|
|
382
381
|
|
|
382
|
+
|
|
383
|
+
## Memory Protocol
|
|
384
|
+
|
|
385
|
+
Write memories to `.claude/agent-memory/task-generator/` — your **bare** slug directory. Never `orchestrator-task-generator/` and never `orchestrator:task-generator/`: the session-start reader resolves only the bare path, so a memory written to a prefixed sibling costs tokens and is never loaded (TD-214). **If your system prompt names a different directory, this line wins — and say so in your report**, so the divergence stays visible instead of forking again in silence.
|
|
386
|
+
|
|
387
|
+
Each memory is its own `.md` file (frontmatter: `name`, `description`, `type`), plus an entry in `.claude/agent-memory/task-generator/memory-index.yaml`. Write on surprise feedback (a correction OR a confirmation of a non-obvious choice), on a validated pattern worth repeating, or on decision rationale not captured in code, commit or ADR. Do not write what already lives in code, commits, `CLAUDE.md` or ADRs, and do not write ephemeral task state.
|
package/agents/test-sidecar.md
CHANGED
|
@@ -110,3 +110,9 @@ Coverage: {pct}% (target: 80%) | Status: {OK | BELOW TARGET}
|
|
|
110
110
|
## Mailbox Protocol
|
|
111
111
|
|
|
112
112
|
When running in a sprint session, follow the **sprint-teammate** skill for the full mailbox protocol (message types, envelope format, inbox/outbox paths). The sprint-teammate skill is injected at session start.
|
|
113
|
+
|
|
114
|
+
## Memory Protocol
|
|
115
|
+
|
|
116
|
+
Write memories to `.claude/agent-memory/test-sidecar/` — your **bare** slug directory. Never `orchestrator-test-sidecar/` and never `orchestrator:test-sidecar/`: the session-start reader resolves only the bare path, so a memory written to a prefixed sibling costs tokens and is never loaded (TD-214). **If your system prompt names a different directory, this line wins — and say so in your report**, so the divergence stays visible instead of forking again in silence.
|
|
117
|
+
|
|
118
|
+
Each memory is its own `.md` file (frontmatter: `name`, `description`, `type`), plus an entry in `.claude/agent-memory/test-sidecar/memory-index.yaml`. Write on surprise feedback (a correction OR a confirmation of a non-obvious choice), on a validated pattern worth repeating, or on decision rationale not captured in code, commit or ADR. Do not write what already lives in code, commits, `CLAUDE.md` or ADRs, and do not write ephemeral task state.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build-time script: generates the SubagentStart/SubagentStop matcher in
|
|
4
|
+
* `hooks/hooks.json` from the canonical agent roster
|
|
5
|
+
* (`packages/definitions/agents/*.md`) — RF-009 (TD-214/TD-239 TASK-007).
|
|
6
|
+
*
|
|
7
|
+
* Problem this fixes: `hooks.json`'s SubagentStart/SubagentStop matcher was
|
|
8
|
+
* a hand-typed 6-name allowlist
|
|
9
|
+
* (`(orchestrator:)?(implementer|specifier|planner|task-generator|reviewer|researcher)`)
|
|
10
|
+
* that was never updated as the agent roster grew to 28 — `docs-guardian`
|
|
11
|
+
* (among 21 others) never received `SubagentStart`'s `[MEMORY-CONTEXT]`
|
|
12
|
+
* injection (RF-010) nor `SubagentStop`'s invocation tracking, because the
|
|
13
|
+
* harness never even fired those hooks for them. This script closes that
|
|
14
|
+
* gap structurally: the matcher is always GENERATED from the real,
|
|
15
|
+
* on-disk `agents/` directory, never typed by hand again.
|
|
16
|
+
*
|
|
17
|
+
* `packages/definitions/agents/` (NOT `.claude/agents`) is the canonical
|
|
18
|
+
* source in THIS repo's own dogfood session — see TD-243 / the
|
|
19
|
+
* `resolveCanonicalAgentsDir()` precedent already shipped in
|
|
20
|
+
* `hooks/subagent-start.ts` (TASK-004, S433): `.claude/agents` resolves to
|
|
21
|
+
* 0 files here (ADR-023 — `.claude/{agents,skills}` is an INSTALL-TARGET,
|
|
22
|
+
* not the SoT, in this repo).
|
|
23
|
+
*
|
|
24
|
+
* DECISION (documented, not accidental — dispatch explicitly required this):
|
|
25
|
+
* `orchestrator.md` IS included in the generated matcher, even though the
|
|
26
|
+
* orchestrator is the main conversation and is never dispatched via
|
|
27
|
+
* `Agent(subagent_type: "orchestrator")`. Rationale: `hooks/subagent-start.ts`
|
|
28
|
+
* TASK-004's OWN runtime canonical-agent-set (`getCanonicalAgentNamesDefault`,
|
|
29
|
+
* feeding `classifyAgentType`) already uses the RAW, unfiltered
|
|
30
|
+
* `scanAgentDefinitions(resolveCanonicalAgentsDir())` — i.e. it already
|
|
31
|
+
* tolerates "orchestrator" as a nominally-classifiable agent name today, in
|
|
32
|
+
* shipped code. Introducing a NEW filter here (excluding orchestrator from
|
|
33
|
+
* the harness-level matcher while the hook-internal allowlist keeps it)
|
|
34
|
+
* would create two divergent "canonical roster" definitions to maintain in
|
|
35
|
+
* lockstep for no functional benefit — the matcher entry is inert either
|
|
36
|
+
* way, since the dispatch that would exercise it never happens. Including it
|
|
37
|
+
* keeps this script a pure, unfiltered "read the directory" generator with
|
|
38
|
+
* zero agent-specific exception logic, which is the whole point of RF-009
|
|
39
|
+
* (never hand-maintain this list again, including the maintenance burden of
|
|
40
|
+
* a hand-maintained EXCLUSION list).
|
|
41
|
+
*
|
|
42
|
+
* Usage: npx tsx src/scripts/generate-hooks-matcher.ts
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Sorted basenames (extension stripped) of every `*.md` file directly under
|
|
46
|
+
* `agentsDir`. Fail-open (returns `[]` on a missing directory) — mirrors
|
|
47
|
+
* `hooks/lib/capability-scanner.ts`'s `scanAgentDefinitions`, deliberately
|
|
48
|
+
* NOT imported from there: this script lives in `src/scripts/` (build-time,
|
|
49
|
+
* plain `.ts`, no bundling), while `capability-scanner.ts` lives in
|
|
50
|
+
* `hooks/lib/` (runtime, gets inlined into `.mjs` bundles by
|
|
51
|
+
* `bundle-hooks.ts`) — cross-importing would couple two independently
|
|
52
|
+
* regenerated artifacts for a five-line function.
|
|
53
|
+
*/
|
|
54
|
+
export declare function scanAgentSlugs(agentsDir: string): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Builds the `(orchestrator:)?(slug1|slug2|...)` matcher string. The
|
|
57
|
+
* `(orchestrator:)?` optional-namespace prefix MUST survive — under plugin
|
|
58
|
+
* scope the harness sends `orchestrator:<agent>`, not a bare agent name (see
|
|
59
|
+
* `hooks/subagent-start.ts` module doc, TASK-004's namespace-normalization
|
|
60
|
+
* fix). Throws on an empty slug list rather than silently emitting
|
|
61
|
+
* `(orchestrator:)?()`, a matcher that matches nothing and would make every
|
|
62
|
+
* `SubagentStart`/`SubagentStop` hook permanently dark without any visible
|
|
63
|
+
* error.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildSubagentMatcher(slugs: string[]): string;
|
|
66
|
+
/**
|
|
67
|
+
* Tests whether `matcher` (as committed in hooks.json) matches `slug` as a
|
|
68
|
+
* COMPLETE string, both bare and under the `orchestrator:` namespace prefix
|
|
69
|
+
* — i.e. does this slug have its own genuine alternative in the matcher,
|
|
70
|
+
* not merely appear as a substring of some other alternative. Anchored
|
|
71
|
+
* (`^...$`) deliberately: this is a stricter, more meaningful check than an
|
|
72
|
+
* unanchored `.test()` would be for "is this slug a real member of the
|
|
73
|
+
* allowlist".
|
|
74
|
+
*/
|
|
75
|
+
export declare function matcherCoversSlug(matcher: string, slug: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Replaces the `"matcher": "..."` value inside BOTH the `SubagentStart` and
|
|
78
|
+
* `SubagentStop` blocks of a `hooks.json` source string with `newMatcher`,
|
|
79
|
+
* leaving everything else (formatting, other hook entries) byte-identical.
|
|
80
|
+
* A plain `JSON.parse` + `JSON.stringify(obj, null, 2)` round-trip was
|
|
81
|
+
* deliberately NOT used here — it would reformat every compact
|
|
82
|
+
* single-line `{ "type": "command", ... }` hook entry onto multiple lines,
|
|
83
|
+
* rewriting the whole file's style for an unrelated reason. Throws if it
|
|
84
|
+
* does not find EXACTLY 2 matches (guards against a silent no-op if
|
|
85
|
+
* hooks.json's SubagentStart/SubagentStop shape is ever restructured).
|
|
86
|
+
*/
|
|
87
|
+
export declare function applyMatcherToHooksJson(hooksJsonContent: string, newMatcher: string): string;
|
|
88
|
+
/**
|
|
89
|
+
* Pure computation: the matcher `hooks.json` SHOULD contain right now,
|
|
90
|
+
* given the real, on-disk `<packageRoot>/agents/` directory. Performs no
|
|
91
|
+
* writes — safe to call from a freshness-check test (mirrors
|
|
92
|
+
* `generate-manifest.ts`'s `generateManifest()` pure/writer split).
|
|
93
|
+
*/
|
|
94
|
+
export declare function generateHooksMatcher(packageRoot?: string): {
|
|
95
|
+
matcher: string;
|
|
96
|
+
slugs: string[];
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Writes the freshly-generated matcher into `<packageRoot>/hooks/hooks.json`.
|
|
100
|
+
* The only function in this module that performs I/O writes.
|
|
101
|
+
*/
|
|
102
|
+
export declare function writeHooksMatcher(packageRoot?: string): {
|
|
103
|
+
matcher: string;
|
|
104
|
+
slugs: string[];
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=generate-hooks-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-hooks-matcher.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-hooks-matcher.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AASH;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAM1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAK5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAiB5F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,GAAE,MAA6B,GAAG;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAIA;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,GAAE,MAA6B,GAAG;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAOA"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build-time script: generates the SubagentStart/SubagentStop matcher in
|
|
4
|
+
* `hooks/hooks.json` from the canonical agent roster
|
|
5
|
+
* (`packages/definitions/agents/*.md`) — RF-009 (TD-214/TD-239 TASK-007).
|
|
6
|
+
*
|
|
7
|
+
* Problem this fixes: `hooks.json`'s SubagentStart/SubagentStop matcher was
|
|
8
|
+
* a hand-typed 6-name allowlist
|
|
9
|
+
* (`(orchestrator:)?(implementer|specifier|planner|task-generator|reviewer|researcher)`)
|
|
10
|
+
* that was never updated as the agent roster grew to 28 — `docs-guardian`
|
|
11
|
+
* (among 21 others) never received `SubagentStart`'s `[MEMORY-CONTEXT]`
|
|
12
|
+
* injection (RF-010) nor `SubagentStop`'s invocation tracking, because the
|
|
13
|
+
* harness never even fired those hooks for them. This script closes that
|
|
14
|
+
* gap structurally: the matcher is always GENERATED from the real,
|
|
15
|
+
* on-disk `agents/` directory, never typed by hand again.
|
|
16
|
+
*
|
|
17
|
+
* `packages/definitions/agents/` (NOT `.claude/agents`) is the canonical
|
|
18
|
+
* source in THIS repo's own dogfood session — see TD-243 / the
|
|
19
|
+
* `resolveCanonicalAgentsDir()` precedent already shipped in
|
|
20
|
+
* `hooks/subagent-start.ts` (TASK-004, S433): `.claude/agents` resolves to
|
|
21
|
+
* 0 files here (ADR-023 — `.claude/{agents,skills}` is an INSTALL-TARGET,
|
|
22
|
+
* not the SoT, in this repo).
|
|
23
|
+
*
|
|
24
|
+
* DECISION (documented, not accidental — dispatch explicitly required this):
|
|
25
|
+
* `orchestrator.md` IS included in the generated matcher, even though the
|
|
26
|
+
* orchestrator is the main conversation and is never dispatched via
|
|
27
|
+
* `Agent(subagent_type: "orchestrator")`. Rationale: `hooks/subagent-start.ts`
|
|
28
|
+
* TASK-004's OWN runtime canonical-agent-set (`getCanonicalAgentNamesDefault`,
|
|
29
|
+
* feeding `classifyAgentType`) already uses the RAW, unfiltered
|
|
30
|
+
* `scanAgentDefinitions(resolveCanonicalAgentsDir())` — i.e. it already
|
|
31
|
+
* tolerates "orchestrator" as a nominally-classifiable agent name today, in
|
|
32
|
+
* shipped code. Introducing a NEW filter here (excluding orchestrator from
|
|
33
|
+
* the harness-level matcher while the hook-internal allowlist keeps it)
|
|
34
|
+
* would create two divergent "canonical roster" definitions to maintain in
|
|
35
|
+
* lockstep for no functional benefit — the matcher entry is inert either
|
|
36
|
+
* way, since the dispatch that would exercise it never happens. Including it
|
|
37
|
+
* keeps this script a pure, unfiltered "read the directory" generator with
|
|
38
|
+
* zero agent-specific exception logic, which is the whole point of RF-009
|
|
39
|
+
* (never hand-maintain this list again, including the maintenance burden of
|
|
40
|
+
* a hand-maintained EXCLUSION list).
|
|
41
|
+
*
|
|
42
|
+
* Usage: npx tsx src/scripts/generate-hooks-matcher.ts
|
|
43
|
+
*/
|
|
44
|
+
import { readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs';
|
|
45
|
+
import { resolve, join, dirname } from 'node:path';
|
|
46
|
+
import { fileURLToPath } from 'node:url';
|
|
47
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
48
|
+
const DEFAULT_PACKAGE_ROOT = resolve(__dirname, '../..');
|
|
49
|
+
/**
|
|
50
|
+
* Sorted basenames (extension stripped) of every `*.md` file directly under
|
|
51
|
+
* `agentsDir`. Fail-open (returns `[]` on a missing directory) — mirrors
|
|
52
|
+
* `hooks/lib/capability-scanner.ts`'s `scanAgentDefinitions`, deliberately
|
|
53
|
+
* NOT imported from there: this script lives in `src/scripts/` (build-time,
|
|
54
|
+
* plain `.ts`, no bundling), while `capability-scanner.ts` lives in
|
|
55
|
+
* `hooks/lib/` (runtime, gets inlined into `.mjs` bundles by
|
|
56
|
+
* `bundle-hooks.ts`) — cross-importing would couple two independently
|
|
57
|
+
* regenerated artifacts for a five-line function.
|
|
58
|
+
*/
|
|
59
|
+
export function scanAgentSlugs(agentsDir) {
|
|
60
|
+
if (!existsSync(agentsDir))
|
|
61
|
+
return [];
|
|
62
|
+
return readdirSync(agentsDir)
|
|
63
|
+
.filter((f) => f.endsWith('.md'))
|
|
64
|
+
.map((f) => f.replace(/\.md$/, ''))
|
|
65
|
+
.sort();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Builds the `(orchestrator:)?(slug1|slug2|...)` matcher string. The
|
|
69
|
+
* `(orchestrator:)?` optional-namespace prefix MUST survive — under plugin
|
|
70
|
+
* scope the harness sends `orchestrator:<agent>`, not a bare agent name (see
|
|
71
|
+
* `hooks/subagent-start.ts` module doc, TASK-004's namespace-normalization
|
|
72
|
+
* fix). Throws on an empty slug list rather than silently emitting
|
|
73
|
+
* `(orchestrator:)?()`, a matcher that matches nothing and would make every
|
|
74
|
+
* `SubagentStart`/`SubagentStop` hook permanently dark without any visible
|
|
75
|
+
* error.
|
|
76
|
+
*/
|
|
77
|
+
export function buildSubagentMatcher(slugs) {
|
|
78
|
+
if (slugs.length === 0) {
|
|
79
|
+
throw new Error('buildSubagentMatcher: empty slug list would produce a vacuous matcher');
|
|
80
|
+
}
|
|
81
|
+
return `(orchestrator:)?(${slugs.join('|')})`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Tests whether `matcher` (as committed in hooks.json) matches `slug` as a
|
|
85
|
+
* COMPLETE string, both bare and under the `orchestrator:` namespace prefix
|
|
86
|
+
* — i.e. does this slug have its own genuine alternative in the matcher,
|
|
87
|
+
* not merely appear as a substring of some other alternative. Anchored
|
|
88
|
+
* (`^...$`) deliberately: this is a stricter, more meaningful check than an
|
|
89
|
+
* unanchored `.test()` would be for "is this slug a real member of the
|
|
90
|
+
* allowlist".
|
|
91
|
+
*/
|
|
92
|
+
export function matcherCoversSlug(matcher, slug) {
|
|
93
|
+
const re = new RegExp(`^${matcher}$`);
|
|
94
|
+
return re.test(slug) && re.test(`orchestrator:${slug}`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Replaces the `"matcher": "..."` value inside BOTH the `SubagentStart` and
|
|
98
|
+
* `SubagentStop` blocks of a `hooks.json` source string with `newMatcher`,
|
|
99
|
+
* leaving everything else (formatting, other hook entries) byte-identical.
|
|
100
|
+
* A plain `JSON.parse` + `JSON.stringify(obj, null, 2)` round-trip was
|
|
101
|
+
* deliberately NOT used here — it would reformat every compact
|
|
102
|
+
* single-line `{ "type": "command", ... }` hook entry onto multiple lines,
|
|
103
|
+
* rewriting the whole file's style for an unrelated reason. Throws if it
|
|
104
|
+
* does not find EXACTLY 2 matches (guards against a silent no-op if
|
|
105
|
+
* hooks.json's SubagentStart/SubagentStop shape is ever restructured).
|
|
106
|
+
*/
|
|
107
|
+
export function applyMatcherToHooksJson(hooksJsonContent, newMatcher) {
|
|
108
|
+
let replacements = 0;
|
|
109
|
+
const updated = hooksJsonContent.replace(/("(?:SubagentStart|SubagentStop)":\s*\[\s*\{\s*"matcher":\s*")[^"]*(")/g, (_match, pre, post) => {
|
|
110
|
+
replacements++;
|
|
111
|
+
return `${pre}${newMatcher}${post}`;
|
|
112
|
+
});
|
|
113
|
+
if (replacements !== 2) {
|
|
114
|
+
throw new Error(`applyMatcherToHooksJson: expected exactly 2 matcher replacements ` +
|
|
115
|
+
`(SubagentStart + SubagentStop), found ${String(replacements)} — ` +
|
|
116
|
+
`hooks.json's shape may have changed; update this script's regex.`);
|
|
117
|
+
}
|
|
118
|
+
return updated;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Pure computation: the matcher `hooks.json` SHOULD contain right now,
|
|
122
|
+
* given the real, on-disk `<packageRoot>/agents/` directory. Performs no
|
|
123
|
+
* writes — safe to call from a freshness-check test (mirrors
|
|
124
|
+
* `generate-manifest.ts`'s `generateManifest()` pure/writer split).
|
|
125
|
+
*/
|
|
126
|
+
export function generateHooksMatcher(packageRoot = DEFAULT_PACKAGE_ROOT) {
|
|
127
|
+
const slugs = scanAgentSlugs(join(packageRoot, 'agents'));
|
|
128
|
+
const matcher = buildSubagentMatcher(slugs);
|
|
129
|
+
return { matcher, slugs };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Writes the freshly-generated matcher into `<packageRoot>/hooks/hooks.json`.
|
|
133
|
+
* The only function in this module that performs I/O writes.
|
|
134
|
+
*/
|
|
135
|
+
export function writeHooksMatcher(packageRoot = DEFAULT_PACKAGE_ROOT) {
|
|
136
|
+
const { matcher, slugs } = generateHooksMatcher(packageRoot);
|
|
137
|
+
const hooksJsonPath = join(packageRoot, 'hooks', 'hooks.json');
|
|
138
|
+
const content = readFileSync(hooksJsonPath, 'utf-8');
|
|
139
|
+
const updated = applyMatcherToHooksJson(content, matcher);
|
|
140
|
+
writeFileSync(hooksJsonPath, updated);
|
|
141
|
+
return { matcher, slugs };
|
|
142
|
+
}
|
|
143
|
+
// ─── CLI Entry Guard ──────────────────────────────────────────────────────────
|
|
144
|
+
// Mirrors the pattern in generate-manifest.ts / sync-hook-mirrors.ts:
|
|
145
|
+
// importing this module (e.g. from a test) must NOT trigger a write — only
|
|
146
|
+
// direct CLI execution does.
|
|
147
|
+
const isCli = process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1];
|
|
148
|
+
if (isCli) {
|
|
149
|
+
const { matcher, slugs } = writeHooksMatcher();
|
|
150
|
+
console.log(`Generated hooks.json SubagentStart/SubagentStop matcher (${String(slugs.length)} agents):`);
|
|
151
|
+
console.log(` ${matcher}`);
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=generate-hooks-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-hooks-matcher.js","sourceRoot":"","sources":["../../src/scripts/generate-hooks-matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,10 +20,32 @@ import type { ManifestSchema } from '../manifest/types.js';
|
|
|
20
20
|
* called with no argument (preserves the original CLI behavior).
|
|
21
21
|
*/
|
|
22
22
|
export declare function generateManifest(packageRoot?: string): ManifestSchema;
|
|
23
|
+
/**
|
|
24
|
+
* True when two manifests differ ONLY by their `generatedAt` stamp — i.e. the
|
|
25
|
+
* substantive content (schema, namespace, version, and every definition entry
|
|
26
|
+
* with its content-derived checksum) is identical.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isManifestContentEqual(a: ManifestSchema, b: ManifestSchema): boolean;
|
|
23
29
|
/**
|
|
24
30
|
* Thin writer: computes the manifest via generateManifest() and writes it to
|
|
25
31
|
* <packageRoot>/manifest.json. This is the only function in this module that
|
|
26
32
|
* performs I/O writes.
|
|
33
|
+
*
|
|
34
|
+
* IDEMPOTENT (S445 Task B). `generatedAt` is the only clock-derived field in the
|
|
35
|
+
* manifest — every other field is content-derived (SHA256 checksums). Stamping a
|
|
36
|
+
* fresh timestamp unconditionally meant that every `npm run build` produced a
|
|
37
|
+
* diff in the git-TRACKED manifest.json even when not a single byte of any
|
|
38
|
+
* definition had changed. Two costs, both real and both paid repeatedly: the
|
|
39
|
+
* working tree was left dirty after any build (and the release requires a clean
|
|
40
|
+
* tree), and readers were trained to wave away diffs in the one file whose diffs
|
|
41
|
+
* carry the checksum of every distributed definition.
|
|
42
|
+
*
|
|
43
|
+
* So `generatedAt` is preserved whenever the content is unchanged, and the write
|
|
44
|
+
* is skipped entirely when the resulting bytes would be identical (this also
|
|
45
|
+
* leaves mtime alone, so mtime-based caches elsewhere are not churned either).
|
|
46
|
+
* The field keeps its documented meaning and stays a real ISO instant: it now
|
|
47
|
+
* answers "when was this manifest generated", where before it answered "when was
|
|
48
|
+
* this build last run" — which is what made it non-reproducible.
|
|
27
49
|
*/
|
|
28
50
|
export declare function writeManifest(packageRoot?: string): ManifestSchema;
|
|
29
51
|
//# sourceMappingURL=generate-manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-manifest.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAkF5E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,GAAE,MAA6B,GAAG,cAAc,CAuC3F;
|
|
1
|
+
{"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-manifest.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAkF5E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,GAAE,MAA6B,GAAG,cAAc,CAuC3F;AA0BD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAIpF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,WAAW,GAAE,MAA6B,GAAG,cAAc,CAwBxF"}
|
|
@@ -121,15 +121,80 @@ export function generateManifest(packageRoot = DEFAULT_PACKAGE_ROOT) {
|
|
|
121
121
|
};
|
|
122
122
|
return manifest;
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Deep structural equality ignoring key order. Used to answer "did the manifest
|
|
126
|
+
* CONTENT change?" — the previous manifest is parsed from disk, so its key order
|
|
127
|
+
* comes from the file and cannot be compared by raw serialization.
|
|
128
|
+
*/
|
|
129
|
+
function deepEqual(a, b) {
|
|
130
|
+
if (a === b)
|
|
131
|
+
return true;
|
|
132
|
+
if (typeof a !== typeof b || a === null || b === null)
|
|
133
|
+
return false;
|
|
134
|
+
if (typeof a !== 'object')
|
|
135
|
+
return false;
|
|
136
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
137
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
|
|
138
|
+
return false;
|
|
139
|
+
return a.every((item, i) => deepEqual(item, b[i]));
|
|
140
|
+
}
|
|
141
|
+
const aKeys = Object.keys(a).sort();
|
|
142
|
+
const bKeys = Object.keys(b).sort();
|
|
143
|
+
if (aKeys.length !== bKeys.length || !aKeys.every((k, i) => k === bKeys[i]))
|
|
144
|
+
return false;
|
|
145
|
+
return aKeys.every((k) => deepEqual(a[k], b[k]));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* True when two manifests differ ONLY by their `generatedAt` stamp — i.e. the
|
|
149
|
+
* substantive content (schema, namespace, version, and every definition entry
|
|
150
|
+
* with its content-derived checksum) is identical.
|
|
151
|
+
*/
|
|
152
|
+
export function isManifestContentEqual(a, b) {
|
|
153
|
+
const { generatedAt: _a, ...restA } = a;
|
|
154
|
+
const { generatedAt: _b, ...restB } = b;
|
|
155
|
+
return deepEqual(restA, restB);
|
|
156
|
+
}
|
|
124
157
|
/**
|
|
125
158
|
* Thin writer: computes the manifest via generateManifest() and writes it to
|
|
126
159
|
* <packageRoot>/manifest.json. This is the only function in this module that
|
|
127
160
|
* performs I/O writes.
|
|
161
|
+
*
|
|
162
|
+
* IDEMPOTENT (S445 Task B). `generatedAt` is the only clock-derived field in the
|
|
163
|
+
* manifest — every other field is content-derived (SHA256 checksums). Stamping a
|
|
164
|
+
* fresh timestamp unconditionally meant that every `npm run build` produced a
|
|
165
|
+
* diff in the git-TRACKED manifest.json even when not a single byte of any
|
|
166
|
+
* definition had changed. Two costs, both real and both paid repeatedly: the
|
|
167
|
+
* working tree was left dirty after any build (and the release requires a clean
|
|
168
|
+
* tree), and readers were trained to wave away diffs in the one file whose diffs
|
|
169
|
+
* carry the checksum of every distributed definition.
|
|
170
|
+
*
|
|
171
|
+
* So `generatedAt` is preserved whenever the content is unchanged, and the write
|
|
172
|
+
* is skipped entirely when the resulting bytes would be identical (this also
|
|
173
|
+
* leaves mtime alone, so mtime-based caches elsewhere are not churned either).
|
|
174
|
+
* The field keeps its documented meaning and stays a real ISO instant: it now
|
|
175
|
+
* answers "when was this manifest generated", where before it answered "when was
|
|
176
|
+
* this build last run" — which is what made it non-reproducible.
|
|
128
177
|
*/
|
|
129
178
|
export function writeManifest(packageRoot = DEFAULT_PACKAGE_ROOT) {
|
|
130
|
-
const
|
|
179
|
+
const next = generateManifest(packageRoot);
|
|
131
180
|
const outputPath = resolve(packageRoot, 'manifest.json');
|
|
132
|
-
|
|
181
|
+
let previousRaw = null;
|
|
182
|
+
let previous = null;
|
|
183
|
+
try {
|
|
184
|
+
previousRaw = readFileSync(outputPath, 'utf-8');
|
|
185
|
+
previous = JSON.parse(previousRaw);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Absent or unparseable (cold start / corrupted) — fall through and write.
|
|
189
|
+
previous = null;
|
|
190
|
+
}
|
|
191
|
+
const manifest = previous && isManifestContentEqual(previous, next)
|
|
192
|
+
? { ...next, generatedAt: previous.generatedAt }
|
|
193
|
+
: next;
|
|
194
|
+
const serialized = JSON.stringify(manifest, null, 2) + '\n';
|
|
195
|
+
if (previousRaw === serialized)
|
|
196
|
+
return manifest;
|
|
197
|
+
writeFileSync(outputPath, serialized);
|
|
133
198
|
return manifest;
|
|
134
199
|
}
|
|
135
200
|
// ─── CLI Entry Guard ──────────────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-manifest.js","sourceRoot":"","sources":["../../src/scripts/generate-manifest.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"generate-manifest.js","sourceRoot":"","sources":["../../src/scripts/generate-manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,19 +2,71 @@ import { createRequire as __createRequireShim } from 'node:module'; const requir
|
|
|
2
2
|
|
|
3
3
|
// hooks/lib/api-client.ts
|
|
4
4
|
import { readFileSync, writeFileSync, mkdirSync, statSync, unlinkSync, readdirSync } from "node:fs";
|
|
5
|
-
import { join
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
import { join as join2 } from "node:path";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
|
|
9
|
+
// ../project-root-resolver/dist/index.js
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
function hasProjectRootMarker(candidate, sentinel) {
|
|
13
|
+
return existsSync(join(candidate, ".git")) || existsSync(join(candidate, "package.json")) || existsSync(join(candidate, sentinel, ".root"));
|
|
14
|
+
}
|
|
15
|
+
function resolveProjectRoot(cwd, sentinel = ".orchestrator") {
|
|
16
|
+
const candidates = [];
|
|
17
|
+
let currentDir = cwd;
|
|
18
|
+
for (; ; ) {
|
|
19
|
+
if (existsSync(join(currentDir, sentinel))) {
|
|
20
|
+
candidates.push(currentDir);
|
|
21
|
+
}
|
|
22
|
+
const parentDir = dirname(currentDir);
|
|
23
|
+
if (parentDir === currentDir) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
currentDir = parentDir;
|
|
27
|
+
}
|
|
28
|
+
const [innermost] = candidates;
|
|
29
|
+
if (innermost === void 0) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
for (const candidate of candidates) {
|
|
33
|
+
if (hasProjectRootMarker(candidate, sentinel)) {
|
|
34
|
+
return candidate;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return innermost;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// hooks/lib/api-client.ts
|
|
41
|
+
function resolveFallbackStateDir(cwd) {
|
|
42
|
+
const cwdHash = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
|
|
43
|
+
return join2(tmpdir(), "orchestrator-hook-fallback", cwdHash);
|
|
44
|
+
}
|
|
45
|
+
var PROJECT_ROOT = (() => {
|
|
46
|
+
const resolved = resolveHookProjectRoot(process.cwd());
|
|
47
|
+
if (resolved !== null && hasProjectRootMarker(resolved, ".orchestrator")) {
|
|
48
|
+
return resolved;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
})();
|
|
52
|
+
var STATE_DIR_OVERRIDE = process.env.ORCHESTRATOR_STATE_DIR;
|
|
53
|
+
var STATE_DIR = STATE_DIR_OVERRIDE !== void 0 && STATE_DIR_OVERRIDE !== "" ? STATE_DIR_OVERRIDE : PROJECT_ROOT !== null ? join2(PROJECT_ROOT, ".orchestrator", ".state") : resolveFallbackStateDir(process.cwd());
|
|
54
|
+
var JWT_CACHE = join2(STATE_DIR, "jwt-token");
|
|
55
|
+
var DEBUG_LOG = join2(STATE_DIR, "hook-debug.log");
|
|
13
56
|
mkdirSync(STATE_DIR, { recursive: true });
|
|
57
|
+
if ((STATE_DIR_OVERRIDE === void 0 || STATE_DIR_OVERRIDE === "") && PROJECT_ROOT === null) {
|
|
58
|
+
log(
|
|
59
|
+
"API-CLIENT",
|
|
60
|
+
`PROJECT_ROOT: no marker-verified ".orchestrator" project root found above ${process.cwd()} \u2014 falling back to isolated state dir ${STATE_DIR} (RF-003)`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
14
63
|
var API_URL = process.env.ORCHESTRATOR_API_URL || "http://localhost:3001";
|
|
15
64
|
var AUTH_EMAIL = process.env.ORCHESTRATOR_ADMIN_EMAIL || process.env.ORCHESTRATOR_AUTH_EMAIL || "system@orchestrator.local";
|
|
16
65
|
var AUTH_PASSWORD = process.env.ORCHESTRATOR_ADMIN_PASSWORD || process.env.ORCHESTRATOR_AUTH_PASSWORD || "system123";
|
|
17
66
|
var PROJECT_ID = process.env.ORCHESTRATOR_PROJECT_ID || "";
|
|
67
|
+
function resolveHookProjectRoot(cwd) {
|
|
68
|
+
return resolveProjectRoot(cwd);
|
|
69
|
+
}
|
|
18
70
|
function log(prefix, msg) {
|
|
19
71
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
|
|
20
72
|
try {
|
|
@@ -24,11 +76,11 @@ function log(prefix, msg) {
|
|
|
24
76
|
} catch {
|
|
25
77
|
}
|
|
26
78
|
}
|
|
27
|
-
var LAST_COMPLETED_FILE =
|
|
79
|
+
var LAST_COMPLETED_FILE = join2(STATE_DIR, "last-completed-workflow.json");
|
|
28
80
|
var LAST_COMPLETED_TTL_MS = 60 * 60 * 1e3;
|
|
29
|
-
var INVOCATIONS_DIR =
|
|
81
|
+
var INVOCATIONS_DIR = join2(STATE_DIR, "invocations");
|
|
30
82
|
var INVOCATION_STATE_TTL_MS = 4 * 60 * 60 * 1e3;
|
|
31
|
-
var DISPATCH_INTENT_DIR =
|
|
83
|
+
var DISPATCH_INTENT_DIR = join2(STATE_DIR, "dispatch-intent");
|
|
32
84
|
async function readStdin() {
|
|
33
85
|
const chunks = [];
|
|
34
86
|
for await (const chunk of process.stdin) {
|