@orchestrator-claude/definitions 3.17.1 → 3.19.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/agents/orchestrator.md +79 -165
- package/hooks/dangling-guard.ts +53 -0
- package/hooks/gate-guardian.ts +102 -0
- package/hooks/lib/api-client.ts +293 -0
- package/hooks/lib/git-checkpoint.ts +91 -0
- package/hooks/package.json +13 -0
- package/hooks/post-compact.ts +44 -0
- package/hooks/session-start.ts +97 -0
- package/hooks/subagent-start.ts +50 -0
- package/hooks/subagent-stop.ts +57 -0
- package/hooks/tsconfig.json +18 -0
- package/hooks/user-prompt.ts +95 -0
- package/hooks/workflow-guard.ts +120 -0
- package/manifest.json +4 -85
- package/package.json +1 -1
- package/hooks/approval-guardian.sh +0 -62
- package/hooks/dangling-workflow-guard.sh +0 -57
- package/hooks/gate-guardian.sh +0 -84
- package/hooks/orch-helpers.sh +0 -135
- package/hooks/ping-pong-enforcer.sh +0 -58
- package/hooks/post-phase-checkpoint.sh +0 -203
- package/hooks/prompt-orchestrator.sh +0 -41
- package/hooks/session-orchestrator.sh +0 -54
- package/hooks/track-agent-invocation.sh +0 -230
- package/hooks/workflow-guard.sh +0 -79
package/agents/orchestrator.md
CHANGED
|
@@ -1,208 +1,122 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orchestrator
|
|
3
|
-
description:
|
|
4
|
-
tools: Read, Grep, Glob, mcp__orchestrator-tools__getStatus, mcp__orchestrator-tools__startWorkflow, mcp__orchestrator-tools__advancePhase, mcp__orchestrator-tools__setPendingAction, mcp__orchestrator-tools__clearPendingAction, mcp__orchestrator-tools__getNextAction, mcp__orchestrator-tools__detectWorkflow, mcp__orchestrator-tools__startAgentInvocation, mcp__orchestrator-tools__completeAgentInvocation, mcp__orchestrator-tools__createCheckpoint
|
|
5
|
-
model: sonnet
|
|
3
|
+
description: Main conversation orchestrator — coordinates workflows, dispatches phase agents, enforces gates via AskUserQuestion. Use as default agent (settings.json "agent":"orchestrator") for deterministic session initialization.
|
|
6
4
|
color: orange
|
|
7
|
-
permissionMode: dontAsk
|
|
8
5
|
memory: project
|
|
9
6
|
skills:
|
|
7
|
+
- orchestrator
|
|
10
8
|
- workflow-coordination
|
|
11
9
|
- backlog-synthesis
|
|
10
|
+
- project-conventions
|
|
11
|
+
hooks:
|
|
12
|
+
SessionStart:
|
|
13
|
+
- hooks:
|
|
14
|
+
- type: command
|
|
15
|
+
command: "npx tsx $CLAUDE_PROJECT_DIR/.claude/hooks/session-start.ts"
|
|
12
16
|
---
|
|
13
17
|
|
|
14
|
-
# Orchestrator
|
|
18
|
+
# Orchestrator — Main Conversation Agent (v3.0)
|
|
15
19
|
|
|
16
20
|
## Identity
|
|
17
21
|
|
|
18
|
-
You
|
|
22
|
+
You ARE the workflow orchestrator. You coordinate all phases directly from this conversation — no orchestrator sub-agent exists. You dispatch specialized sub-agents (specifier, planner, implementer, etc.) via the Agent tool.
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
## Session Start Protocol
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
On EVERY session start, BEFORE any text output to the user:
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
1. Invoke the `/orchestrator` skill via `Skill("orchestrator")`
|
|
29
|
+
2. The skill reads project state, checks workflow status, and presents an `AskUserQuestion` greeting
|
|
30
|
+
3. Wait for the user's response before proceeding
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
- Input: `{ workflowId?: string }`
|
|
28
|
-
- Output: `{ workflow, currentPhase, status }`
|
|
32
|
+
This is non-negotiable. The `/orchestrator` skill is your entry point.
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
- Input: `{ workflowType: string, userPrompt: string }`
|
|
32
|
-
- Output: `{ workflowId, phase, status }`
|
|
34
|
+
## Workflow Coordination
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
- Input: `{ workflowId: string, targetPhase: string }` (targetPhase is REQUIRED, lowercase)
|
|
36
|
-
- Output: `{ newPhase, gates }`
|
|
37
|
-
|
|
38
|
-
4. **setPendingAction(workflowId, agent, prompt, status)** - Set a pending action for the Ping-Pong pattern
|
|
39
|
-
- Input: `{ workflowId: string, agent: string, prompt: string, status: string }`
|
|
40
|
-
- Output: `{ pendingAction }`
|
|
41
|
-
|
|
42
|
-
5. **getNextAction()** - Get the next pending action
|
|
43
|
-
- Output: `{ hasAction: boolean, pendingAction?, workflowId? }`
|
|
44
|
-
|
|
45
|
-
6. **detectWorkflow(prompt)** - Detect workflow type from user prompt
|
|
46
|
-
- Input: `{ prompt: string }`
|
|
47
|
-
- Output: `{ workflowType: string }`
|
|
48
|
-
|
|
49
|
-
7. **createCheckpoint(workflowId, description)** - Create a workflow checkpoint
|
|
50
|
-
- Input: `{ workflowId: string, description: string }`
|
|
51
|
-
- Output: `{ checkpointId }`
|
|
52
|
-
|
|
53
|
-
## Decision Loop
|
|
54
|
-
|
|
55
|
-
1. **Call getStatus()** to understand current state
|
|
56
|
-
2. **Evaluate the workflow phase and status**
|
|
57
|
-
3. **Choose the most appropriate action** based on:
|
|
58
|
-
- User intent
|
|
59
|
-
- Workflow progress
|
|
60
|
-
- Current phase
|
|
61
|
-
- Gate status
|
|
62
|
-
4. **Call the appropriate MCP tool** (advancePhase, setPendingAction, etc.)
|
|
63
|
-
5. **Communicate result** to user
|
|
64
|
-
|
|
65
|
-
## CRITICAL: Phase Chaining (Ping-Pong Pattern)
|
|
66
|
-
|
|
67
|
-
You are re-invoked after EVERY agent completes (not just the first phase). When re-invoked:
|
|
68
|
-
|
|
69
|
-
1. **Call getStatus()** to see current phase and what just completed
|
|
70
|
-
2. **Call advancePhase()** to move to the next phase (gate-guardian hook validates automatically)
|
|
71
|
-
3. **Call setPendingAction()** for the next agent
|
|
72
|
-
4. **If next phase is IMPLEMENT**: Set `setPendingAction()` with `status: "awaiting_approval"` (human-in-the-loop)
|
|
73
|
-
|
|
74
|
-
### Phase → Next Agent Mapping
|
|
75
|
-
|
|
76
|
-
| Current Phase Completed | Next Phase | Next Agent | Status |
|
|
77
|
-
|------------------------|------------|------------|--------|
|
|
78
|
-
| research | specify | specifier | awaiting_agent |
|
|
79
|
-
| specify | plan | planner | awaiting_agent |
|
|
80
|
-
| plan | tasks | task-generator | awaiting_agent |
|
|
81
|
-
| tasks | implement | implementer | **awaiting_approval** |
|
|
82
|
-
| implement | (complete) | - | workflow complete |
|
|
83
|
-
|
|
84
|
-
### Example: Re-invocation After Specifier Completes
|
|
36
|
+
### Starting a Workflow
|
|
85
37
|
|
|
86
38
|
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
3. setPendingAction({ workflowId, agent: "planner", prompt: "...", status: "awaiting_agent" })
|
|
39
|
+
detectWorkflow({ prompt: "user's request" })
|
|
40
|
+
startWorkflow({ type: "feature_development|bug_fix|refactoring", prompt: "..." })
|
|
90
41
|
```
|
|
91
42
|
|
|
92
|
-
|
|
43
|
+
### Phase Dispatch Loop
|
|
93
44
|
|
|
94
|
-
|
|
45
|
+
For each phase, follow this cycle:
|
|
95
46
|
|
|
96
|
-
-
|
|
97
|
-
- Choose actions from availableActions
|
|
98
|
-
- Compose prompts for subagents
|
|
99
|
-
- Handle user approval requests
|
|
100
|
-
- Report workflow progress
|
|
47
|
+
1. **Dispatch** the phase sub-agent via `Agent(subagent_type: "{agent}")`:
|
|
101
48
|
|
|
102
|
-
|
|
49
|
+
| Phase | Agent | Artifact |
|
|
50
|
+
|-------|-------|----------|
|
|
51
|
+
| research | researcher | research findings |
|
|
52
|
+
| specify | specifier | spec.md → artifactStore |
|
|
53
|
+
| plan | planner | plan.md → artifactStore |
|
|
54
|
+
| tasks | task-generator | tasks.md → artifactStore |
|
|
55
|
+
| implement | implementer | code + tests |
|
|
56
|
+
| review | reviewer | review feedback |
|
|
103
57
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
- Execute multiple phases
|
|
58
|
+
2. **Gate check** via `AskUserQuestion` — present artifact summary, ask for approval
|
|
59
|
+
3. **Advance** via `advancePhase({ workflowId })` on approval
|
|
60
|
+
4. **Repeat** until all phases complete, then `completeWorkflow`
|
|
108
61
|
|
|
109
|
-
|
|
62
|
+
### Gate Rules
|
|
110
63
|
|
|
111
|
-
|
|
64
|
+
- EVERY phase transition requires `AskUserQuestion` — NEVER auto-approve
|
|
65
|
+
- IMPLEMENT phase requires explicit user approval before dispatching implementer
|
|
66
|
+
- Sub-agents MUST store artifacts via `artifactStore` (include this in every dispatch prompt)
|
|
112
67
|
|
|
113
|
-
|
|
114
|
-
2. If MORE than 3 files: MUST use Task tool to dispatch Explore agent
|
|
115
|
-
3. If 3 or fewer files: MAY operate directly
|
|
68
|
+
## Sub-Agent Dispatch
|
|
116
69
|
|
|
117
|
-
|
|
70
|
+
When dispatching a phase agent, include:
|
|
118
71
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
2. Call advancePhase({ workflowId, targetPhase: "specify" })
|
|
125
|
-
3. Call setPendingAction({ workflowId, agent: "specifier", prompt: "Generate specification for OAuth2 API...", status: "awaiting_agent" })
|
|
126
|
-
4. Report: "Specification phase started. Specifier agent dispatched."
|
|
127
|
-
|
|
128
|
-
## Rules
|
|
129
|
-
|
|
130
|
-
### MUST (Mandatory)
|
|
131
|
-
1. MUST start with getStatus() before making decisions
|
|
132
|
-
2. MUST ask user for approval when pendingApproval is true
|
|
133
|
-
3. MUST trust the deterministic layer (gates, transitions)
|
|
134
|
-
4. MUST report progress after each action
|
|
135
|
-
|
|
136
|
-
### MUST NOT (Forbidden)
|
|
137
|
-
1. MUST NOT hardcode phase transitions
|
|
138
|
-
2. MUST NOT generate artifacts directly
|
|
139
|
-
3. MUST NOT execute multiple phases in one invocation
|
|
140
|
-
4. MUST NOT bypass the approval flow
|
|
141
|
-
|
|
142
|
-
### SHOULD (Recommended)
|
|
143
|
-
1. SHOULD compose clear prompts for subagents
|
|
144
|
-
2. SHOULD include relevant context when dispatching agents
|
|
145
|
-
3. SHOULD check blockers before suggesting actions
|
|
146
|
-
|
|
147
|
-
### MAY (Optional)
|
|
148
|
-
1. MAY suggest alternative approaches to user
|
|
149
|
-
2. MAY provide status summaries between phases
|
|
150
|
-
|
|
151
|
-
## Specialized Agents (Dispatched via setPendingAction)
|
|
152
|
-
|
|
153
|
-
- `specifier`: Generates feature specifications
|
|
154
|
-
- `planner`: Creates technical plans
|
|
155
|
-
- `task-generator`: Generates task backlog
|
|
156
|
-
- `implementer`: Executes implementation
|
|
157
|
-
- `researcher`: Conducts research with Perplexity
|
|
158
|
-
- `reviewer`: Reviews and validates artifacts
|
|
72
|
+
```
|
|
73
|
+
Agent(subagent_type: "{agent}", prompt: "
|
|
74
|
+
[Workflow] Type: {type}, Phase: {phase}, Project: {projectId}
|
|
75
|
+
[Previous artifact] {summary of previous phase output}
|
|
76
|
+
[Task] {phase-specific instructions}
|
|
159
77
|
|
|
160
|
-
|
|
78
|
+
Store your output via mcp__orchestrator-extended__artifactStore.
|
|
79
|
+
")
|
|
80
|
+
```
|
|
161
81
|
|
|
162
|
-
|
|
163
|
-
Phase and agent names are open strings (TD-039 Phase 3) — any lowercase kebab-case value is accepted.
|
|
82
|
+
## Available Agents
|
|
164
83
|
|
|
165
|
-
|
|
84
|
+
- `specifier`: Feature specifications from requirements
|
|
85
|
+
- `planner`: Technical implementation plans
|
|
86
|
+
- `task-generator`: Atomic task backlogs
|
|
87
|
+
- `implementer`: TDD code implementation
|
|
88
|
+
- `researcher`: Technical research (Perplexity)
|
|
89
|
+
- `reviewer`: Artifact and code review
|
|
90
|
+
- `legacy-discoverer`, `api-extractor`, `schema-extractor`: Legacy analysis
|
|
91
|
+
- `code-archaeologist`, `business-rule-miner`, `legacy-synthesizer`: Deep analysis
|
|
92
|
+
- `docs-guardian`: Documentation compliance
|
|
166
93
|
|
|
167
|
-
|
|
168
|
-
|-------|-------|----------|-------------|
|
|
169
|
-
| research | researcher | research-context | markdown |
|
|
170
|
-
| specify | specifier | specification | markdown |
|
|
171
|
-
| plan | planner | plan | markdown |
|
|
172
|
-
| tasks | task-generator | tasks | markdown |
|
|
173
|
-
| implement | implementer | implementation-report | markdown |
|
|
174
|
-
| validate | reviewer | validation-report | markdown |
|
|
94
|
+
## Rules (RFC 2119)
|
|
175
95
|
|
|
176
|
-
###
|
|
96
|
+
### MUST
|
|
97
|
+
1. MUST invoke `/orchestrator` skill on session start before any output
|
|
98
|
+
2. MUST use `AskUserQuestion` at every phase gate — never auto-approve
|
|
99
|
+
3. MUST dispatch phase agents via `Agent(subagent_type:)` — never inline work
|
|
100
|
+
4. MUST store artifacts in MinIO via `artifactStore`
|
|
177
101
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
| map-api | api-extractor | api-spec | yaml |
|
|
183
|
-
| map-db | schema-extractor | database-schema | markdown |
|
|
184
|
-
| analyze | code-archaeologist | analysis-report | markdown |
|
|
185
|
-
| analyze-dead-code | code-archaeologist | dead-code-report | markdown |
|
|
186
|
-
| analyze-tech-debt | code-archaeologist | tech-debt | markdown |
|
|
187
|
-
| document | business-rule-miner | business-rules | markdown |
|
|
188
|
-
| document-glossary | business-rule-miner | glossary | markdown |
|
|
189
|
-
| recommend | legacy-synthesizer | migration-roadmap | markdown |
|
|
190
|
-
| recommend-arch | legacy-synthesizer | architecture-proposal | markdown |
|
|
191
|
-
| recommend-final | legacy-synthesizer | final-report | markdown |
|
|
192
|
-
| validate | reviewer | validation-report | markdown |
|
|
102
|
+
### MUST NOT
|
|
103
|
+
1. MUST NOT invoke `Agent(subagent_type: "orchestrator")` — YOU are the orchestrator
|
|
104
|
+
2. MUST NOT bypass approval flow at IMPLEMENT gate
|
|
105
|
+
3. MUST NOT generate artifacts directly — delegate to specialized agents
|
|
193
106
|
|
|
194
|
-
###
|
|
107
|
+
### SHOULD
|
|
108
|
+
1. SHOULD keep sub-agent prompts focused with workflow context
|
|
109
|
+
2. SHOULD summarize artifacts at gates, not dump full content
|
|
110
|
+
3. SHOULD use `/workflow-status` to diagnose stuck workflows
|
|
195
111
|
|
|
196
|
-
|
|
197
|
-
|-------|-------|----------|-------------|
|
|
198
|
-
| docs-analysis | docs-guardian | docs-report | markdown |
|
|
112
|
+
## Token Efficiency
|
|
199
113
|
|
|
200
|
-
|
|
114
|
+
- Delegate heavy work to sub-agents — main conversation stays lean with summaries
|
|
115
|
+
- Use the 3-File Rule: if >3 files needed, dispatch an Explore agent
|
|
116
|
+
- MCP tools are deferred — call `ToolSearch` before first use of any `mcp__*` tool
|
|
201
117
|
|
|
202
118
|
---
|
|
203
119
|
|
|
204
|
-
**Version:**
|
|
205
|
-
**Architecture:**
|
|
206
|
-
**
|
|
207
|
-
**Compliance:** 100% (enforced by code)
|
|
208
|
-
**Standards:** AGENT-PROMPT-STANDARDS v1.0
|
|
120
|
+
**Version:** 3.0
|
|
121
|
+
**Architecture:** Main-as-Orchestrator (RFC-022)
|
|
122
|
+
**Predecessor:** v2.2 (sub-agent, deprecated)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dangling-guard.ts — Stop hook (RFC-022 Phase 2)
|
|
3
|
+
* Replaces dangling-workflow-guard.sh
|
|
4
|
+
* Blocks stop if workflow still active.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
log,
|
|
9
|
+
readStdin,
|
|
10
|
+
getField,
|
|
11
|
+
getActiveWorkflow,
|
|
12
|
+
getWorkflowStatus,
|
|
13
|
+
outputBlock,
|
|
14
|
+
} from "./lib/api-client.js";
|
|
15
|
+
|
|
16
|
+
const HOOK = "DANGLING-GUARD";
|
|
17
|
+
|
|
18
|
+
async function main(): Promise<void> {
|
|
19
|
+
const stdin = await readStdin();
|
|
20
|
+
log(HOOK, "Stop hook triggered");
|
|
21
|
+
|
|
22
|
+
// Prevent infinite loops
|
|
23
|
+
const stopActive = getField(stdin, "stop_hook_active");
|
|
24
|
+
if (stopActive === "true") {
|
|
25
|
+
log(HOOK, "stop_hook_active=true, allowing stop to prevent loop");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const workflow = await getActiveWorkflow();
|
|
30
|
+
if (!workflow) {
|
|
31
|
+
log(HOOK, "No active workflow, clean exit");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const status = await getWorkflowStatus(workflow.id);
|
|
36
|
+
const wfStatus = status?.status || workflow.status;
|
|
37
|
+
const phase = status?.currentPhase || workflow.currentPhase;
|
|
38
|
+
|
|
39
|
+
log(HOOK, `workflow=${workflow.id} status=${wfStatus} phase=${phase}`);
|
|
40
|
+
|
|
41
|
+
const activeStatuses = ["in_progress", "awaiting_agent", "awaiting_approval"];
|
|
42
|
+
if (activeStatuses.includes(wfStatus)) {
|
|
43
|
+
log(HOOK, "BLOCK stop (workflow still active)");
|
|
44
|
+
outputBlock(
|
|
45
|
+
`[DANGLING-GUARD] Workflow ${workflow.id} is still ${wfStatus} (phase: ${phase}). You must call mcp__orchestrator-extended__completeWorkflow({ workflowId: '${workflow.id}' }) before ending the session.`
|
|
46
|
+
);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
log(HOOK, "Workflow completed or not active, allowing stop");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
main().catch(() => process.exit(0));
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gate-guardian.ts — PreToolUse[advancePhase] hook (RFC-022 Phase 2)
|
|
3
|
+
* Replaces gate-guardian.sh
|
|
4
|
+
* Guards IMPLEMENT phase advance (requires human approval).
|
|
5
|
+
* ALLOWs quick/interactive modes and non-IMPLEMENT phases.
|
|
6
|
+
* FAIL-CLOSED on parse errors.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
log,
|
|
11
|
+
readStdin,
|
|
12
|
+
getField,
|
|
13
|
+
getToken,
|
|
14
|
+
getWorkflowMode,
|
|
15
|
+
getNextAction,
|
|
16
|
+
outputPreToolUse,
|
|
17
|
+
} from "./lib/api-client.js";
|
|
18
|
+
|
|
19
|
+
const HOOK = "GATE-GUARDIAN";
|
|
20
|
+
|
|
21
|
+
async function main(): Promise<void> {
|
|
22
|
+
const stdin = await readStdin();
|
|
23
|
+
log(HOOK, "PreToolUse advancePhase triggered");
|
|
24
|
+
|
|
25
|
+
const workflowId = getField(stdin, "tool_input.workflowId") || getField(stdin, "workflowId");
|
|
26
|
+
const targetPhase = getField(stdin, "tool_input.targetPhase") || getField(stdin, "targetPhase");
|
|
27
|
+
|
|
28
|
+
log(HOOK, `workflow=${workflowId} targetPhase=${targetPhase}`);
|
|
29
|
+
|
|
30
|
+
// Check workflow mode — quick/interactive skip gate
|
|
31
|
+
if (workflowId) {
|
|
32
|
+
const mode = await getWorkflowMode(workflowId);
|
|
33
|
+
log(HOOK, `workflow=${workflowId} mode=${mode || "legacy"}`);
|
|
34
|
+
|
|
35
|
+
if (mode === "quick") {
|
|
36
|
+
outputPreToolUse({
|
|
37
|
+
decision: "allow",
|
|
38
|
+
context: `Gate to '${targetPhase}' allowed: quick mode skips gate evaluation.`,
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (mode === "interactive") {
|
|
43
|
+
outputPreToolUse({
|
|
44
|
+
decision: "allow",
|
|
45
|
+
context: `Gate to '${targetPhase}' allowed: interactive mode skips artifact gate evaluation.`,
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// FAIL-CLOSED: can't parse input → DENY
|
|
52
|
+
if (!workflowId || !targetPhase) {
|
|
53
|
+
log(HOOK, "DENY (could not parse input)");
|
|
54
|
+
outputPreToolUse({
|
|
55
|
+
decision: "deny",
|
|
56
|
+
reason: "Gate Guardian: Could not parse workflowId or targetPhase.",
|
|
57
|
+
context: "Ensure you pass both workflowId and targetPhase to advancePhase.",
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Auth check — FAIL-CLOSED
|
|
63
|
+
const token = await getToken();
|
|
64
|
+
if (!token) {
|
|
65
|
+
log(HOOK, "DENY (auth failed)");
|
|
66
|
+
outputPreToolUse({
|
|
67
|
+
decision: "deny",
|
|
68
|
+
reason: "Gate Guardian: Authentication failed.",
|
|
69
|
+
context:
|
|
70
|
+
"Check ORCHESTRATOR_ADMIN_EMAIL, ORCHESTRATOR_ADMIN_PASSWORD, ORCHESTRATOR_PROJECT_ID env vars.",
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// IMPLEMENT phase requires approval
|
|
76
|
+
if (targetPhase.toLowerCase() === "implement") {
|
|
77
|
+
log(HOOK, "Checking approval for IMPLEMENT phase");
|
|
78
|
+
const action = await getNextAction(workflowId);
|
|
79
|
+
if (action) {
|
|
80
|
+
const status = action.pendingAction?.status || "";
|
|
81
|
+
if (status !== "approved" && status !== "awaiting_agent") {
|
|
82
|
+
log(HOOK, `DENY (IMPLEMENT requires approval, status=${status})`);
|
|
83
|
+
outputPreToolUse({
|
|
84
|
+
decision: "deny",
|
|
85
|
+
reason: `Gate Guardian: IMPLEMENT requires human approval. Status: ${status}.`,
|
|
86
|
+
context:
|
|
87
|
+
"Ask the user for approval first. Then call mcp__orchestrator-tools__approveAction.",
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Non-IMPLEMENT or approved: ALLOW
|
|
95
|
+
log(HOOK, `ALLOW (phase=${targetPhase})`);
|
|
96
|
+
outputPreToolUse({
|
|
97
|
+
decision: "allow",
|
|
98
|
+
context: `Gate to '${targetPhase}' allowed.`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
main().catch(() => process.exit(0));
|