@orchestrator-claude/definitions 3.12.0 → 3.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hooks/dangling-workflow-guard.sh +57 -0
- package/hooks/gate-guardian.sh +79 -0
- package/hooks/orch-helpers.sh +133 -0
- package/hooks/ping-pong-enforcer.sh +58 -0
- package/hooks/post-phase-checkpoint.sh +159 -137
- package/hooks/prompt-orchestrator.sh +41 -0
- package/hooks/session-orchestrator.sh +54 -0
- package/hooks/track-agent-invocation.sh +108 -70
- package/hooks/workflow-guard.sh +79 -0
- package/manifest.json +35 -19
- package/package.json +1 -1
- package/hooks/post-agent-artifact-relay.sh +0 -11
- package/hooks/post-artifact-generate.sh +0 -39
- package/hooks/post-implement-validate.sh +0 -102
- package/hooks/pre-agent-invoke.sh +0 -34
- package/hooks/pre-phase-advance.sh +0 -40
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Track Agent Invocation Hook
|
|
3
|
-
#
|
|
4
|
-
# Registers agent invocations via REST API (PostgreSQL).
|
|
2
|
+
# Track Agent Invocation Hook
|
|
3
|
+
# Registers agent invocations in orchestrator-index.json
|
|
5
4
|
#
|
|
6
5
|
# Usage (called by Claude Code hooks):
|
|
7
6
|
# track-agent-invocation.sh start (reads stdin JSON)
|
|
@@ -14,67 +13,14 @@ set -e
|
|
|
14
13
|
|
|
15
14
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
15
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
16
|
+
INDEX_FILE="$PROJECT_ROOT/.orchestrator/orchestrator-index.json"
|
|
17
17
|
STATE_DIR="$PROJECT_ROOT/.orchestrator/.state"
|
|
18
18
|
INVOCATION_FILE="$STATE_DIR/current-invocation"
|
|
19
19
|
DEBUG_LOG="$STATE_DIR/hook-debug.log"
|
|
20
20
|
|
|
21
|
-
# API Configuration
|
|
22
|
-
API_URL="${ORCHESTRATOR_API_URL:-http://localhost:3001}"
|
|
23
|
-
AUTH_EMAIL="${ORCHESTRATOR_AUTH_EMAIL:-admin@orchestrator.local}"
|
|
24
|
-
AUTH_PASSWORD="${ORCHESTRATOR_AUTH_PASSWORD:-admin123}"
|
|
25
|
-
PROJECT_ID="${ORCHESTRATOR_PROJECT_ID:-d001d65d-25f5-4d13-b1dc-d006873e949c}"
|
|
26
|
-
|
|
27
21
|
# Ensure state directory exists
|
|
28
22
|
mkdir -p "$STATE_DIR"
|
|
29
23
|
|
|
30
|
-
# Log rotation: max 1MB, keep 3 rotated copies
|
|
31
|
-
MAX_LOG_SIZE=1048576 # 1MB in bytes
|
|
32
|
-
if [ -f "$DEBUG_LOG" ]; then
|
|
33
|
-
LOG_SIZE=$(stat -f%z "$DEBUG_LOG" 2>/dev/null || stat -c%s "$DEBUG_LOG" 2>/dev/null || echo 0)
|
|
34
|
-
if [ "$LOG_SIZE" -gt "$MAX_LOG_SIZE" ]; then
|
|
35
|
-
[ -f "${DEBUG_LOG}.2" ] && mv "${DEBUG_LOG}.2" "${DEBUG_LOG}.3"
|
|
36
|
-
[ -f "${DEBUG_LOG}.1" ] && mv "${DEBUG_LOG}.1" "${DEBUG_LOG}.2"
|
|
37
|
-
mv "$DEBUG_LOG" "${DEBUG_LOG}.1"
|
|
38
|
-
fi
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
log() {
|
|
42
|
-
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$DEBUG_LOG"
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
# Auth function: login and cache JWT
|
|
46
|
-
get_token() {
|
|
47
|
-
local cached="$STATE_DIR/jwt-token"
|
|
48
|
-
if [ -f "$cached" ]; then
|
|
49
|
-
local age=$(( $(date +%s) - $(stat -c%Y "$cached" 2>/dev/null || stat -f%m "$cached" 2>/dev/null || echo 0) ))
|
|
50
|
-
if [ "$age" -lt 3500 ]; then # Refresh if > ~58 min
|
|
51
|
-
cat "$cached"
|
|
52
|
-
return
|
|
53
|
-
fi
|
|
54
|
-
fi
|
|
55
|
-
local resp
|
|
56
|
-
resp=$(curl -s -f -X POST "${API_URL}/api/v1/auth/login" \
|
|
57
|
-
-H "Content-Type: application/json" \
|
|
58
|
-
-d "{\"email\":\"${AUTH_EMAIL}\",\"password\":\"${AUTH_PASSWORD}\"}" 2>/dev/null) || return 1
|
|
59
|
-
local token
|
|
60
|
-
token=$(echo "$resp" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(d);console.log(j.data?.accessToken||j.accessToken||j.token||'')}catch{console.log('')}})" 2>/dev/null)
|
|
61
|
-
if [ -n "$token" ]; then
|
|
62
|
-
echo "$token" > "$cached"
|
|
63
|
-
echo "$token"
|
|
64
|
-
fi
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
# Get active workflow ID from REST API
|
|
68
|
-
get_workflow_id() {
|
|
69
|
-
local token
|
|
70
|
-
token=$(get_token) || return 1
|
|
71
|
-
local resp
|
|
72
|
-
resp=$(curl -s -f "${API_URL}/api/v1/workflows?status=in_progress" \
|
|
73
|
-
-H "Authorization: Bearer $token" \
|
|
74
|
-
-H "X-Project-ID: $PROJECT_ID" 2>/dev/null) || return 1
|
|
75
|
-
echo "$resp" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(d);const wfs=j.data||j;const wf=Array.isArray(wfs)?wfs[0]:wfs;console.log(wf?.id||'')}catch{console.log('')}})" 2>/dev/null
|
|
76
|
-
}
|
|
77
|
-
|
|
78
24
|
ACTION="${1:-}"
|
|
79
25
|
|
|
80
26
|
# Read stdin into variable (Claude Code passes JSON via stdin)
|
|
@@ -88,6 +34,7 @@ case "$ACTION" in
|
|
|
88
34
|
# Extract agent info from stdin JSON
|
|
89
35
|
# Structure: { "tool_name": "Task", "tool_input": { "subagent_type": "...", ... } }
|
|
90
36
|
if [ -n "$STDIN_DATA" ]; then
|
|
37
|
+
# Debug: log received data
|
|
91
38
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] START stdin: $STDIN_DATA" >> "$DEBUG_LOG"
|
|
92
39
|
|
|
93
40
|
AGENT_NAME=$(echo "$STDIN_DATA" | node -e "
|
|
@@ -96,6 +43,7 @@ case "$ACTION" in
|
|
|
96
43
|
process.stdin.on('end', () => {
|
|
97
44
|
try {
|
|
98
45
|
const json = JSON.parse(data);
|
|
46
|
+
// Try different structures
|
|
99
47
|
const type = json.tool_input?.subagent_type
|
|
100
48
|
|| json.subagent_type
|
|
101
49
|
|| json.tool_input?.type
|
|
@@ -128,6 +76,7 @@ case "$ACTION" in
|
|
|
128
76
|
});
|
|
129
77
|
")
|
|
130
78
|
elif [ -n "$CLAUDE_TOOL_INPUT" ]; then
|
|
79
|
+
# Fallback to environment variable
|
|
131
80
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] START env: $CLAUDE_TOOL_INPUT" >> "$DEBUG_LOG"
|
|
132
81
|
|
|
133
82
|
AGENT_NAME=$(echo "$CLAUDE_TOOL_INPUT" | node -e "
|
|
@@ -148,35 +97,124 @@ case "$ACTION" in
|
|
|
148
97
|
PHASE="unknown"
|
|
149
98
|
fi
|
|
150
99
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
100
|
+
# Generate invocation ID
|
|
101
|
+
INVOCATION_ID="inv-$(date +%s)-$(head -c 4 /dev/urandom | xxd -p)"
|
|
154
102
|
STARTED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
155
|
-
|
|
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
|
|
156
117
|
echo "$INVOCATION_ID" > "$INVOCATION_FILE"
|
|
157
118
|
|
|
158
|
-
#
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
+
});
|
|
164
138
|
|
|
165
|
-
|
|
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
|
|
166
145
|
;;
|
|
167
146
|
|
|
168
147
|
complete)
|
|
148
|
+
# Get invocation ID from state file
|
|
169
149
|
INVOCATION_ID=""
|
|
170
150
|
if [ -f "$INVOCATION_FILE" ]; then
|
|
171
151
|
INVOCATION_ID=$(cat "$INVOCATION_FILE")
|
|
172
|
-
rm -f "$INVOCATION_FILE"
|
|
173
152
|
fi
|
|
174
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
|
|
175
160
|
if [ -n "$STDIN_DATA" ]; then
|
|
176
161
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] COMPLETE stdin: $STDIN_DATA" >> "$DEBUG_LOG"
|
|
177
162
|
fi
|
|
178
163
|
|
|
179
|
-
|
|
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"
|
|
180
218
|
;;
|
|
181
219
|
|
|
182
220
|
*)
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
package/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "orchestrator-definitions/v1",
|
|
3
3
|
"namespace": "orchestrator",
|
|
4
|
-
"version": "3.12.
|
|
5
|
-
"generatedAt": "2026-03-
|
|
4
|
+
"version": "3.12.2",
|
|
5
|
+
"generatedAt": "2026-03-15T23:15:56.132Z",
|
|
6
6
|
"definitions": {
|
|
7
7
|
"agents": [
|
|
8
8
|
{
|
|
@@ -234,26 +234,34 @@
|
|
|
234
234
|
],
|
|
235
235
|
"hooks": [
|
|
236
236
|
{
|
|
237
|
-
"slug": "
|
|
238
|
-
"file": "hooks/
|
|
237
|
+
"slug": "dangling-workflow-guard",
|
|
238
|
+
"file": "hooks/dangling-workflow-guard.sh",
|
|
239
239
|
"version": "1.0.0",
|
|
240
|
-
"checksum": "sha256:
|
|
240
|
+
"checksum": "sha256:34b195e03357e1d264328d7345832845beae11d2846c8e22810e427b20c75a0c",
|
|
241
241
|
"supersedes": null,
|
|
242
242
|
"metadata": {}
|
|
243
243
|
},
|
|
244
244
|
{
|
|
245
|
-
"slug": "
|
|
246
|
-
"file": "hooks/
|
|
245
|
+
"slug": "gate-guardian",
|
|
246
|
+
"file": "hooks/gate-guardian.sh",
|
|
247
247
|
"version": "1.0.0",
|
|
248
|
-
"checksum": "sha256:
|
|
248
|
+
"checksum": "sha256:7a5add785c53b4040bfde3ba68af8d2f43f65ecc101b600793f6f47a3e411f15",
|
|
249
249
|
"supersedes": null,
|
|
250
250
|
"metadata": {}
|
|
251
251
|
},
|
|
252
252
|
{
|
|
253
|
-
"slug": "
|
|
254
|
-
"file": "hooks/
|
|
253
|
+
"slug": "orch-helpers",
|
|
254
|
+
"file": "hooks/orch-helpers.sh",
|
|
255
255
|
"version": "1.0.0",
|
|
256
|
-
"checksum": "sha256:
|
|
256
|
+
"checksum": "sha256:0038a622374b5c88b9c674a8fc49744a72752c390db3e45a00948e6676e42959",
|
|
257
|
+
"supersedes": null,
|
|
258
|
+
"metadata": {}
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"slug": "ping-pong-enforcer",
|
|
262
|
+
"file": "hooks/ping-pong-enforcer.sh",
|
|
263
|
+
"version": "1.0.0",
|
|
264
|
+
"checksum": "sha256:d2a5a10ea253da2ead5e203d64690129a56f377ecabe7ea4d43cd9c99d4cad95",
|
|
257
265
|
"supersedes": null,
|
|
258
266
|
"metadata": {}
|
|
259
267
|
},
|
|
@@ -261,23 +269,23 @@
|
|
|
261
269
|
"slug": "post-phase-checkpoint",
|
|
262
270
|
"file": "hooks/post-phase-checkpoint.sh",
|
|
263
271
|
"version": "1.0.0",
|
|
264
|
-
"checksum": "sha256:
|
|
272
|
+
"checksum": "sha256:f75c815334e371bf508642b9591d94a548e1221c65ff7f34af9e430ec6e88722",
|
|
265
273
|
"supersedes": null,
|
|
266
274
|
"metadata": {}
|
|
267
275
|
},
|
|
268
276
|
{
|
|
269
|
-
"slug": "
|
|
270
|
-
"file": "hooks/
|
|
277
|
+
"slug": "prompt-orchestrator",
|
|
278
|
+
"file": "hooks/prompt-orchestrator.sh",
|
|
271
279
|
"version": "1.0.0",
|
|
272
|
-
"checksum": "sha256:
|
|
280
|
+
"checksum": "sha256:93835c7798185a9c8f8bf84a029c660b2bbe34801cd34c5be6b2b7a1f07a0b8b",
|
|
273
281
|
"supersedes": null,
|
|
274
282
|
"metadata": {}
|
|
275
283
|
},
|
|
276
284
|
{
|
|
277
|
-
"slug": "
|
|
278
|
-
"file": "hooks/
|
|
285
|
+
"slug": "session-orchestrator",
|
|
286
|
+
"file": "hooks/session-orchestrator.sh",
|
|
279
287
|
"version": "1.0.0",
|
|
280
|
-
"checksum": "sha256:
|
|
288
|
+
"checksum": "sha256:143024a68b8438a0724fd93dd9b6eb1688bcc89c1a846ae7f6c389361b469f65",
|
|
281
289
|
"supersedes": null,
|
|
282
290
|
"metadata": {}
|
|
283
291
|
},
|
|
@@ -285,7 +293,15 @@
|
|
|
285
293
|
"slug": "track-agent-invocation",
|
|
286
294
|
"file": "hooks/track-agent-invocation.sh",
|
|
287
295
|
"version": "1.0.0",
|
|
288
|
-
"checksum": "sha256:
|
|
296
|
+
"checksum": "sha256:6a9343b032dd72e391fc4c476af480ee3055a5a25ec60d3524b0b0d804a80c6d",
|
|
297
|
+
"supersedes": null,
|
|
298
|
+
"metadata": {}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"slug": "workflow-guard",
|
|
302
|
+
"file": "hooks/workflow-guard.sh",
|
|
303
|
+
"version": "1.0.0",
|
|
304
|
+
"checksum": "sha256:170a15396a61c537df4c8adc093d7ac36faab6e7de761ff8d283828c53e4a332",
|
|
289
305
|
"supersedes": null,
|
|
290
306
|
"metadata": {}
|
|
291
307
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Post-Agent Artifact Relay Hook (DEPRECATED — ADR-012)
|
|
3
|
-
#
|
|
4
|
-
# With ADR-012 F1, agents store artifacts directly via MCP artifactStore.
|
|
5
|
-
# This hook is no longer needed. Kept as documentation.
|
|
6
|
-
#
|
|
7
|
-
# Previous behavior: relayed artifacts from filesystem staging to MinIO.
|
|
8
|
-
# Now: agents call mcp__orchestrator-extended__artifactStore directly.
|
|
9
|
-
|
|
10
|
-
# No-op: agents handle artifact storage directly
|
|
11
|
-
exit 0
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Post-Artifact Generate Hook
|
|
3
|
-
# Executado apos geracao de um artefato
|
|
4
|
-
# Valida artefato, atualiza indice, cria checkpoint
|
|
5
|
-
|
|
6
|
-
set -e
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
10
|
-
|
|
11
|
-
# Recebe evento via stdin ou argumento
|
|
12
|
-
if [ -n "$1" ]; then
|
|
13
|
-
EVENT="$1"
|
|
14
|
-
else
|
|
15
|
-
EVENT=$(cat)
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
# Verifica se temos o handler compilado
|
|
19
|
-
HANDLER="$PROJECT_ROOT/dist/hook.js"
|
|
20
|
-
|
|
21
|
-
if [ ! -f "$HANDLER" ]; then
|
|
22
|
-
echo '{"success": false, "error": "Hook handler not compiled. Run npm run build first."}' >&2
|
|
23
|
-
exit 1
|
|
24
|
-
fi
|
|
25
|
-
|
|
26
|
-
# Executa o handler TypeScript
|
|
27
|
-
echo "$EVENT" | node "$HANDLER" post-artifact
|
|
28
|
-
|
|
29
|
-
EXIT_CODE=$?
|
|
30
|
-
|
|
31
|
-
# Log do resultado
|
|
32
|
-
if [ $EXIT_CODE -eq 0 ]; then
|
|
33
|
-
echo "[post-artifact-generate] Artifact processed successfully" >&2
|
|
34
|
-
else
|
|
35
|
-
echo "[post-artifact-generate] Warning: Artifact processing had issues" >&2
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
# Este hook nao bloqueia, apenas avisa
|
|
39
|
-
exit 0
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Post-Implement Validation Hook (v2 — REST API)
|
|
3
|
-
# Validates workflow consistency after IMPLEMENT phase.
|
|
4
|
-
# Defense-in-depth: agents track progress via MCP, this validates externally.
|
|
5
|
-
#
|
|
6
|
-
# Exit codes:
|
|
7
|
-
# 0 = Validation passed or skipped
|
|
8
|
-
# 1 = Warning detected (TDD violation detected)
|
|
9
|
-
|
|
10
|
-
set -e
|
|
11
|
-
|
|
12
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
14
|
-
STATE_DIR="$PROJECT_ROOT/.orchestrator/.state"
|
|
15
|
-
|
|
16
|
-
# API Configuration
|
|
17
|
-
API_URL="${ORCHESTRATOR_API_URL:-http://localhost:3001}"
|
|
18
|
-
AUTH_EMAIL="${ORCHESTRATOR_AUTH_EMAIL:-admin@orchestrator.local}"
|
|
19
|
-
AUTH_PASSWORD="${ORCHESTRATOR_AUTH_PASSWORD:-admin123}"
|
|
20
|
-
PROJECT_ID="${ORCHESTRATOR_PROJECT_ID:-d001d65d-25f5-4d13-b1dc-d006873e949c}"
|
|
21
|
-
|
|
22
|
-
# Colors
|
|
23
|
-
RED='\033[0;31m'
|
|
24
|
-
YELLOW='\033[1;33m'
|
|
25
|
-
GREEN='\033[0;32m'
|
|
26
|
-
NC='\033[0m'
|
|
27
|
-
|
|
28
|
-
log_info() { echo -e "${GREEN}[post-implement-validate]${NC} $1" >&2; }
|
|
29
|
-
log_warn() { echo -e "${YELLOW}[post-implement-validate] WARNING:${NC} $1" >&2; }
|
|
30
|
-
|
|
31
|
-
# Auth: get cached token
|
|
32
|
-
get_token() {
|
|
33
|
-
mkdir -p "$STATE_DIR"
|
|
34
|
-
local cached="$STATE_DIR/jwt-token"
|
|
35
|
-
if [ -f "$cached" ]; then
|
|
36
|
-
local age=$(( $(date +%s) - $(stat -c%Y "$cached" 2>/dev/null || stat -f%m "$cached" 2>/dev/null || echo 0) ))
|
|
37
|
-
if [ "$age" -lt 3500 ]; then
|
|
38
|
-
cat "$cached"
|
|
39
|
-
return
|
|
40
|
-
fi
|
|
41
|
-
fi
|
|
42
|
-
local resp
|
|
43
|
-
resp=$(curl -s -f -X POST "${API_URL}/api/v1/auth/login" \
|
|
44
|
-
-H "Content-Type: application/json" \
|
|
45
|
-
-d "{\"email\":\"${AUTH_EMAIL}\",\"password\":\"${AUTH_PASSWORD}\"}" 2>/dev/null) || return 1
|
|
46
|
-
local token
|
|
47
|
-
token=$(echo "$resp" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(d);console.log(j.data?.accessToken||j.accessToken||j.token||'')}catch{console.log('')}})" 2>/dev/null)
|
|
48
|
-
if [ -n "$token" ]; then
|
|
49
|
-
echo "$token" > "$cached"
|
|
50
|
-
echo "$token"
|
|
51
|
-
fi
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# Get workflow status from REST API
|
|
55
|
-
TOKEN=$(get_token) || { exit 0; } # Can't auth → skip silently
|
|
56
|
-
|
|
57
|
-
WORKFLOW_RESP=$(curl -s -f "${API_URL}/api/v1/workflows?status=in_progress" \
|
|
58
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
59
|
-
-H "X-Project-ID: $PROJECT_ID" 2>/dev/null) || { exit 0; }
|
|
60
|
-
|
|
61
|
-
# Extract workflow info
|
|
62
|
-
WORKFLOW_INFO=$(echo "$WORKFLOW_RESP" | node -e "
|
|
63
|
-
let d='';
|
|
64
|
-
process.stdin.on('data',c=>d+=c);
|
|
65
|
-
process.stdin.on('end',()=>{
|
|
66
|
-
try {
|
|
67
|
-
const j=JSON.parse(d);
|
|
68
|
-
const wfs=j.data||j;
|
|
69
|
-
const wf=Array.isArray(wfs)?wfs[0]:wfs;
|
|
70
|
-
if(!wf){console.log('{}');return;}
|
|
71
|
-
console.log(JSON.stringify({
|
|
72
|
-
id:wf.id||'',
|
|
73
|
-
phase:wf.currentPhase||wf.phase||'',
|
|
74
|
-
status:wf.status||''
|
|
75
|
-
}));
|
|
76
|
-
}catch{console.log('{}')}
|
|
77
|
-
});
|
|
78
|
-
" 2>/dev/null)
|
|
79
|
-
|
|
80
|
-
CURRENT_PHASE=$(echo "$WORKFLOW_INFO" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).phase||'unknown')}catch{console.log('unknown')}})" 2>/dev/null)
|
|
81
|
-
STATUS=$(echo "$WORKFLOW_INFO" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{console.log(JSON.parse(d).status||'unknown')}catch{console.log('unknown')}})" 2>/dev/null)
|
|
82
|
-
|
|
83
|
-
# Count source and test files
|
|
84
|
-
TS_FILES_COUNT=0
|
|
85
|
-
if [ -d "$PROJECT_ROOT/src" ]; then
|
|
86
|
-
TS_FILES_COUNT=$(find "$PROJECT_ROOT/src" -name "*.ts" 2>/dev/null | wc -l | tr -d ' ')
|
|
87
|
-
fi
|
|
88
|
-
TEST_FILES_COUNT=0
|
|
89
|
-
if [ -d "$PROJECT_ROOT/tests" ]; then
|
|
90
|
-
TEST_FILES_COUNT=$(find "$PROJECT_ROOT/tests" \( -name "*.test.ts" -o -name "*.spec.ts" \) 2>/dev/null | wc -l | tr -d ' ')
|
|
91
|
-
fi
|
|
92
|
-
|
|
93
|
-
log_info "Phase: $CURRENT_PHASE | Status: $STATUS | Src: $TS_FILES_COUNT | Tests: $TEST_FILES_COUNT"
|
|
94
|
-
|
|
95
|
-
# TDD check: source files without tests
|
|
96
|
-
if [ "$TS_FILES_COUNT" -gt 5 ] && [ "$TEST_FILES_COUNT" -eq 0 ]; then
|
|
97
|
-
log_warn "Found $TS_FILES_COUNT source files but no test files. TDD may not have been followed."
|
|
98
|
-
exit 1
|
|
99
|
-
fi
|
|
100
|
-
|
|
101
|
-
log_info "Validation passed."
|
|
102
|
-
exit 0
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Pre-Agent Invoke Hook
|
|
3
|
-
# Executado antes de invocar um subagent
|
|
4
|
-
# Valida contexto e injeta informacoes da KB
|
|
5
|
-
|
|
6
|
-
set -e
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
10
|
-
|
|
11
|
-
# Recebe evento via stdin ou argumento
|
|
12
|
-
if [ -n "$1" ]; then
|
|
13
|
-
EVENT="$1"
|
|
14
|
-
else
|
|
15
|
-
EVENT=$(cat)
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
# Verifica se temos o handler compilado
|
|
19
|
-
HANDLER="$PROJECT_ROOT/dist/hook.js"
|
|
20
|
-
|
|
21
|
-
if [ ! -f "$HANDLER" ]; then
|
|
22
|
-
echo '{"success": false, "error": "Hook handler not compiled. Run npm run build first."}' >&2
|
|
23
|
-
exit 1
|
|
24
|
-
fi
|
|
25
|
-
|
|
26
|
-
# Executa o handler TypeScript
|
|
27
|
-
echo "$EVENT" | node "$HANDLER" pre-agent-invoke
|
|
28
|
-
|
|
29
|
-
EXIT_CODE=$?
|
|
30
|
-
|
|
31
|
-
# Exit code determina se agente pode prosseguir
|
|
32
|
-
# 0 = permitido
|
|
33
|
-
# 1 = bloqueado
|
|
34
|
-
exit $EXIT_CODE
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Pre-Phase Advance Hook
|
|
3
|
-
# Executado antes de avancar para proxima fase
|
|
4
|
-
# Avalia gate e cria checkpoint
|
|
5
|
-
|
|
6
|
-
set -e
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
10
|
-
|
|
11
|
-
# Recebe evento via stdin ou argumento
|
|
12
|
-
if [ -n "$1" ]; then
|
|
13
|
-
EVENT="$1"
|
|
14
|
-
else
|
|
15
|
-
EVENT=$(cat)
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
# Verifica se temos o handler compilado
|
|
19
|
-
HANDLER="$PROJECT_ROOT/dist/hook.js"
|
|
20
|
-
|
|
21
|
-
if [ ! -f "$HANDLER" ]; then
|
|
22
|
-
echo '{"success": false, "error": "Hook handler not compiled. Run npm run build first."}' >&2
|
|
23
|
-
exit 1
|
|
24
|
-
fi
|
|
25
|
-
|
|
26
|
-
# Executa o handler TypeScript
|
|
27
|
-
echo "$EVENT" | node "$HANDLER" pre-phase-advance
|
|
28
|
-
|
|
29
|
-
EXIT_CODE=$?
|
|
30
|
-
|
|
31
|
-
# Exit code determina se fase pode avancar
|
|
32
|
-
# 0 = gate passou, pode avancar
|
|
33
|
-
# 1 = gate falhou, bloqueado
|
|
34
|
-
if [ $EXIT_CODE -eq 0 ]; then
|
|
35
|
-
echo "[pre-phase-advance] Gate passed, advancing phase" >&2
|
|
36
|
-
else
|
|
37
|
-
echo "[pre-phase-advance] Gate failed, phase advance blocked" >&2
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
exit $EXIT_CODE
|