@orchestrator-claude/cli 3.17.1 → 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.
Files changed (55) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/templates/base/CLAUDE.md.hbs +45 -28
  4. package/dist/templates/base/claude/agents/orchestrator.md +84 -117
  5. package/dist/templates/base/claude/hooks/dangling-guard.ts +53 -0
  6. package/dist/templates/base/claude/hooks/gate-guardian.ts +102 -0
  7. package/dist/templates/base/claude/hooks/lib/api-client.ts +293 -0
  8. package/dist/templates/base/claude/hooks/lib/git-checkpoint.ts +91 -0
  9. package/dist/templates/base/claude/hooks/package.json +13 -0
  10. package/dist/templates/base/claude/hooks/post-compact.ts +44 -0
  11. package/dist/templates/base/claude/hooks/session-start.ts +97 -0
  12. package/dist/templates/base/claude/hooks/subagent-start.ts +50 -0
  13. package/dist/templates/base/claude/hooks/subagent-stop.ts +57 -0
  14. package/dist/templates/base/claude/hooks/tsconfig.json +18 -0
  15. package/dist/templates/base/claude/hooks/user-prompt.ts +95 -0
  16. package/dist/templates/base/claude/hooks/workflow-guard.ts +120 -0
  17. package/dist/templates/base/claude/settings.json +23 -22
  18. package/dist/templates/base/claude/skills/orchestrator/SKILL.md +108 -0
  19. package/package.json +1 -1
  20. package/templates/base/CLAUDE.md.hbs +45 -28
  21. package/templates/base/claude/agents/orchestrator.md +84 -117
  22. package/templates/base/claude/hooks/dangling-guard.ts +53 -0
  23. package/templates/base/claude/hooks/gate-guardian.ts +102 -0
  24. package/templates/base/claude/hooks/lib/api-client.ts +293 -0
  25. package/templates/base/claude/hooks/lib/git-checkpoint.ts +91 -0
  26. package/templates/base/claude/hooks/package.json +13 -0
  27. package/templates/base/claude/hooks/post-compact.ts +44 -0
  28. package/templates/base/claude/hooks/session-start.ts +97 -0
  29. package/templates/base/claude/hooks/subagent-start.ts +50 -0
  30. package/templates/base/claude/hooks/subagent-stop.ts +57 -0
  31. package/templates/base/claude/hooks/tsconfig.json +18 -0
  32. package/templates/base/claude/hooks/user-prompt.ts +95 -0
  33. package/templates/base/claude/hooks/workflow-guard.ts +120 -0
  34. package/templates/base/claude/settings.json +23 -22
  35. package/templates/base/claude/skills/orchestrator/SKILL.md +108 -0
  36. package/dist/templates/base/claude/hooks/approval-guardian.sh +0 -62
  37. package/dist/templates/base/claude/hooks/dangling-workflow-guard.sh +0 -57
  38. package/dist/templates/base/claude/hooks/gate-guardian.sh +0 -84
  39. package/dist/templates/base/claude/hooks/orch-helpers.sh +0 -135
  40. package/dist/templates/base/claude/hooks/ping-pong-enforcer.sh +0 -58
  41. package/dist/templates/base/claude/hooks/post-phase-checkpoint.sh +0 -203
  42. package/dist/templates/base/claude/hooks/prompt-orchestrator.sh +0 -41
  43. package/dist/templates/base/claude/hooks/session-orchestrator.sh +0 -54
  44. package/dist/templates/base/claude/hooks/track-agent-invocation.sh +0 -230
  45. package/dist/templates/base/claude/hooks/workflow-guard.sh +0 -79
  46. package/templates/base/claude/hooks/approval-guardian.sh +0 -62
  47. package/templates/base/claude/hooks/dangling-workflow-guard.sh +0 -57
  48. package/templates/base/claude/hooks/gate-guardian.sh +0 -84
  49. package/templates/base/claude/hooks/orch-helpers.sh +0 -135
  50. package/templates/base/claude/hooks/ping-pong-enforcer.sh +0 -58
  51. package/templates/base/claude/hooks/post-phase-checkpoint.sh +0 -203
  52. package/templates/base/claude/hooks/prompt-orchestrator.sh +0 -41
  53. package/templates/base/claude/hooks/session-orchestrator.sh +0 -54
  54. package/templates/base/claude/hooks/track-agent-invocation.sh +0 -230
  55. package/templates/base/claude/hooks/workflow-guard.sh +0 -79
