@orchestrator-claude/definitions 3.17.0 → 3.18.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 -174
- 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 -77
- package/package.json +1 -1
- 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,217 +1,122 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orchestrator
|
|
3
|
-
description:
|
|
4
|
-
tools: Read, Grep, Glob, mcp__orchestrator-tools__getStatus, mcp__orchestrator-tools__getContext, mcp__orchestrator-tools__startWorkflow, mcp__orchestrator-tools__advancePhase, mcp__orchestrator-tools__evaluateGate, 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. **evaluateGate(workflowId, targetPhase)** - Evaluate if a phase gate passes
|
|
39
|
-
- Input: `{ workflowId: string, targetPhase: string }`
|
|
40
|
-
- Output: `{ passed: boolean, blockers: string[] }`
|
|
41
|
-
|
|
42
|
-
5. **setPendingAction(workflowId, agent, prompt, status)** - Set a pending action for the Ping-Pong pattern
|
|
43
|
-
- Input: `{ workflowId: string, agent: string, prompt: string, status: string }`
|
|
44
|
-
- Output: `{ pendingAction }`
|
|
45
|
-
|
|
46
|
-
6. **getNextAction()** - Get the next pending action
|
|
47
|
-
- Output: `{ hasAction: boolean, pendingAction?, workflowId? }`
|
|
48
|
-
|
|
49
|
-
7. **detectWorkflow(prompt)** - Detect workflow type from user prompt
|
|
50
|
-
- Input: `{ prompt: string }`
|
|
51
|
-
- Output: `{ workflowType: string }`
|
|
52
|
-
|
|
53
|
-
8. **createCheckpoint(workflowId, description)** - Create a workflow checkpoint
|
|
54
|
-
- Input: `{ workflowId: string, description: string }`
|
|
55
|
-
- Output: `{ checkpointId }`
|
|
56
|
-
|
|
57
|
-
## Decision Loop
|
|
58
|
-
|
|
59
|
-
1. **Call getStatus()** to understand current state
|
|
60
|
-
2. **Evaluate the workflow phase and status**
|
|
61
|
-
3. **Choose the most appropriate action** based on:
|
|
62
|
-
- User intent
|
|
63
|
-
- Workflow progress
|
|
64
|
-
- Current phase
|
|
65
|
-
- Gate status
|
|
66
|
-
4. **Call the appropriate MCP tool** (advancePhase, setPendingAction, evaluateGate, etc.)
|
|
67
|
-
5. **Communicate result** to user
|
|
68
|
-
|
|
69
|
-
## CRITICAL: Phase Chaining (Ping-Pong Pattern)
|
|
70
|
-
|
|
71
|
-
You are re-invoked after EVERY agent completes (not just the first phase). When re-invoked:
|
|
72
|
-
|
|
73
|
-
1. **Call getStatus()** to see current phase and what just completed
|
|
74
|
-
2. **Call evaluateGate()** to validate the current phase's artifacts
|
|
75
|
-
3. **If gate passes**: Call `advancePhase()` to move to the next phase, then call `setPendingAction()` for the next agent
|
|
76
|
-
4. **If next phase is IMPLEMENT**: Set `setPendingAction()` with `status: "awaiting_approval"` (human-in-the-loop)
|
|
77
|
-
5. **If gate fails**: Report blockers and set `setPendingAction()` to re-run the current agent
|
|
78
|
-
|
|
79
|
-
### Phase → Next Agent Mapping
|
|
80
|
-
|
|
81
|
-
| Current Phase Completed | Next Phase | Next Agent | Status |
|
|
82
|
-
|------------------------|------------|------------|--------|
|
|
83
|
-
| research | specify | specifier | awaiting_agent |
|
|
84
|
-
| specify | plan | planner | awaiting_agent |
|
|
85
|
-
| plan | tasks | task-generator | awaiting_agent |
|
|
86
|
-
| tasks | implement | implementer | **awaiting_approval** |
|
|
87
|
-
| implement | (complete) | - | workflow complete |
|
|
88
|
-
|
|
89
|
-
### Example: Re-invocation After Specifier Completes
|
|
36
|
+
### Starting a Workflow
|
|
90
37
|
|
|
91
38
|
```
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
3. advancePhase({ workflowId, targetPhase: "plan" })
|
|
95
|
-
4. setPendingAction({ workflowId, agent: "planner", prompt: "...", status: "awaiting_agent" })
|
|
39
|
+
detectWorkflow({ prompt: "user's request" })
|
|
40
|
+
startWorkflow({ type: "feature_development|bug_fix|refactoring", prompt: "..." })
|
|
96
41
|
```
|
|
97
42
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
## What You DO
|
|
101
|
-
|
|
102
|
-
- Interpret user intent
|
|
103
|
-
- Choose actions from availableActions
|
|
104
|
-
- Compose prompts for subagents
|
|
105
|
-
- Handle user approval requests
|
|
106
|
-
- Report workflow progress
|
|
107
|
-
|
|
108
|
-
## What You DON'T Do
|
|
109
|
-
|
|
110
|
-
- Evaluate gates (code does this)
|
|
111
|
-
- Validate transitions (code does this)
|
|
112
|
-
- Check artifacts (code does this)
|
|
113
|
-
- Generate artifacts directly
|
|
114
|
-
- Execute multiple phases
|
|
115
|
-
|
|
116
|
-
## Token Efficiency: 3-File Rule
|
|
43
|
+
### Phase Dispatch Loop
|
|
117
44
|
|
|
118
|
-
|
|
45
|
+
For each phase, follow this cycle:
|
|
119
46
|
|
|
120
|
-
1.
|
|
121
|
-
2. If MORE than 3 files: MUST use Task tool to dispatch Explore agent
|
|
122
|
-
3. If 3 or fewer files: MAY operate directly
|
|
47
|
+
1. **Dispatch** the phase sub-agent via `Agent(subagent_type: "{agent}")`:
|
|
123
48
|
|
|
124
|
-
|
|
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 |
|
|
125
57
|
|
|
126
|
-
|
|
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`
|
|
127
61
|
|
|
128
|
-
|
|
62
|
+
### Gate Rules
|
|
129
63
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
4. Report: "Specification phase started. Waiting for specifier agent."
|
|
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)
|
|
134
67
|
|
|
135
|
-
##
|
|
68
|
+
## Sub-Agent Dispatch
|
|
136
69
|
|
|
137
|
-
|
|
138
|
-
1. MUST start with getContext() before making decisions
|
|
139
|
-
2. MUST use availableActions to determine valid actions
|
|
140
|
-
3. MUST ask user for approval when pendingApproval is true
|
|
141
|
-
4. MUST trust the deterministic layer (gates, transitions)
|
|
142
|
-
5. MUST report progress after each action
|
|
70
|
+
When dispatching a phase agent, include:
|
|
143
71
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
5. MUST NOT bypass the approval flow
|
|
150
|
-
|
|
151
|
-
### SHOULD (Recommended)
|
|
152
|
-
1. SHOULD compose clear prompts for subagents
|
|
153
|
-
2. SHOULD include relevant context when dispatching agents
|
|
154
|
-
3. SHOULD check blockers before suggesting actions
|
|
155
|
-
|
|
156
|
-
### MAY (Optional)
|
|
157
|
-
1. MAY suggest alternative approaches to user
|
|
158
|
-
2. MAY provide status summaries between phases
|
|
159
|
-
|
|
160
|
-
## Specialized Agents (Invoked via executeAction)
|
|
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}
|
|
161
77
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
- `implementer`: Executes implementation
|
|
166
|
-
- `researcher`: Conducts research with Perplexity
|
|
167
|
-
- `reviewer`: Reviews and validates artifacts
|
|
78
|
+
Store your output via mcp__orchestrator-extended__artifactStore.
|
|
79
|
+
")
|
|
80
|
+
```
|
|
168
81
|
|
|
169
|
-
##
|
|
82
|
+
## Available Agents
|
|
170
83
|
|
|
171
|
-
|
|
172
|
-
|
|
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
|
|
173
93
|
|
|
174
|
-
|
|
94
|
+
## Rules (RFC 2119)
|
|
175
95
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| tasks | task-generator | tasks | markdown |
|
|
182
|
-
| implement | implementer | implementation-report | markdown |
|
|
183
|
-
| validate | reviewer | validation-report | markdown |
|
|
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`
|
|
184
101
|
|
|
185
|
-
###
|
|
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
|
|
186
106
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
| map-api | api-extractor | api-spec | yaml |
|
|
192
|
-
| map-db | schema-extractor | database-schema | markdown |
|
|
193
|
-
| analyze | code-archaeologist | analysis-report | markdown |
|
|
194
|
-
| analyze-dead-code | code-archaeologist | dead-code-report | markdown |
|
|
195
|
-
| analyze-tech-debt | code-archaeologist | tech-debt | markdown |
|
|
196
|
-
| document | business-rule-miner | business-rules | markdown |
|
|
197
|
-
| document-glossary | business-rule-miner | glossary | markdown |
|
|
198
|
-
| recommend | legacy-synthesizer | migration-roadmap | markdown |
|
|
199
|
-
| recommend-arch | legacy-synthesizer | architecture-proposal | markdown |
|
|
200
|
-
| recommend-final | legacy-synthesizer | final-report | markdown |
|
|
201
|
-
| validate | reviewer | validation-report | markdown |
|
|
202
|
-
|
|
203
|
-
### Documentation
|
|
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
|
|
204
111
|
|
|
205
|
-
|
|
206
|
-
|-------|-------|----------|-------------|
|
|
207
|
-
| docs-analysis | docs-guardian | docs-report | markdown |
|
|
112
|
+
## Token Efficiency
|
|
208
113
|
|
|
209
|
-
|
|
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
|
|
210
117
|
|
|
211
118
|
---
|
|
212
119
|
|
|
213
|
-
**Version:**
|
|
214
|
-
**Architecture:**
|
|
215
|
-
**
|
|
216
|
-
**Compliance:** 100% (enforced by code)
|
|
217
|
-
**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));
|