arkaos 2.6.0 → 2.8.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.
@@ -1,312 +1,140 @@
1
1
  #!/usr/bin/env bash
2
2
  # ============================================================================
3
- # ARKA OS — UserPromptSubmit Hook (5-Layer Context Injection)
4
- # Injects contextual rules per prompt with caching for performance
5
- # Timeout: 10s | Output: JSON to stdout | Target: <200ms
3
+ # ArkaOS v2 — UserPromptSubmit Hook (Synapse v2 Bridge)
4
+ # Calls Python Synapse engine for 8-layer context injection
5
+ # Timeout: 10s | Output: JSON to stdout | Target: <100ms
6
6
  # ============================================================================
7
7
 
8
8
  input=$(cat)
9
9
 
10
- # ─── Performance Timing ──────────────────────────────────────────────────
11
- _HOOK_START=$(date +%s 2>/dev/null)
12
- _HOOK_START_NS=$(date +%s%N 2>/dev/null || echo "0")
13
- _hook_ms() {
14
- local end_ns=$(date +%s%N 2>/dev/null || echo "0")
15
- if [ "$_HOOK_START_NS" != "0" ] && [ "$end_ns" != "0" ] && [ ${#end_ns} -gt 10 ]; then
16
- echo $(( (end_ns - _HOOK_START_NS) / 1000000 ))
17
- else
18
- echo $(( ($(date +%s) - _HOOK_START) * 1000 ))
19
- fi
20
- }
10
+ # ─── V1 Migration Detection ─────────────────────────────────────────────
11
+ V1_PATHS=("$HOME/.claude/skills/arka-os" "$HOME/.claude/skills/arkaos")
12
+ MIGRATION_MARKER="$HOME/.arkaos/migrated-from-v1"
21
13
 
22
- # Extract fields
23
- PROMPT=$(echo "$input" | jq -r '.prompt // ""' 2>/dev/null)
24
- CWD=$(echo "$input" | jq -r '.cwd // ""' 2>/dev/null)
25
- SESSION_ID=$(echo "$input" | jq -r '.session_id // ""' 2>/dev/null)
14
+ for v1_path in "${V1_PATHS[@]}"; do
15
+ if [ -d "$v1_path" ] && [ ! -f "$MIGRATION_MARKER" ]; then
16
+ echo "{\"additionalContext\": \"[MIGRATION] ArkaOS v1 detected at $v1_path. Run: npx arkaos migrate — This will backup v1, preserve your data, and install v2. See: https://github.com/andreagroferreira/arka-os#install\"}"
17
+ exit 0
18
+ fi
19
+ done
20
+
21
+ # ─── Sync Version Detection ────────────────────────────────────────────
22
+ SYNC_STATE="$HOME/.arkaos/sync-state.json"
23
+ ARKAOS_VERSION_FILE="$HOME/.arkaos/.repo-path"
24
+
25
+ if [ -f "$ARKAOS_VERSION_FILE" ]; then
26
+ _REPO_PATH=$(cat "$ARKAOS_VERSION_FILE")
27
+ if [ -f "$_REPO_PATH/VERSION" ]; then
28
+ _CURRENT_VERSION=$(cat "$_REPO_PATH/VERSION")
29
+ elif [ -f "$_REPO_PATH/package.json" ]; then
30
+ _CURRENT_VERSION=$(python3 -c "import json; print(json.load(open('$_REPO_PATH/package.json'))['version'])" 2>/dev/null || echo "")
31
+ fi
26
32
 
27
- CONTEXT_PARTS=()
28
- ARKA_OS="${ARKA_OS:-$HOME/.claude/skills/arka}"
29
- CACHE_DIR="/tmp/arka-context-cache"
30
- mkdir -p "$CACHE_DIR"
33
+ if [ -n "${_CURRENT_VERSION:-}" ]; then
34
+ if [ -f "$SYNC_STATE" ]; then
35
+ _SYNCED_VERSION=$(python3 -c "import json; print(json.load(open('$SYNC_STATE'))['version'])" 2>/dev/null || echo "none")
36
+ else
37
+ _SYNCED_VERSION="none"
38
+ fi
31
39
 
32
- # ─── Cache Helper ─────────────────────────────────────────────────────────
33
- # cache_get <key> <ttl_seconds> returns cached value or empty
34
- cache_get() {
35
- local file="$CACHE_DIR/$1"
36
- local ttl="$2"
37
- if [ -f "$file" ]; then
38
- local age=$(( $(date +%s) - $(stat -f%m "$file" 2>/dev/null || stat -c%Y "$file" 2>/dev/null || echo 0) ))
39
- if [ "$age" -lt "$ttl" ]; then
40
- cat "$file"
41
- return 0
40
+ if [ "$_CURRENT_VERSION" != "$_SYNCED_VERSION" ]; then
41
+ _SYNC_NOTICE="[arka:update-available] ArkaOS v${_CURRENT_VERSION} installed (synced: ${_SYNCED_VERSION}). Run /arka update to sync all projects. "
42
42
  fi
43
43
  fi
44
- return 1
45
- }
44
+ fi
46
45
 
47
- cache_set() {
48
- echo "$2" > "$CACHE_DIR/$1"
49
- }
46
+ # ─── Session Greeting (now handled by SessionStart hook via systemMessage) ──
47
+ _ARKA_GREETING=""
50
48
 
51
- # ─── L0: Constitution (compressed, 300s cache) ───────────────────────────
52
- L0=$(cache_get "constitution" 300) || {
53
- REPO_PATH=$(cat "$ARKA_OS/.repo-path" 2>/dev/null || echo "")
54
- CONSTITUTION_FILE=""
55
- [ -f "$REPO_PATH/CONSTITUTION.md" ] && CONSTITUTION_FILE="$REPO_PATH/CONSTITUTION.md"
56
- if [ -n "$CONSTITUTION_FILE" ]; then
57
- L0="[Constitution] NON-NEGOTIABLE: branch-isolation, obsidian-output, authority-boundaries, security-gate, context-first, solid-clean-code, spec-driven, human-writing, squad-routing, full-visibility, sequential-validation, mandatory-qa, arka-supremacy | QUALITY-GATE: marta-cqo, eduardo-copy, francisca-tech-ux | MUST: conventional-commits, test-coverage, pattern-matching, actionable-output, memory-persistence"
58
- cache_set "constitution" "$L0"
49
+ # ─── Performance Timing ──────────────────────────────────────────────────
50
+ _HOOK_START_NS=$(date +%s%N 2>/dev/null || echo "0")
51
+ _hook_ms() {
52
+ local end_ns=$(date +%s%N 2>/dev/null || echo "0")
53
+ if [ "$_HOOK_START_NS" != "0" ] && [ "$end_ns" != "0" ] && [ ${#end_ns} -gt 10 ]; then
54
+ echo $(( (end_ns - _HOOK_START_NS) / 1000000 ))
59
55
  else
60
- L0=""
56
+ echo "0"
61
57
  fi
62
58
  }
63
- [ -n "$L0" ] && CONTEXT_PARTS+=("$L0")
64
- _L0_MS=$(_hook_ms)
65
-
66
- # ─── L1: Department Routing (no cache — fast string match) ───────────────
67
- PROMPT_LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]')
68
- DETECTED_DEPT=""
69
59
 
70
- if echo "$PROMPT_LOWER" | grep -qE '\b(build|code|feature|deploy|test|review|scaffold|debug|refactor|api|migration|stack)\b'; then
71
- DETECTED_DEPT="dev"
72
- elif echo "$PROMPT_LOWER" | grep -qE '\b(budget|invoice|revenue|forecast|profit|loss|roi|margin|cash.?flow|financial|invest)\b'; then
73
- DETECTED_DEPT="finance"
74
- elif echo "$PROMPT_LOWER" | grep -qE '\b(social|content|campaign|post|instagram|linkedin|twitter|tiktok|seo|marketing|ads|email.?campaign)\b'; then
75
- DETECTED_DEPT="marketing"
76
- elif echo "$PROMPT_LOWER" | grep -qE '\b(store|product|shop|shopify|ecommerce|catalog|inventory|cart|checkout|pricing)\b'; then
77
- DETECTED_DEPT="ecommerce"
78
- elif echo "$PROMPT_LOWER" | grep -qE '\b(strategy|brainstorm|market|swot|competitor|roadmap|pivot|growth)\b'; then
79
- DETECTED_DEPT="strategy"
80
- elif echo "$PROMPT_LOWER" | grep -qE '\b(task|email|calendar|automate|meeting|workflow|process|schedule|slack|discord|notify)\b'; then
81
- DETECTED_DEPT="operations"
82
- elif echo "$PROMPT_LOWER" | grep -qE '\b(learn|persona|knowledge|youtube|transcribe|article|research)\b'; then
83
- DETECTED_DEPT="knowledge"
84
- elif echo "$PROMPT_LOWER" | grep -qE '\b(brand|logo|colors|palette|mockup|photoshoot|brand.?identity|brand.?guide|mood.?board|naming|positioning|visual.?design|motion.?design|brand.?video|social.?kit)\b'; then
85
- DETECTED_DEPT="brand"
86
- fi
87
- [ -n "$DETECTED_DEPT" ] && CONTEXT_PARTS+=("[dept:$DETECTED_DEPT]")
88
- _L1_MS=$(( $(_hook_ms) - ${_L0_MS:-0} ))
89
-
90
- # ─── L2: Agent Memory (30s cache) ────────────────────────────────────────
91
- # Detect agent name from prompt
92
- DETECTED_AGENT=""
93
- if echo "$PROMPT_LOWER" | grep -qE '\bmarco\b|/.*cto\b'; then
94
- DETECTED_AGENT="cto"
95
- elif echo "$PROMPT_LOWER" | grep -qE '\bpaulo\b|tech.?lead'; then
96
- DETECTED_AGENT="tech-lead"
97
- elif echo "$PROMPT_LOWER" | grep -qE '\bgabriel\b|architect'; then
98
- DETECTED_AGENT="architect"
99
- elif echo "$PROMPT_LOWER" | grep -qE '\bandre\b|senior.?dev|backend'; then
100
- DETECTED_AGENT="senior-dev"
101
- elif echo "$PROMPT_LOWER" | grep -qE '\bdiana\b|frontend.?dev'; then
102
- DETECTED_AGENT="frontend-dev"
103
- elif echo "$PROMPT_LOWER" | grep -qE '\bbruno\b|security'; then
104
- DETECTED_AGENT="security"
105
- elif echo "$PROMPT_LOWER" | grep -qE '\bcarlos\b|devops'; then
106
- DETECTED_AGENT="devops"
107
- elif echo "$PROMPT_LOWER" | grep -qE '\brita\b|\bqa\b'; then
108
- DETECTED_AGENT="qa"
109
- elif echo "$PROMPT_LOWER" | grep -qE '\blucas\b|analyst'; then
110
- DETECTED_AGENT="analyst"
111
- elif echo "$PROMPT_LOWER" | grep -qE '\bhelena\b|cfo'; then
112
- DETECTED_AGENT="cfo"
113
- elif echo "$PROMPT_LOWER" | grep -qE '\bsofia\b|coo'; then
114
- DETECTED_AGENT="coo"
115
- elif echo "$PROMPT_LOWER" | grep -qE '\bluna\b|content.?creator'; then
116
- DETECTED_AGENT="content-creator"
117
- elif echo "$PROMPT_LOWER" | grep -qE '\bricardo\b|ecommerce.?manager'; then
118
- DETECTED_AGENT="ecommerce-manager"
119
- elif echo "$PROMPT_LOWER" | grep -qE '\btomas\b|strategist'; then
120
- DETECTED_AGENT="strategist"
121
- elif echo "$PROMPT_LOWER" | grep -qE '\bclara\b|knowledge.?curator'; then
122
- DETECTED_AGENT="knowledge-curator"
123
- elif echo "$PROMPT_LOWER" | grep -qE '\bvalentina\b|creative.?director'; then
124
- DETECTED_AGENT="creative-director"
125
- elif echo "$PROMPT_LOWER" | grep -qE '\bmateus\b|brand.?strategist'; then
126
- DETECTED_AGENT="brand-strategist"
127
- elif echo "$PROMPT_LOWER" | grep -qE '\bisabel\b|visual.?designer'; then
128
- DETECTED_AGENT="visual-designer"
129
- elif echo "$PROMPT_LOWER" | grep -qE '\brafael\b|motion.?designer'; then
130
- DETECTED_AGENT="motion-designer"
60
+ # ─── Paths ───────────────────────────────────────────────────────────────
61
+ # Resolve ARKAOS_ROOT: env var → .repo-path → npm package → fallback
62
+ if [ -n "${ARKAOS_ROOT:-}" ]; then
63
+ : # already set
64
+ elif [ -f "$HOME/.arkaos/.repo-path" ]; then
65
+ ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
66
+ elif [ -d "$HOME/.arkaos" ]; then
67
+ ARKAOS_ROOT="$HOME/.arkaos"
68
+ else
69
+ ARKAOS_ROOT="/Users/andreagroferreira/.npm/_npx/67d92defd11b9985/node_modules/arkaos"
131
70
  fi
71
+ export ARKAOS_ROOT
132
72
 
133
- if [ -n "$DETECTED_AGENT" ]; then
134
- AGENT_CACHE_KEY="agent-${DETECTED_AGENT}"
135
- AGENT_CTX=$(cache_get "$AGENT_CACHE_KEY" 30) || {
136
- AGENT_MEM="$HOME/.claude/agent-memory/arka-${DETECTED_AGENT}/MEMORY.md"
137
- AGENT_CTX="[agent:$DETECTED_AGENT"
73
+ CACHE_DIR="/tmp/arkaos-context-cache"
74
+ CACHE_TTL=300 # Constitution cache: 5 minutes
138
75
 
139
- # Inject DISC profile from agents-registry.json (fast jq lookup)
140
- REPO_PATH=$(cat "$ARKA_OS/.repo-path" 2>/dev/null || echo "")
141
- REGISTRY_FILE="$REPO_PATH/knowledge/agents-registry.json"
142
- if [ -f "$REGISTRY_FILE" ] && command -v jq &>/dev/null; then
143
- DISC_COMBO=$(jq -r --arg id "$DETECTED_AGENT" '.agents[] | select(.id == $id) | .disc.combination // ""' "$REGISTRY_FILE" 2>/dev/null)
144
- [ -n "$DISC_COMBO" ] && AGENT_CTX+=" disc:$DISC_COMBO"
145
- fi
146
-
147
- if [ -f "$AGENT_MEM" ]; then
148
- # Extract last 3 gotchas from agent memory
149
- GOTCHAS=$(sed -n '/^## Gotchas/,/^## /{ /^## Gotchas/d; /^## /d; /^$/d; p; }' "$AGENT_MEM" 2>/dev/null | head -3)
150
- if [ -n "$GOTCHAS" ]; then
151
- AGENT_CTX+=" gotchas: $(echo "$GOTCHAS" | tr '\n' '; ' | head -c 200)"
152
- fi
153
- fi
76
+ mkdir -p "$CACHE_DIR" 2>/dev/null
154
77
 
155
- AGENT_CTX+="]"
156
- cache_set "$AGENT_CACHE_KEY" "$AGENT_CTX"
157
- }
158
- CONTEXT_PARTS+=("$AGENT_CTX")
78
+ # ─── Extract user input from hook JSON ───────────────────────────────────
79
+ user_input=""
80
+ if command -v jq &>/dev/null; then
81
+ user_input=$(echo "$input" | jq -r '.userInput // .message // ""' 2>/dev/null)
82
+ fi
83
+ # Fallback: try to get the raw text
84
+ if [ -z "$user_input" ]; then
85
+ user_input=$(echo "$input" | head -c 2000)
159
86
  fi
160
- _L2_MS=$(( $(_hook_ms) - ${_L0_MS:-0} - ${_L1_MS:-0} ))
161
87
 
162
- # ─── L3: Active Project (30s cache) ──────────────────────────────────────
163
- if [ -n "$CWD" ]; then
164
- PROJECT_CACHE_KEY="project-$(echo "$CWD" | md5 2>/dev/null || echo "$CWD" | md5sum 2>/dev/null | cut -d' ' -f1 || echo "nocache")"
165
- PROJECT_CTX=$(cache_get "$PROJECT_CACHE_KEY" 30) || {
166
- PROJECT_CTX=""
167
- # Check ARKA OS projects/ directory
168
- REPO_PATH=$(cat "$ARKA_OS/.repo-path" 2>/dev/null || echo "")
169
- if [ -n "$REPO_PATH" ] && [ -d "$REPO_PATH/projects" ]; then
170
- for proj_md in "$REPO_PATH/projects"/*/PROJECT.md; do
171
- [ -f "$proj_md" ] || continue
172
- PROJ_DIR=$(dirname "$proj_md")
173
- if [ -f "$PROJ_DIR/.project-path" ]; then
174
- PROJ_PATH=$(cat "$PROJ_DIR/.project-path" 2>/dev/null)
175
- if [ -n "$PROJ_PATH" ] && [[ "$CWD" == "$PROJ_PATH"* ]]; then
176
- PROJ_NAME=$(basename "$PROJ_DIR")
177
- # Try to extract stack from PROJECT.md
178
- PROJ_STACK=$(grep -i 'stack\|framework' "$proj_md" 2>/dev/null | head -1 | sed 's/.*: *//' | head -c 50)
179
- PROJECT_CTX="[project:$PROJ_NAME"
180
- [ -n "$PROJ_STACK" ] && PROJECT_CTX+=" stack:$PROJ_STACK"
181
- PROJECT_CTX+="]"
182
- break
183
- fi
184
- fi
185
- done
186
- fi
88
+ # ─── Try Python Synapse bridge first ────────────────────────────────────
89
+ python_result=""
90
+ BRIDGE_SCRIPT="${ARKAOS_ROOT}/scripts/synapse-bridge.py"
187
91
 
188
- # Also check installed skills for project paths
189
- if [ -z "$PROJECT_CTX" ]; then
190
- for proj_dir in "$HOME/.claude/skills"/arka-*/; do
191
- [ -d "$proj_dir" ] || continue
192
- if [ -f "$proj_dir/.project-path" ]; then
193
- PROJ_PATH=$(cat "$proj_dir/.project-path" 2>/dev/null)
194
- if [ -n "$PROJ_PATH" ] && [[ "$CWD" == "$PROJ_PATH"* ]]; then
195
- PROJ_NAME=$(basename "$proj_dir" | sed 's/^arka-//')
196
- PROJECT_CTX="[project:$PROJ_NAME]"
197
- break
198
- fi
199
- fi
200
- done
201
- fi
92
+ if command -v python3 &>/dev/null && [ -f "$BRIDGE_SCRIPT" ]; then
93
+ bridge_output=$(echo "{\"user_input\":$(echo "$user_input" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || echo '""')}" \
94
+ | ARKAOS_ROOT="$ARKAOS_ROOT" python3 "$BRIDGE_SCRIPT" --root "$ARKAOS_ROOT" 2>/dev/null)
202
95
 
203
- cache_set "$PROJECT_CACHE_KEY" "$PROJECT_CTX"
204
- }
205
- [ -n "$PROJECT_CTX" ] && CONTEXT_PARTS+=("$PROJECT_CTX")
96
+ if [ -n "$bridge_output" ]; then
97
+ python_result=$(echo "$bridge_output" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('context_string',''))" 2>/dev/null)
98
+ fi
206
99
  fi
207
- _L3_MS=$(( $(_hook_ms) - ${_L0_MS:-0} - ${_L1_MS:-0} - ${_L2_MS:-0} ))
208
100
 
209
- # ─── L4: Git Branch Detection (no cache — fast check) ────────────────────
210
- if [ -n "$CWD" ]; then
211
- CURRENT_BRANCH=$(git -C "$CWD" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
212
- if [ -n "$CURRENT_BRANCH" ] && [ "$CURRENT_BRANCH" != "main" ] && [ "$CURRENT_BRANCH" != "master" ] && [ "$CURRENT_BRANCH" != "dev" ]; then
213
- CONTEXT_PARTS+=("[branch:$CURRENT_BRANCH]")
101
+ # ─── Fallback: Bash-only context (if Python unavailable) ────────────────
102
+ if [ -z "$python_result" ]; then
103
+ # L0: Constitution (cached)
104
+ L0=""
105
+ L0_CACHE="$CACHE_DIR/l0-constitution"
106
+ if [ -f "$L0_CACHE" ] && [ $(($(date +%s) - $(stat -f%m "$L0_CACHE" 2>/dev/null || stat -c%Y "$L0_CACHE" 2>/dev/null || echo 0))) -lt $CACHE_TTL ]; then
107
+ L0=$(cat "$L0_CACHE")
108
+ else
109
+ L0="[Constitution] NON-NEGOTIABLE: branch-isolation, obsidian-output, authority-boundaries, security-gate, context-first, solid-clean-code, spec-driven, human-writing, squad-routing, full-visibility, sequential-validation, mandatory-qa, arka-supremacy | QUALITY-GATE: marta-cqo, eduardo-copy, francisca-tech-ux | MUST: conventional-commits, test-coverage, pattern-matching, actionable-output, memory-persistence"
110
+ echo "$L0" > "$L0_CACHE" 2>/dev/null
214
111
  fi
215
- fi
216
- _L4_MS=$(( $(_hook_ms) - ${_L0_MS:-0} - ${_L1_MS:-0} - ${_L2_MS:-0} - ${_L3_MS:-0} ))
217
112
 
218
- # ─── Gotchas Injection (30s cache) ───────────────────────────────────────
219
- if [ -n "$DETECTED_DEPT" ]; then
220
- GOTCHA_CACHE_KEY="gotchas-${DETECTED_DEPT}"
221
- GOTCHA_CTX=$(cache_get "$GOTCHA_CACHE_KEY" 30) || {
222
- GOTCHA_CTX=""
223
- GOTCHAS_FILE="$HOME/.arka-os/gotchas.json"
224
- if [ -f "$GOTCHAS_FILE" ] && command -v jq &>/dev/null; then
225
- # Get top 2 recurring errors for this department with count >= 3 (include suggestions)
226
- TOP_GOTCHAS=$(jq -r --arg cat "$DETECTED_DEPT" \
227
- '[.[] | select(.category == $cat and .count >= 3)] | sort_by(-.count) | .[0:2] | .[] |
228
- if .suggestion then "\(.pattern) (x\(.count)) \u2192 \(.suggestion)" else "\(.pattern) (x\(.count))" end' \
229
- "$GOTCHAS_FILE" 2>/dev/null)
230
- if [ -n "$TOP_GOTCHAS" ]; then
231
- GOTCHA_CTX="[gotchas:$DETECTED_DEPT $(echo "$TOP_GOTCHAS" | tr '\n' '; ' | head -c 300)]"
232
- fi
233
- fi
234
- cache_set "$GOTCHA_CACHE_KEY" "$GOTCHA_CTX"
235
- }
236
- [ -n "$GOTCHA_CTX" ] && CONTEXT_PARTS+=("$GOTCHA_CTX")
237
- fi
113
+ # L4: Git branch
114
+ L4=""
115
+ branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
116
+ if [ -n "$branch" ] && [ "$branch" != "main" ] && [ "$branch" != "master" ] && [ "$branch" != "dev" ]; then
117
+ L4="[branch:$branch]"
118
+ fi
238
119
 
239
- # ─── L5: Command Hint (30s cache) ────────────────────────────────────────
240
- # Fast keyword lookup against commands-registry for non-explicit prompts
241
- if [ -n "$PROMPT" ] && ! echo "$PROMPT" | grep -qE '^/(dev|mkt|ecom|fin|ops|strat|kb|arka|do) '; then
242
- CMD_CACHE_KEY="cmdhint-$(echo "$PROMPT_LOWER" | md5 2>/dev/null || echo "$PROMPT_LOWER" | md5sum 2>/dev/null | cut -d' ' -f1)"
243
- CMD_HINT=$(cache_get "$CMD_CACHE_KEY" 30) || {
244
- CMD_HINT=""
245
- REPO_PATH=$(cat "$ARKA_OS/.repo-path" 2>/dev/null || echo "")
246
- REGISTRY="$REPO_PATH/knowledge/commands-registry.json"
247
- if [ -f "$REGISTRY" ] && command -v jq &>/dev/null; then
248
- # Extract words from prompt and match against registry keywords
249
- CMD_HINT=$(jq -r --arg prompt "$PROMPT_LOWER" '
250
- ($prompt | split(" ") | map(select(length > 2))) as $words |
251
- [.commands[] |
252
- {id, command, department,
253
- score: ([.keywords[] | . as $kw |
254
- if ($words | any(. == $kw)) then 2
255
- elif ($words | join(" ") | test($kw)) then 3
256
- else 0 end
257
- ] | add // 0)}
258
- ] | sort_by(-.score) | [.[:2][] | select(.score > 0)] |
259
- if length > 0 then
260
- map("[hint:\(.command)]") | join(" ")
261
- else "" end
262
- ' "$REGISTRY" 2>/dev/null)
263
- fi
264
- cache_set "$CMD_CACHE_KEY" "$CMD_HINT"
265
- }
266
- [ -n "$CMD_HINT" ] && CONTEXT_PARTS+=("$CMD_HINT")
267
- fi
268
- _L5_MS=$(( $(_hook_ms) - ${_L0_MS:-0} - ${_L1_MS:-0} - ${_L2_MS:-0} - ${_L3_MS:-0} - ${_L4_MS:-0} ))
120
+ # L7: Time
121
+ hour=$(date +%H)
122
+ if [ "$hour" -ge 5 ] && [ "$hour" -lt 12 ]; then
123
+ L7="[time:morning]"
124
+ elif [ "$hour" -ge 12 ] && [ "$hour" -lt 18 ]; then
125
+ L7="[time:afternoon]"
126
+ else
127
+ L7="[time:evening]"
128
+ fi
269
129
 
270
- # ─── Time of Day (no cache) ──────────────────────────────────────────────
271
- HOUR=$(date +%H)
272
- if [ "$HOUR" -lt 12 ]; then
273
- CONTEXT_PARTS+=("[time:morning]")
274
- elif [ "$HOUR" -lt 18 ]; then
275
- CONTEXT_PARTS+=("[time:afternoon]")
276
- else
277
- CONTEXT_PARTS+=("[time:evening]")
130
+ python_result="$L0 $L4 $L7"
278
131
  fi
279
132
 
280
- # ─── Log Metrics ─────────────────────────────────────────────────────────
281
- _DURATION_MS=$(_hook_ms)
282
- METRICS_FILE="$HOME/.arka-os/hook-metrics.json"
283
- METRICS_LOCK="$HOME/.arka-os/hook-metrics.lock"
284
- mkdir -p "$HOME/.arka-os"
285
- (
286
- if command -v flock &>/dev/null; then flock -w 2 200; else true; fi
287
- [ ! -f "$METRICS_FILE" ] && echo '[]' > "$METRICS_FILE"
288
- NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
289
- jq --argjson dur "$_DURATION_MS" --arg ts "$NOW" --arg hook "user-prompt-submit" \
290
- --argjson l0 "${_L0_MS:-0}" --argjson l1 "${_L1_MS:-0}" --argjson l2 "${_L2_MS:-0}" \
291
- --argjson l3 "${_L3_MS:-0}" --argjson l4 "${_L4_MS:-0}" --argjson l5 "${_L5_MS:-0}" \
292
- '. += [{"hook": $hook, "duration_ms": $dur, "timestamp": $ts, "layers": {"L0": $l0, "L1": $l1, "L2": $l2, "L3": $l3, "L4": $l4, "L5": $l5}}] | .[-500:]' \
293
- "$METRICS_FILE" > "$METRICS_FILE.tmp" 2>/dev/null && mv "$METRICS_FILE.tmp" "$METRICS_FILE"
294
- ) 200>"$METRICS_LOCK" 2>/dev/null
133
+ # ─── Output ──────────────────────────────────────────────────────────────
134
+ echo "{\"additionalContext\": \"${_ARKA_GREETING:-}${_SYNC_NOTICE:-}$python_result\"}"
295
135
 
296
- # ─── Output ───────────────────────────────────────────────────────────────
297
- if [ ${#CONTEXT_PARTS[@]} -gt 0 ]; then
298
- CONTEXT=""
299
- for part in "${CONTEXT_PARTS[@]}"; do
300
- CONTEXT+="$part "
301
- done
302
- CONTEXT="${CONTEXT% }"
303
-
304
- jq -n --arg ctx "$CONTEXT" '{
305
- "hookSpecificOutput": {
306
- "hookEventName": "UserPromptSubmit",
307
- "additionalContext": $ctx
308
- }
309
- }'
310
- else
311
- echo '{}'
136
+ # ─── Metrics ─────────────────────────────────────────────────────────────
137
+ elapsed=$(_hook_ms)
138
+ if [ "$elapsed" -gt 0 ] 2>/dev/null; then
139
+ echo "{\"hook\":\"user-prompt-submit-v2\",\"ms\":$elapsed}" >> "$CACHE_DIR/hook-metrics.jsonl" 2>/dev/null
312
140
  fi
@@ -5,6 +5,17 @@
5
5
  "padding": 2
6
6
  },
7
7
  "hooks": {
8
+ "SessionStart": [
9
+ {
10
+ "hooks": [
11
+ {
12
+ "type": "command",
13
+ "command": "{{HOOKS_DIR}}/session-start.sh",
14
+ "timeout": 5
15
+ }
16
+ ]
17
+ }
18
+ ],
8
19
  "UserPromptSubmit": [
9
20
  {
10
21
  "hooks": [
@@ -37,6 +48,17 @@
37
48
  }
38
49
  ]
39
50
  }
51
+ ],
52
+ "CwdChanged": [
53
+ {
54
+ "hooks": [
55
+ {
56
+ "type": "command",
57
+ "command": "{{HOOKS_DIR}}/cwd-changed.sh",
58
+ "timeout": 5
59
+ }
60
+ ]
61
+ }
40
62
  ]
41
63
  }
42
64
  }
@@ -0,0 +1,60 @@
1
+ # ArkaOS -- Standard Ecosystem Workflow
2
+
3
+ > All ecosystem skills MUST follow this workflow. No exceptions.
4
+ > This is referenced by all ecosystem SKILL.md files.
5
+
6
+ ## Phase 1: Context Loading
7
+
8
+ - Read ecosystem registry (`~/.claude/skills/arka/knowledge/ecosystems.json`)
9
+ - Read project descriptor(s) for affected project(s)
10
+ - Read project CLAUDE.md if it exists
11
+ - Check git status and current branch
12
+ - Load relevant memory from claude-mem
13
+
14
+ ## Phase 2: Context Verification (NON-NEGOTIABLE)
15
+
16
+ - Restate the request to confirm understanding
17
+ - Ask at least 1 clarifying question about scope or intent
18
+ - Challenge at least 1 assumption (devil's advocate)
19
+ - Search memory/knowledge base for prior related work
20
+ - Only proceed after user confirms understanding
21
+
22
+ ## Phase 3: Analysis & Planning
23
+
24
+ - Identify affected projects within the ecosystem
25
+ - Determine which squad roles are needed
26
+ - Assess complexity (simple/medium/complex)
27
+ - Create execution plan with specific steps
28
+
29
+ ## Phase 4: Plan Presentation & Approval
30
+
31
+ - Present the plan to the user with:
32
+ - Affected files/projects
33
+ - Squad roles assigned
34
+ - Estimated scope (small/medium/large)
35
+ - Risks or concerns
36
+ - Wait for explicit user approval
37
+ - Options: Approve / Modify / Cancel
38
+
39
+ ## Phase 5: Execution
40
+
41
+ - Create feature branch (NON-NEGOTIABLE for code changes)
42
+ - Use worktree isolation for multi-file changes
43
+ - Squad agents execute in their domain
44
+ - Follow TDD where applicable
45
+ - Commit frequently with conventional commit messages
46
+
47
+ ## Phase 6: Quality Gate (NON-NEGOTIABLE)
48
+
49
+ - **Marta** (CQO) orchestrates the review
50
+ - **Eduardo** (Copy Director) reviews all text output
51
+ - **Francisca** (Tech/UX Director) reviews all code and technical output
52
+ - Verdict: APPROVED or REJECTED
53
+ - REJECTED -> return to Phase 5 with specific feedback
54
+ - APPROVED -> proceed to Phase 7
55
+
56
+ ## Phase 7: Documentation & Report
57
+
58
+ - Update Obsidian vault with deliverables
59
+ - Present final report to user
60
+ - Include: what was done, files changed, tests run, next steps
@@ -0,0 +1,15 @@
1
+ # ArkaOS — User Instructions
2
+
3
+ ## Version Drift Warning
4
+
5
+ When your context contains `[arka:update-available]`, show this warning before your response:
6
+
7
+ > ArkaOS update available. Run `/arka update` to sync all projects.
8
+
9
+ ## Squad Routing
10
+
11
+ You are operating within ArkaOS. Every request routes through the appropriate department squad. Never respond as a generic assistant.
12
+
13
+ ## Language
14
+
15
+ Match the user's language. When writing in Portuguese, use European Portuguese (pt-PT).
@@ -28,6 +28,19 @@ export default {
28
28
  settings.hooks = {};
29
29
  }
30
30
 
31
+ // SessionStart — Branded greeting + version drift detection
32
+ settings.hooks.SessionStart = [
33
+ {
34
+ hooks: [
35
+ {
36
+ type: "command",
37
+ command: join(hooksDir, "session-start.sh"),
38
+ timeout: 5,
39
+ },
40
+ ],
41
+ },
42
+ ];
43
+
31
44
  // UserPromptSubmit — Synapse v2 context injection
32
45
  settings.hooks.UserPromptSubmit = [
33
46
  {
@@ -67,6 +80,19 @@ export default {
67
80
  },
68
81
  ];
69
82
 
83
+ // CwdChanged — Project/ecosystem auto-detection
84
+ settings.hooks.CwdChanged = [
85
+ {
86
+ hooks: [
87
+ {
88
+ type: "command",
89
+ command: join(hooksDir, "cwd-changed.sh"),
90
+ timeout: 5,
91
+ },
92
+ ],
93
+ },
94
+ ];
95
+
70
96
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
71
97
  console.log(" Claude Code hooks configured.");
72
98
  },