@@ -1,230 +0,0 @@
1
- #!/bin/bash
2
- # Track Agent Invocation Hook
3
- # Registers agent invocations in orchestrator-index.json
4
- #
5
- # Usage (called by Claude Code hooks):
6
- # track-agent-invocation.sh start (reads stdin JSON)
7
- # track-agent-invocation.sh complete (reads stdin JSON)
8
- #
9
- # Claude Code passes JSON via stdin with structure:
10
- # { "tool_name": "Task", "tool_input": { "subagent_type": "...", ... } }
11
-
12
- set -e
13
-
14
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
16
- INDEX_FILE="$PROJECT_ROOT/.orchestrator/orchestrator-index.json"
17
- STATE_DIR="$PROJECT_ROOT/.orchestrator/.state"
18
- INVOCATION_FILE="$STATE_DIR/current-invocation"
19
- DEBUG_LOG="$STATE_DIR/hook-debug.log"
20
-
21
- # Ensure state directory exists
22
- mkdir -p "$STATE_DIR"
23
-
24
- ACTION="${1:-}"
25
-
26
- # Read stdin into variable (Claude Code passes JSON via stdin)
27
- STDIN_DATA=""
28
- if [ ! -t 0 ]; then
29
- STDIN_DATA=$(cat)
30
- fi
31
-
32
- case "$ACTION" in
33
- start)
34
- # Extract agent info from stdin JSON
35
- # Structure: { "tool_name": "Task", "tool_input": { "subagent_type": "...", ... } }
36
- if [ -n "$STDIN_DATA" ]; then
37
- # Debug: log received data
38
- echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] START stdin: $STDIN_DATA" >> "$DEBUG_LOG"
39
-
40
- AGENT_NAME=$(echo "$STDIN_DATA" | node -e "
41
- let data = '';
42
- process.stdin.on('data', chunk => data += chunk);
43
- process.stdin.on('end', () => {
44
- try {
45
- const json = JSON.parse(data);
46
- // Try different structures
47
- const type = json.tool_input?.subagent_type
48
- || json.subagent_type
49
- || json.tool_input?.type
50
- || 'unknown';
51
- console.log(type);
52
- } catch { console.log('unknown'); }
53
- });
54
- ")
55
- PHASE=$(echo "$STDIN_DATA" | node -e "
56
- let data = '';
57
- process.stdin.on('data', chunk => data += chunk);
58
- process.stdin.on('end', () => {
59
- try {
60
- const json = JSON.parse(data);
61
- const type = json.tool_input?.subagent_type
62
- || json.subagent_type
63
- || json.tool_input?.type
64
- || 'unknown';
65
- const phaseMap = {
66
- 'specifier': 'specify',
67
- 'planner': 'plan',
68
- 'task-generator': 'tasks',
69
- 'implementer': 'implement',
70
- 'researcher': 'research',
71
- 'reviewer': 'review',
72
- 'orchestrator': 'orchestrate'
73
- };
74
- console.log(phaseMap[type] || type);
75
- } catch { console.log('unknown'); }
76
- });
77
- ")
78
- elif [ -n "$CLAUDE_TOOL_INPUT" ]; then
79
- # Fallback to environment variable
80
- echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] START env: $CLAUDE_TOOL_INPUT" >> "$DEBUG_LOG"
81
-
82
- AGENT_NAME=$(echo "$CLAUDE_TOOL_INPUT" | node -e "
83
- let data = '';
84
- process.stdin.on('data', chunk => data += chunk);
85
- process.stdin.on('end', () => {
86
- try {
87
- const json = JSON.parse(data);
88
- const type = json.subagent_type || json.tool_input?.subagent_type || 'unknown';
89
- console.log(type);
90
- } catch { console.log('unknown'); }
91
- });
92
- ")
93
- PHASE="unknown"
94
- else
95
- echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] START no input received" >> "$DEBUG_LOG"
96
- AGENT_NAME="unknown"
97
- PHASE="unknown"
98
- fi
99
-
100
- # Generate invocation ID
101
- INVOCATION_ID="inv-$(date +%s)-$(head -c 4 /dev/urandom | xxd -p)"
102
- STARTED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
103
-
104
- # Get workflow ID from index
105
- WORKFLOW_ID=""
106
- if [ -f "$INDEX_FILE" ]; then
107
- WORKFLOW_ID=$(node -e "
108
- const fs = require('fs');
109
- try {
110
- const idx = JSON.parse(fs.readFileSync('$INDEX_FILE', 'utf8'));
111
- console.log(idx.activeWorkflow?.id || 'wf-standalone-' + Date.now());
112
- } catch { console.log('wf-standalone-' + Date.now()); }
113
- ")
114
- fi
115
-
116
- # Save invocation state
117
- echo "$INVOCATION_ID" > "$INVOCATION_FILE"
118
-
119
- # Update orchestrator-index.json
120
- if [ -f "$INDEX_FILE" ]; then
121
- node -e "
122
- const fs = require('fs');
123
- const indexPath = '$INDEX_FILE';
124
- const idx = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
125
-
126
- if (!idx.agentInvocations) idx.agentInvocations = [];
127
-
128
- idx.agentInvocations.push({
129
- id: '$INVOCATION_ID',
130
- agentName: '$AGENT_NAME',
131
- phase: '$PHASE',
132
- workflowId: '$WORKFLOW_ID',
133
- startedAt: '$STARTED_AT',
134
- completedAt: null,
135
- status: 'running',
136
- durationMs: 0
137
- });
138
-
139
- fs.writeFileSync(indexPath, JSON.stringify(idx, null, 2));
140
- console.log(JSON.stringify({ invocationId: '$INVOCATION_ID', startedAt: '$STARTED_AT' }));
141
- "
142
- else
143
- echo '{"invocationId": "'$INVOCATION_ID'", "startedAt": "'$STARTED_AT'", "warning": "No index file found"}'
144
- fi
145
- ;;
146
-
147
- complete)
148
- # Get invocation ID from state file
149
- INVOCATION_ID=""
150
- if [ -f "$INVOCATION_FILE" ]; then
151
- INVOCATION_ID=$(cat "$INVOCATION_FILE")
152
- fi
153
-
154
- if [ -z "$INVOCATION_ID" ]; then
155
- echo '{"success": false, "error": "No invocation ID found"}'
156
- exit 0 # Don't fail the hook
157
- fi
158
-
159
- # Debug log
160
- if [ -n "$STDIN_DATA" ]; then
161
- echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] COMPLETE stdin: $STDIN_DATA" >> "$DEBUG_LOG"
162
- fi
163
-
164
- # Determine status - default to success
165
- STATUS="success"
166
- SUMMARY="Completed"
167
-
168
- COMPLETED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
169
-
170
- # Update orchestrator-index.json
171
- if [ -f "$INDEX_FILE" ]; then
172
- node -e "
173
- const fs = require('fs');
174
- const indexPath = '$INDEX_FILE';
175
- const idx = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
176
-
177
- const invocations = idx.agentInvocations || [];
178
- const invIdx = invocations.findIndex(i => i.id === '$INVOCATION_ID');
179
-
180
- if (invIdx === -1) {
181
- console.log(JSON.stringify({ success: false, error: 'Invocation not found' }));
182
- process.exit(0);
183
- }
184
-
185
- const inv = invocations[invIdx];
186
- const startTime = new Date(inv.startedAt).getTime();
187
- const endTime = new Date('$COMPLETED_AT').getTime();
188
- const durationMs = endTime - startTime;
189
-
190
- invocations[invIdx] = {
191
- ...inv,
192
- completedAt: '$COMPLETED_AT',
193
- status: '$STATUS' === 'success' ? 'completed' : 'failed',
194
- durationMs,
195
- result: {
196
- status: '$STATUS',
197
- summary: '$SUMMARY'
198
- }
199
- };
200
-
201
- idx.agentInvocations = invocations;
202
-
203
- // Update statistics
204
- if (idx.statistics) {
205
- idx.statistics.totalInvocations = invocations.length;
206
- idx.statistics.lastActivity = '$COMPLETED_AT';
207
- }
208
-
209
- fs.writeFileSync(indexPath, JSON.stringify(idx, null, 2));
210
- console.log(JSON.stringify({ success: true, durationMs }));
211
- "
212
- else
213
- echo '{"success": false, "error": "No index file found"}'
214
- fi
215
-
216
- # Clean up state file
217
- rm -f "$INVOCATION_FILE"
218
- ;;
219
-
220
- *)
221
- echo "Usage: $0 {start|complete}"
222
- echo ""
223
- echo "This script is called by Claude Code hooks."
224
- echo "It reads JSON from stdin with structure:"
225
- echo ' { "tool_name": "Task", "tool_input": { "subagent_type": "...", ... } }'
226
- echo ""
227
- echo "Debug log: $DEBUG_LOG"
228
- exit 0
229
- ;;
230
- esac
@@ -1,79 +0,0 @@
1
- #!/bin/bash
2
- # workflow-guard.sh — ADR-013 Phase 5 Hook (JSON Structured Output)
3
- # Trigger: PreToolUse on Write|Edit
4
- # Purpose: Block writes to src/ and tests/ when no active workflow exists.
5
- #
6
- # Output: JSON with permissionDecision (deny/allow) + additionalContext
7
- # Exit 0 with JSON = structured decision
8
-
9
- set -euo pipefail
10
-
11
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
- source "$SCRIPT_DIR/orch-helpers.sh"
13
-
14
- STDIN_DATA=$(orch_read_stdin)
15
-
16
- # Extract file path (Claude Code wraps in tool_input)
17
- FILE_PATH=$(orch_json_field "$STDIN_DATA" "tool_input.file_path")
18
- [ -z "$FILE_PATH" ] && FILE_PATH=$(orch_json_field "$STDIN_DATA" "file_path")
19
- [ -z "$FILE_PATH" ] && FILE_PATH=$(orch_json_field "$STDIN_DATA" "input.file_path")
20
-
21
- orch_log "workflow-guard: file_path=$FILE_PATH"
22
-
23
- # Explicit bypass via env var (for direct implementation without dogfooding)
24
- if [ "${SKIP_WORKFLOW_GUARD:-}" = "true" ]; then
25
- orch_log "workflow-guard: ALLOW (SKIP_WORKFLOW_GUARD=true)"
26
- echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","additionalContext":"Workflow guard bypassed via SKIP_WORKFLOW_GUARD=true."}}'
27
- exit 0
28
- fi
29
-
30
- # Only guard src/ and tests/ paths (production code)
31
- case "$FILE_PATH" in
32
- */src/*|*/tests/*)
33
- ;;
34
- *)
35
- orch_log "workflow-guard: ALLOW (non-guarded path)"
36
- exit 0
37
- ;;
38
- esac
39
-
40
- # Allow config and non-code files
41
- case "$FILE_PATH" in
42
- *.json|*.yml|*.yaml|*.md|*.env|*.env.*)
43
- orch_log "workflow-guard: ALLOW (config/doc file)"
44
- exit 0
45
- ;;
46
- esac
47
-
48
- # Check for active workflow
49
- WORKFLOW_ID=$(orch_get_active_workflow 2>/dev/null) || WORKFLOW_ID=""
50
-
51
- if [ -n "$WORKFLOW_ID" ]; then
52
- # Check if running inside a sub-agent (agent_id present) or main agent (absent)
53
- AGENT_ID=$(orch_json_field "$STDIN_DATA" "agent_id")
54
-
55
- if [ -n "$AGENT_ID" ]; then
56
- # Sub-agent writing — ALLOW
57
- AGENT_TYPE=$(orch_json_field "$STDIN_DATA" "agent_type")
58
- orch_log "workflow-guard: ALLOW (sub-agent: ${AGENT_TYPE:-unknown}, workflow: $WORKFLOW_ID)"
59
- echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"allow\",\"additionalContext\":\"Active workflow: ${WORKFLOW_ID}. Sub-agent ${AGENT_TYPE:-unknown} write allowed.\"}}"
60
- exit 0
61
- fi
62
-
63
- # Main agent writing directly — check if SKIP_SUBAGENT_GUARD allows it
64
- if [ "${SKIP_SUBAGENT_GUARD:-}" = "true" ]; then
65
- orch_log "workflow-guard: ALLOW (SKIP_SUBAGENT_GUARD=true, workflow: $WORKFLOW_ID)"
66
- echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"allow\",\"additionalContext\":\"Active workflow: ${WORKFLOW_ID}. Direct write allowed via SKIP_SUBAGENT_GUARD.\"}}"
67
- exit 0
68
- fi
69
-
70
- # Main agent writing directly — DENY, must use sub-agent
71
- orch_log "workflow-guard: DENY (main agent direct write, no sub-agent invocation)"
72
- echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Workflow Guard: Direct code writes are blocked. You must invoke a sub-agent (e.g. implementer) to write code. The sub-agent will have write access.\",\"additionalContext\":\"Use the Agent tool to spawn an implementer sub-agent for code changes. The workflow-guard allows writes only from sub-agents (identified by agent_id in hook input).\"}}"
73
- exit 0
74
- fi
75
-
76
- # No active workflow — DENY with structured instructions
77
- orch_log "workflow-guard: DENY (no active workflow)"
78
- echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Workflow Guard: No active workflow. Direct implementation is not allowed.","additionalContext":"You MUST start a workflow before writing code:\n1. mcp__orchestrator-tools__detectWorkflow({ prompt: \"...\" })\n2. mcp__orchestrator-tools__startWorkflow({ workflowType: \"...\", prompt: \"...\" })\n3. Follow the nextStep returned by startWorkflow\n\nThe workflow-guard hook blocks all writes to src/ and tests/ without an active workflow."}}'
79
- exit 0