arkaos 2.7.0 → 2.9.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/VERSION CHANGED
@@ -1 +1 @@
1
- 2.7.0
1
+ 2.9.0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # ArkaOS — CwdChanged Hook
4
+ # Fires when the working directory changes. Detects ecosystem and injects
5
+ # project context so Claude knows which squad and stack to use.
6
+ # ============================================================================
7
+
8
+ input=$(cat)
9
+ NEW_CWD=$(echo "$input" | jq -r '.cwd // ""' 2>/dev/null)
10
+
11
+ if [ -z "$NEW_CWD" ] || [ ! -d "$NEW_CWD" ]; then
12
+ exit 0
13
+ fi
14
+
15
+ # ─── Detect ecosystem from ecosystems.json ─────────────────────────────
16
+ ECOSYSTEMS_FILE="$HOME/.claude/skills/arka/knowledge/ecosystems.json"
17
+ ECOSYSTEM=""
18
+ ECOSYSTEM_NAME=""
19
+
20
+ if [ -f "$ECOSYSTEMS_FILE" ] && command -v python3 &>/dev/null; then
21
+ eval "$(python3 -c "
22
+ import json, os, sys
23
+
24
+ cwd = '$NEW_CWD'
25
+ eco_file = os.path.expanduser('$ECOSYSTEMS_FILE')
26
+
27
+ try:
28
+ data = json.load(open(eco_file))
29
+ ecosystems = data.get('ecosystems', {})
30
+
31
+ for eco_id, eco in ecosystems.items():
32
+ projects = eco.get('projects', [])
33
+ for proj in projects:
34
+ # Check if cwd contains the project name
35
+ if proj in cwd:
36
+ print(f'ECOSYSTEM=\"{eco_id}\"')
37
+ print(f'ECOSYSTEM_NAME=\"{eco.get(\"name\", eco_id)}\"')
38
+ sys.exit(0)
39
+
40
+ # No match by project name, try by path patterns
41
+ if '/herd/' in cwd or '/Herd/' in cwd:
42
+ dir_name = os.path.basename(cwd.rstrip('/'))
43
+ for eco_id, eco in ecosystems.items():
44
+ for proj in eco.get('projects', []):
45
+ if proj == dir_name:
46
+ print(f'ECOSYSTEM=\"{eco_id}\"')
47
+ print(f'ECOSYSTEM_NAME=\"{eco.get(\"name\", eco_id)}\"')
48
+ sys.exit(0)
49
+ except Exception:
50
+ pass
51
+
52
+ print('ECOSYSTEM=\"\"')
53
+ print('ECOSYSTEM_NAME=\"\"')
54
+ " 2>/dev/null)"
55
+ fi
56
+
57
+ # ─── Detect stack ──────────────────────────────────────────────────────
58
+ STACK="unknown"
59
+ if [ -f "$NEW_CWD/composer.json" ]; then
60
+ STACK="laravel"
61
+ elif [ -f "$NEW_CWD/package.json" ]; then
62
+ if grep -q '"nuxt"' "$NEW_CWD/package.json" 2>/dev/null; then
63
+ STACK="nuxt"
64
+ elif grep -q '"next"' "$NEW_CWD/package.json" 2>/dev/null; then
65
+ STACK="nextjs"
66
+ elif grep -q '"react"' "$NEW_CWD/package.json" 2>/dev/null; then
67
+ STACK="react"
68
+ elif grep -q '"vue"' "$NEW_CWD/package.json" 2>/dev/null; then
69
+ STACK="vue"
70
+ else
71
+ STACK="node"
72
+ fi
73
+ elif [ -f "$NEW_CWD/pyproject.toml" ]; then
74
+ STACK="python"
75
+ fi
76
+
77
+ # ─── Check for project descriptor ─────────────────────────────────────
78
+ DIR_NAME=$(basename "$NEW_CWD")
79
+ DESCRIPTOR=""
80
+ DESCRIPTOR_FILE="$HOME/.claude/skills/arka/projects/${DIR_NAME}.md"
81
+ DESCRIPTOR_DIR="$HOME/.claude/skills/arka/projects/${DIR_NAME}/PROJECT.md"
82
+
83
+ if [ -f "$DESCRIPTOR_FILE" ]; then
84
+ DESCRIPTOR="$DESCRIPTOR_FILE"
85
+ elif [ -f "$DESCRIPTOR_DIR" ]; then
86
+ DESCRIPTOR="$DESCRIPTOR_DIR"
87
+ fi
88
+
89
+ # ─── Build context output ─────────────────────────────────────────────
90
+ CONTEXT=""
91
+
92
+ if [ -n "$ECOSYSTEM" ]; then
93
+ CONTEXT="[arka:project-context] Ecosystem: ${ECOSYSTEM_NAME} (${ECOSYSTEM}) | Stack: ${STACK} | Use /arka-${ECOSYSTEM} for dedicated squad routing."
94
+ elif [ "$STACK" != "unknown" ]; then
95
+ CONTEXT="[arka:project-context] Stack: ${STACK} | No ecosystem assigned. Use /arka onboard to register this project."
96
+ fi
97
+
98
+ if [ -n "$DESCRIPTOR" ]; then
99
+ CONTEXT="${CONTEXT} Descriptor: ${DESCRIPTOR}"
100
+ fi
101
+
102
+ if [ -n "$CONTEXT" ]; then
103
+ echo "{\"additionalContext\": \"${CONTEXT}\"}"
104
+ fi
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # ArkaOS — SessionStart Hook
4
+ # Uses systemMessage (same protocol as claude-mem) for guaranteed display.
5
+ # ============================================================================
6
+
7
+ # ─── Profile ───────────────────────────────────────────────────────────
8
+ NAME="founder"
9
+ COMPANY="WizardingCode"
10
+ VERSION="2.x"
11
+
12
+ if [ -f "$HOME/.arkaos/profile.json" ] && command -v python3 &>/dev/null; then
13
+ NAME=$(python3 -c "import json; p=json.load(open('$HOME/.arkaos/profile.json')); print(p.get('name', p.get('role', 'founder')))" 2>/dev/null || echo "founder")
14
+ COMPANY=$(python3 -c "import json; print(json.load(open('$HOME/.arkaos/profile.json')).get('company', 'WizardingCode'))" 2>/dev/null || echo "WizardingCode")
15
+ fi
16
+
17
+ if [ -f "$HOME/.arkaos/.repo-path" ]; then
18
+ REPO=$(cat "$HOME/.arkaos/.repo-path")
19
+ [ -f "$REPO/VERSION" ] && VERSION=$(cat "$REPO/VERSION" | tr -d '[:space:]')
20
+ fi
21
+
22
+ # ─── Time greeting ─────────────────────────────────────────────────────
23
+ HOUR=$(date +%H)
24
+ if [ "$HOUR" -ge 5 ] && [ "$HOUR" -lt 12 ]; then GREETING="Bom dia"
25
+ elif [ "$HOUR" -ge 12 ] && [ "$HOUR" -lt 19 ]; then GREETING="Boa tarde"
26
+ else GREETING="Boa noite"; fi
27
+
28
+ # ─── Version drift ─────────────────────────────────────────────────────
29
+ SYNC_STATE="$HOME/.arkaos/sync-state.json"
30
+ DRIFT=""
31
+
32
+ if [ -f "$SYNC_STATE" ]; then
33
+ SYNCED=$(python3 -c "import json; print(json.load(open('$SYNC_STATE'))['version'])" 2>/dev/null || echo "none")
34
+ if [ "$SYNCED" != "$VERSION" ]; then
35
+ DRIFT="\\n[arka:update-available] Core v${VERSION} != synced v${SYNCED}. Run /arka update."
36
+ fi
37
+ else
38
+ DRIFT="\\n[arka:update-available] Never synced. Run /arka update."
39
+ fi
40
+
41
+ # ─── Build message ─────────────────────────────────────────────────────
42
+ MSG="╔══════════════════════════════════════════════╗\\n"
43
+ MSG+="║ ║\\n"
44
+ MSG+="║ A R K A O S ║\\n"
45
+ MSG+="║ ║\\n"
46
+ MSG+="║ The Operating System for AI Teams ║\\n"
47
+ MSG+="║ by WizardingCode ║\\n"
48
+ MSG+="║ ║\\n"
49
+ MSG+="╚══════════════════════════════════════════════╝\\n"
50
+ MSG+="\\n"
51
+ MSG+="${GREETING}, ${NAME} (${COMPANY})\\n"
52
+ MSG+="ArkaOS v${VERSION} | 65 agents | 17 departments | 244+ skills"
53
+ MSG+="${DRIFT}"
54
+
55
+ # ─── Output as systemMessage (same protocol as claude-mem) ─────────────
56
+ python3 -c "
57
+ import json
58
+ msg = '''$(echo -e "$MSG")'''
59
+ print(json.dumps({'systemMessage': msg}))
60
+ "
@@ -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,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
  },
@@ -30,14 +30,14 @@ export async function install({ runtime, path, force }) {
30
30
  const installDir = userConfig.installDir;
31
31
 
32
32
  // ═══ Step 1: Create directories ═══
33
- step(1, 12, "Creating directories...");
33
+ step(1, 13, "Creating directories...");
34
34
  ensureDir(installDir);
35
35
  const dirs = ["config", "config/hooks", "agents", "media", "session-digests", "vault"];
36
36
  for (const d of dirs) ensureDir(join(installDir, d));
37
37
  ok(`${dirs.length + 1} directories ready`);
38
38
 
39
39
  // ═══ Step 2: Detect v1 installation ═══
40
- step(2, 12, "Checking for v1 installation...");
40
+ step(2, 13, "Checking for v1 installation...");
41
41
  const v1Paths = [
42
42
  join(homedir(), ".claude", "skills", "arka-os"),
43
43
  join(homedir(), ".claude", "skills", "arkaos"),
@@ -51,35 +51,56 @@ export async function install({ runtime, path, force }) {
51
51
  }
52
52
 
53
53
  // ═══ Step 3: Check Python ═══
54
- step(3, 12, "Checking Python 3.11+...");
54
+ step(3, 13, "Checking Python 3.11+...");
55
55
  const pythonCmd = checkPython();
56
56
  ok(`Found: ${pythonCmd}`);
57
57
 
58
58
  // ═══ Step 4: Install Python core + dependencies based on user choices ═══
59
- step(4, 12, "Installing Python dependencies (this may take a minute)...");
59
+ step(4, 13, "Installing Python dependencies (this may take a minute)...");
60
60
  installAllPythonDeps(pythonCmd, userConfig);
61
61
 
62
62
  // ═══ Step 5: Copy configuration files ═══
63
- step(5, 12, "Copying configuration files...");
63
+ step(5, 13, "Copying configuration files...");
64
64
  copyConfigFiles(installDir);
65
65
  ok("Constitution, standards, and config copied");
66
66
 
67
67
  // ═══ Step 6: Install hooks with real paths ═══
68
- step(6, 12, "Installing hooks...");
68
+ step(6, 13, "Installing hooks...");
69
69
  installHooks(installDir);
70
70
 
71
71
  // ═══ Step 7: Configure runtime ═══
72
- step(7, 12, "Configuring runtime...");
72
+ step(7, 13, "Configuring runtime...");
73
73
  const adapter = await loadAdapter(runtime);
74
74
  adapter.configureHooks(config, installDir);
75
75
  ok(`${config.name} configured`);
76
76
 
77
77
  // ═══ Step 8: Install ArkaOS skill to Claude Code ═══
78
- step(8, 12, "Installing /arka skill...");
78
+ step(8, 13, "Installing /arka skill...");
79
79
  installSkill(config, installDir);
80
80
 
81
- // ═══ Step 9: Create references and profile ═══
82
- step(9, 12, "Creating references...");
81
+ // ═══ Step 9: Install CLI wrapper and user instructions ═══
82
+ step(9, 13, "Installing CLI wrapper...");
83
+ const binDir = join(installDir, "bin");
84
+ ensureDir(binDir);
85
+ const wrapperSrc = join(ARKAOS_ROOT, "bin", "arka-claude");
86
+ if (existsSync(wrapperSrc)) {
87
+ copyFileSync(wrapperSrc, join(binDir, "arka-claude"));
88
+ try { chmodSync(join(binDir, "arka-claude"), 0o755); } catch {}
89
+ ok("arka-claude wrapper installed");
90
+ console.log(` Add to PATH: export PATH="$HOME/.arkaos/bin:$PATH"`);
91
+ console.log(` Optional alias: alias claude="arka-claude"`);
92
+ }
93
+ const claudeMdSrc = join(ARKAOS_ROOT, "config", "user-claude.md");
94
+ const userClaudeMd = join(homedir(), ".claude", "CLAUDE.md");
95
+ if (existsSync(claudeMdSrc) && !existsSync(userClaudeMd)) {
96
+ copyFileSync(claudeMdSrc, userClaudeMd);
97
+ ok("~/.claude/CLAUDE.md created (ArkaOS user instructions)");
98
+ } else if (existsSync(userClaudeMd)) {
99
+ ok("~/.claude/CLAUDE.md already exists (preserved)");
100
+ }
101
+
102
+ // ═══ Step 10: Create references and profile ═══
103
+ step(10, 13, "Creating references...");
83
104
  writeFileSync(join(installDir, ".repo-path"), ARKAOS_ROOT);
84
105
  const skillsDir = join(config.skillsDir || join(homedir(), ".claude", "skills"), "arkaos");
85
106
  ensureDir(skillsDir);
@@ -115,7 +136,7 @@ export async function install({ runtime, path, force }) {
115
136
  }
116
137
 
117
138
  // ═══ Step 10: Index knowledge base ═══
118
- step(10, 12, "Setting up knowledge base...");
139
+ step(11, 13, "Setting up knowledge base...");
119
140
  if (userConfig.installKnowledge) {
120
141
  const kbDb = join(installDir, "knowledge.db");
121
142
  // Index ArkaOS skills first
@@ -143,7 +164,7 @@ export async function install({ runtime, path, force }) {
143
164
  }
144
165
 
145
166
  // ═══ Step 11: Verify installation ═══
146
- step(11, 12, "Verifying installation...");
167
+ step(12, 13, "Verifying installation...");
147
168
  let checks = 0;
148
169
  if (existsSync(join(installDir, "config", "constitution.yaml"))) checks++;
149
170
  if (existsSync(join(installDir, "config", "hooks", "user-prompt-submit.sh"))) checks++;
@@ -158,7 +179,7 @@ export async function install({ runtime, path, force }) {
158
179
  ok(`${checks}/5 checks passed`);
159
180
 
160
181
  // ═══ Step 12: Finalize ═══
161
- step(12, 12, "Finalizing...");
182
+ step(13, 13, "Finalizing...");
162
183
  const manifest = {
163
184
  version: VERSION,
164
185
  runtime,
@@ -358,9 +379,11 @@ function installHooks(installDir) {
358
379
  ensureDir(hooksDir);
359
380
 
360
381
  const hookMap = {
361
- "user-prompt-submit-v2.sh": "user-prompt-submit.sh",
362
- "post-tool-use-v2.sh": "post-tool-use.sh",
363
- "pre-compact-v2.sh": "pre-compact.sh",
382
+ "session-start.sh": "session-start.sh",
383
+ "user-prompt-submit.sh": "user-prompt-submit.sh",
384
+ "post-tool-use.sh": "post-tool-use.sh",
385
+ "pre-compact.sh": "pre-compact.sh",
386
+ "cwd-changed.sh": "cwd-changed.sh",
364
387
  };
365
388
 
366
389
  const srcHooksDir = join(ARKAOS_ROOT, "config", "hooks");
@@ -83,9 +83,11 @@ export async function update() {
83
83
  // ── 3. Update hooks ──
84
84
  console.log(" [3/6] Updating hooks...");
85
85
  const hookMap = {
86
- "user-prompt-submit-v2.sh": "user-prompt-submit.sh",
87
- "post-tool-use-v2.sh": "post-tool-use.sh",
88
- "pre-compact-v2.sh": "pre-compact.sh",
86
+ "session-start.sh": "session-start.sh",
87
+ "user-prompt-submit.sh": "user-prompt-submit.sh",
88
+ "post-tool-use.sh": "post-tool-use.sh",
89
+ "pre-compact.sh": "pre-compact.sh",
90
+ "cwd-changed.sh": "cwd-changed.sh",
89
91
  };
90
92
  const srcHooksDir = join(ARKAOS_ROOT, "config", "hooks");
91
93
  const destHooksDir = join(installDir, "config", "hooks");
@@ -110,8 +112,26 @@ export async function update() {
110
112
  }
111
113
  console.log(" ✓ Hooks updated");
112
114
 
113
- // ── 4. Update /arka skill ──
114
- console.log(" [4/6] Updating /arka skill...");
115
+ // ── 4. Update CLI wrapper + user CLAUDE.md ──
116
+ console.log(" [4/7] Updating CLI wrapper and user instructions...");
117
+ const binDir = join(installDir, "bin");
118
+ mkdirSync(binDir, { recursive: true });
119
+ const wrapperSrc = join(ARKAOS_ROOT, "bin", "arka-claude");
120
+ if (existsSync(wrapperSrc)) {
121
+ copyFileSync(wrapperSrc, join(binDir, "arka-claude"));
122
+ try { chmodSync(join(binDir, "arka-claude"), 0o755); } catch {}
123
+ console.log(" ✓ arka-claude wrapper updated");
124
+ }
125
+ const userClaudeMd = join(homedir(), ".claude", "CLAUDE.md");
126
+ const claudeMdSrc = join(ARKAOS_ROOT, "config", "user-claude.md");
127
+ if (existsSync(claudeMdSrc)) {
128
+ mkdirSync(join(homedir(), ".claude"), { recursive: true });
129
+ copyFileSync(claudeMdSrc, userClaudeMd);
130
+ console.log(" ✓ ~/.claude/CLAUDE.md updated");
131
+ }
132
+
133
+ // ── 5. Update /arka skill ──
134
+ console.log(" [5/7] Updating /arka skill...");
115
135
  const skillSrc = join(ARKAOS_ROOT, "arka", "SKILL.md");
116
136
  const skillDest = join(homedir(), ".claude", "skills", "arka");
117
137
  mkdirSync(skillDest, { recursive: true });
@@ -122,13 +142,13 @@ export async function update() {
122
142
  console.log(" ✓ /arka skill updated");
123
143
  }
124
144
 
125
- // ── 5. Update .repo-path ──
126
- console.log(" [5/6] Updating references...");
145
+ // ── 6. Update .repo-path ──
146
+ console.log(" [6/7] Updating references...");
127
147
  writeFileSync(join(installDir, ".repo-path"), ARKAOS_ROOT);
128
148
  console.log(" ✓ Repo path updated");
129
149
 
130
- // ── 6. Update manifest ──
131
- console.log(" [6/6] Finalizing...");
150
+ // ── 7. Update manifest ──
151
+ console.log(" [7/7] Finalizing...");
132
152
  manifest.version = VERSION;
133
153
  manifest.repoRoot = ARKAOS_ROOT;
134
154
  manifest.updatedAt = new Date().toISOString();
@@ -147,7 +167,7 @@ export async function update() {
147
167
  core_updated_at: new Date().toISOString()
148
168
  };
149
169
  writeFileSync(syncStatePath, JSON.stringify(syncState, null, 2));
150
- console.log(" ✓ Sync state reset (run /arka update to sync projects)");
170
+ console.log(" ✓ Sync state reset (auto-detected on next Claude session)");
151
171
 
152
172
  console.log(`
153
173
  ╔══════════════════════════════════════════╗
@@ -160,6 +180,7 @@ export async function update() {
160
180
  Projects: ${profile.projectsDir || "not set"}
161
181
  Vault: ${profile.vaultPath || "not set"}
162
182
 
163
- Run /arka update in Claude Code to sync all projects.
183
+ Next time you open Claude Code, ArkaOS will automatically
184
+ detect the update and sync all your projects.
164
185
  `);
165
186
  }
@@ -1,20 +1,372 @@
1
1
  {
2
2
  "_meta": {
3
3
  "description": "ARKA OS — Project Ecosystem Registry",
4
- "updated": "2026-04-06"
4
+ "updated": "2026-04-07"
5
5
  },
6
6
  "ecosystems": {
7
+ "edp": {
8
+ "name": "EDP",
9
+ "description": "Enterprise integration architecture platform for EDP (Energias de Portugal). Architect solutions, AI agents, and API governance for system analysts.",
10
+ "client": "EDP - Energias de Portugal",
11
+ "type": "client",
12
+ "status": "active",
13
+ "projects": [
14
+ "gba-web",
15
+ "gba-lurch-a2a",
16
+ "gba-zenodotus"
17
+ ],
18
+ "squad": {
19
+ "roles": [
20
+ "project-manager",
21
+ "backend-developer",
22
+ "frontend-developer",
23
+ "ai-specialist",
24
+ "context-analyst",
25
+ "security-engineer",
26
+ "qa-tester"
27
+ ],
28
+ "description": "Dedicated EDP squad for integration architecture platform"
29
+ },
30
+ "tech_stack": {
31
+ "frontend": ["Laravel 12", "Inertia.js 2", "Vue 3", "TypeScript", "Tailwind CSS 4"],
32
+ "backend": ["PHP 8.4", "Python 3.12+", "FastAPI"],
33
+ "databases": ["MySQL", "PostgreSQL", "SQLite (dev)", "Redis"],
34
+ "ai": ["Azure OpenAI (GPT-5-mini-gba)", "pydantic-ai", "FastA2A"],
35
+ "infra": ["Docker", "FrankenPHP", "Laravel Octane", "Uvicorn", "Kafka", "AWS RDS", "ELK Stack"],
36
+ "auth": ["Azure AD OAuth 2.0", "JWT", "Spatie Permissions"],
37
+ "protocols": ["REST", "SOAP", "A2A (JSON-RPC 2.0)", "MCP"]
38
+ },
39
+ "created_at": "2026-03-17"
40
+ },
41
+ "rockport": {
42
+ "name": "Rockport",
43
+ "description": "E-commerce marketplace platform for Rockport premium footwear. CRM, storefront, SAP ERP integration, and logistics microservice.",
44
+ "client": "Rockport",
45
+ "type": "client",
46
+ "status": "active",
47
+ "projects": [
48
+ "crm-rockport",
49
+ "rockport-ecommerce-v2",
50
+ "sap-erp-service",
51
+ "gologistic-ms"
52
+ ],
53
+ "squad": {
54
+ "roles": [
55
+ "project-manager",
56
+ "backend-developer",
57
+ "frontend-developer",
58
+ "ecommerce-specialist",
59
+ "integrations-specialist",
60
+ "security-engineer",
61
+ "qa-tester"
62
+ ],
63
+ "description": "Dedicated Rockport squad for e-commerce platform"
64
+ },
65
+ "tech_stack": {
66
+ "frontend": ["Nuxt 4", "Vue 3", "TypeScript", "Tailwind CSS 4", "Nuxt UI 4", "Pinia 3", "Vuetify 3"],
67
+ "backend": ["PHP 8.4", "Laravel 11/12", "Laravel Modules"],
68
+ "databases": ["PostgreSQL", "Redis", "Meilisearch", "SQLite (dev)"],
69
+ "payments": ["SIBS", "Klarna", "Adyen", "MBWay"],
70
+ "integrations": ["SAP Business One", "Kafka", "GoLogistic", "DPD", "Mirakl", "Actito", "SendGrid", "Infobip"],
71
+ "infra": ["Docker", "FrankenPHP", "Octane/Roadrunner", "Horizon", "DigitalOcean Spaces", "AWS S3"],
72
+ "auth": ["Sanctum", "Spatie Permissions", "Social Login (Google/Facebook/Apple)"],
73
+ "protocols": ["REST", "Kafka", "WebSocket (Reverb)"]
74
+ },
75
+ "created_at": "2026-03-17"
76
+ },
77
+ "clubefashion": {
78
+ "name": "ClubeFashion",
79
+ "description": "E-commerce marketplace platform for ClubeFashion. Complex ecosystem with CRM migration in progress, Mirakl marketplace, Primavera ERP, and AI-ready modernization.",
80
+ "client": "ClubeFashion",
81
+ "type": "client",
82
+ "status": "active",
83
+ "projects": [
84
+ "the-burrow-hub",
85
+ "marketplace-ms",
86
+ "goblinledger",
87
+ "crm-cf-v2",
88
+ "nuxt-boilerplate",
89
+ "crm-frontend-v2"
90
+ ],
91
+ "squad": {
92
+ "roles": [
93
+ "project-manager",
94
+ "backend-developer",
95
+ "frontend-developer",
96
+ "ecommerce-specialist",
97
+ "marketplace-specialist",
98
+ "erp-specialist",
99
+ "migration-architect",
100
+ "ai-specialist",
101
+ "security-engineer",
102
+ "qa-tester",
103
+ "devops"
104
+ ],
105
+ "description": "Dedicated ClubeFashion squad — largest team due to migration complexity"
106
+ },
107
+ "tech_stack": {
108
+ "frontend": ["Nuxt 4", "Vue 3", "Vuetify 3", "Nuxt UI 4", "TypeScript", "Tailwind CSS 4", "Pinia"],
109
+ "backend": ["PHP 8.4/8.5", "Laravel 11/12", "Laravel Modules (19)"],
110
+ "databases": ["PostgreSQL", "Redis", "Meilisearch", "SQLite (dev)"],
111
+ "payments": ["SIBS", "Klarna", "Adyen", "MBWay"],
112
+ "integrations": ["Mirakl (marketplace-ms)", "Primavera ERP (goblinledger)", "Kafka (30+ topics)", "Actito", "SendGrid", "Infobip", "Skeepers", "DPD", "Google Merchant"],
113
+ "infra": ["Docker", "FrankenPHP", "Octane/Roadrunner", "Horizon", "AWS S3", "DigitalOcean Spaces"],
114
+ "auth": ["Sanctum", "Spatie Permissions", "Social Login"],
115
+ "protocols": ["REST", "Kafka", "WebSocket (Reverb)"],
116
+ "project_management": ["ClickUp (Space: 90153217724)"]
117
+ },
118
+ "migration": {
119
+ "from": "the-burrow-hub (Laravel 11, 19 modules, 431 migrations, 163 models)",
120
+ "to": "crm-cf-v2 (Laravel 12, AI-ready, strict types) + crm-frontend-v2 (Vue 3 SPA)",
121
+ "status": "paused — foundation laid, 0% content migration",
122
+ "priority": "planning phase"
123
+ },
124
+ "created_at": "2026-03-17"
125
+ },
126
+ "fovory": {
127
+ "name": "Fovory",
128
+ "description": "Supplier-to-Shopify integration engine with custom Laravel codebase (fovory-supplier-sync) AND Shopify store operations/marketing. Dual nature: dev squad for code work, ops/marketing squad for store management.",
129
+ "client": "Fovory (internal business)",
130
+ "type": "internal",
131
+ "status": "active",
132
+ "projects": [
133
+ "fovory-supplier-sync"
134
+ ],
135
+ "platform": "Shopify + Custom Laravel App",
136
+ "squad": {
137
+ "roles": [
138
+ "tech-lead",
139
+ "backend-developer",
140
+ "frontend-developer",
141
+ "ai-specialist",
142
+ "security-engineer",
143
+ "qa-tester",
144
+ "operations-manager",
145
+ "ecommerce-manager",
146
+ "product-manager",
147
+ "marketing-strategist",
148
+ "content-creator",
149
+ "ads-specialist",
150
+ "email-marketing",
151
+ "seo-specialist",
152
+ "analytics-specialist",
153
+ "pricing-strategist"
154
+ ],
155
+ "description": "Dual squad: dev team (Laravel/Vue) + operations/marketing team (Shopify store)"
156
+ },
157
+ "tech_stack": {
158
+ "frontend": ["Vue 3.5", "Inertia.js 3", "TypeScript", "Tailwind CSS 4", "Nuxt UI 4", "TipTap 3", "TanStack Table", "Unovis"],
159
+ "backend": ["PHP 8.4", "Laravel 13", "Laravel Horizon", "Laravel Reverb", "Laravel Fortify", "Laravel Pennant"],
160
+ "databases": ["PostgreSQL", "Redis", "SQLite (dev)"],
161
+ "ai": ["Laravel AI SDK", "Claude/Anthropic", "OpenRouter", "OpenAI"],
162
+ "import": ["Maatwebsite Excel", "WebSocket progress"],
163
+ "testing": ["Pest 5", "Playwright", "Larastan", "Rector", "Pint"],
164
+ "build": ["Bun", "Vite"],
165
+ "shopify": ["Shopify GraphQL Admin API", "Shopify MCP"]
166
+ },
167
+ "codebase_stats": {
168
+ "models": 43,
169
+ "actions": 75,
170
+ "controllers": 42,
171
+ "vue_pages": 44,
172
+ "migrations": 72,
173
+ "tests": 943,
174
+ "assertions": 2997,
175
+ "updated": "2026-04-07"
176
+ },
177
+ "capabilities": {
178
+ "dev": ["Supplier integration (API + CSV)", "Product CRUD with variants/offers", "AI system (providers/agents/personas/triggers)", "Bulk import (Excel + WebSocket)", "E-commerce settings", "Multi-locale translations"],
179
+ "store": ["Shopify MCP", "Product management", "CSV bulk operations", "Pricing strategy (min 35% margin)", "Stock management (15min sync, 5% buffer)", "Translations"],
180
+ "marketing": ["Social media (Instagram, LinkedIn, TikTok, X)", "Email campaigns", "Google Ads", "Meta Ads", "Content calendars", "Reels/Shorts scripts"],
181
+ "analytics": ["Google Analytics 4", "Google Ads", "Shopify Analytics", "Meta Pixel"],
182
+ "knowledge": ["KB personas for content voice", "Market research", "Competitor analysis", "Trend analysis"],
183
+ "automation": ["Bulk product updates", "Price optimization", "Translation automation", "Ad creative generation"]
184
+ },
185
+ "created_at": "2026-03-17",
186
+ "updated_at": "2026-04-07"
187
+ },
7
188
  "wizardingcode": {
189
+ "name": "WizardingCode Internal",
190
+ "description": "Internal growth engine. Revenue target: 1M EUR by Dec 2026. Micro-SaaS, AI tools, content creation, financial management, trend scouting.",
191
+ "client": "WizardingCode (internal)",
192
+ "type": "internal",
193
+ "status": "active",
194
+ "projects": [
195
+ "lora-tester",
196
+ "purz-comfyui-workflows"
197
+ ],
198
+ "squad": {
199
+ "roles": [
200
+ "ceo-copilot",
201
+ "creative-director",
202
+ "marketing-lead",
203
+ "data-analyst",
204
+ "market-scout",
205
+ "content-creator",
206
+ "financial-controller",
207
+ "full-stack-builder",
208
+ "growth-hacker",
209
+ "community-manager"
210
+ ],
211
+ "description": "Growth team — strategy, content, finance, and product development"
212
+ },
213
+ "revenue_target": {
214
+ "amount": 1000000,
215
+ "currency": "EUR",
216
+ "deadline": "2026-12-31",
217
+ "monthly_target": 83333
218
+ },
219
+ "capabilities": {
220
+ "strategy": ["Idea evaluation", "OKRs", "Roadmap", "Market analysis"],
221
+ "product": ["Micro-SaaS", "AI tools", "ARKA OS Pro", "Landing pages"],
222
+ "content": ["AI articles", "Entrepreneurship", "YouTube", "LinkedIn", "Newsletter"],
223
+ "finance": ["Gmail accounting", "Revenue tracking", "Investment plans", "Invoicing"],
224
+ "marketing": ["Social media", "Email funnels", "Google Ads", "Growth hacking"]
225
+ },
226
+ "integrations": ["Gmail (accounting)", "Google Calendar", "ClickUp", "InvoiceExpress"],
227
+ "created_at": "2026-03-17"
228
+ },
229
+ "rothbard100": {
230
+ "name": "Rothbard 100",
231
+ "description": "Libertarian event platform celebrating the 100th anniversary of Murray Rothbard. Landing page, future registration app, and event CRM. Organized by Cataláxia EDITORA. Event: Porto, 27 Jun 2026.",
232
+ "client": "Cataláxia EDITORA",
233
+ "type": "internal",
234
+ "status": "active",
235
+ "projects": [
236
+ "rothbard100-landing"
237
+ ],
238
+ "squad": {
239
+ "roles": [
240
+ "project-manager",
241
+ "frontend-developer",
242
+ "content-creator",
243
+ "seo-marketing",
244
+ "security-engineer",
245
+ "qa-tester",
246
+ "devops"
247
+ ],
248
+ "description": "Dedicated Rothbard 100 squad for event platform — landing page focus"
249
+ },
250
+ "tech_stack": {
251
+ "frontend": ["Nuxt 4.4.2", "Vue 3", "TypeScript", "Tailwind CSS 4", "Nuxt UI v4.5.1"],
252
+ "i18n": ["@nuxtjs/i18n (pt, en, fr, es, de)"],
253
+ "content": ["@nuxt/content v3"],
254
+ "images": ["@nuxt/image v2"],
255
+ "icons": ["Iconify (lucide + simple-icons)"],
256
+ "infra": ["Cloudflare Pages", "pnpm"],
257
+ "build": ["SSG (Nitro prerender)"]
258
+ },
259
+ "brand": {
260
+ "primary_color": "#FFC939",
261
+ "secondary_color": "#000000",
262
+ "theme": "dark-premium-revolutionary",
263
+ "style": "Silicon Valley event level",
264
+ "font": "Inter (400-900)",
265
+ "mode": "light-only"
266
+ },
267
+ "created_at": "2026-03-26",
268
+ "updated_at": "2026-04-07"
269
+ },
270
+ "cascais24horas": {
271
+ "name": "Cascais 24 Horas",
272
+ "description": "Local news and events portal for Cascais, Portugal. Security-critical rebuild after WordPress hack. CMS backend with admin panel and public-facing Nuxt frontend.",
273
+ "client": "WizardingCode (internal project)",
274
+ "type": "internal",
275
+ "status": "active",
276
+ "projects": [
277
+ "cascais24horas-cms",
278
+ "cascais24horas-web"
279
+ ],
280
+ "squad": {
281
+ "roles": [
282
+ "project-manager",
283
+ "backend-developer",
284
+ "frontend-developer-cms",
285
+ "frontend-developer-web",
286
+ "content-creator",
287
+ "seo-marketing",
288
+ "security-engineer",
289
+ "qa-tester"
290
+ ],
291
+ "description": "Dedicated Cascais24Horas squad for news portal rebuild"
292
+ },
293
+ "tech_stack": {
294
+ "frontend_cms": ["Vue 3", "Inertia.js 3", "TypeScript", "Tailwind CSS 4", "TipTap"],
295
+ "frontend_web": ["Nuxt 4", "Nuxt UI 4", "Vue 3", "TypeScript", "Tailwind CSS 4"],
296
+ "backend": ["PHP 8.4", "Laravel 12"],
297
+ "databases": ["SQLite (dev)", "PostgreSQL (prod)", "Redis"],
298
+ "search": ["Laravel Scout"],
299
+ "media": ["Spatie MediaLibrary"],
300
+ "auth": ["Sanctum", "Spatie Permission"],
301
+ "seo": ["Spatie Sitemap", "Nuxt SEO", "Google News"],
302
+ "content": ["@nuxt/content v3", "TipTap", "HTML Purifier"]
303
+ },
304
+ "security_context": "Rebuilt after WordPress hack — security is first-class concern",
305
+ "created_at": "2026-03-31"
306
+ },
307
+ "marlon": {
308
+ "name": "Marlon",
309
+ "description": "Services and consulting client of WizardingCode. Web application ecosystem with Nuxt/Vue frontend. Dedicated squad and orchestrator.",
310
+ "client": "Marlon",
311
+ "type": "client",
312
+ "status": "active",
313
+ "projects": [],
314
+ "squad": {
315
+ "roles": [
316
+ "project-manager",
317
+ "backend-developer",
318
+ "frontend-developer",
319
+ "security-engineer",
320
+ "qa-tester",
321
+ "devops"
322
+ ],
323
+ "description": "Dedicated Marlon squad for services/consulting web platform"
324
+ },
325
+ "tech_stack": {
326
+ "frontend": ["Nuxt 4", "Vue 3", "TypeScript", "Tailwind CSS 4", "Nuxt UI 4"],
327
+ "backend": ["PHP 8.4", "Laravel 12"],
328
+ "databases": ["PostgreSQL", "SQLite (dev)", "Redis"],
329
+ "auth": ["Sanctum", "Spatie Permissions"],
330
+ "infra": ["Docker", "pnpm", "Vercel/Netlify"]
331
+ },
332
+ "created_at": "2026-04-06"
333
+ },
334
+ "zugatv": {
335
+ "name": "ZugaTV",
336
+ "description": "Portuguese content/media partner. Viral interactive content and audience growth funnels. First project: Raio-X Ideologico — political ideology quiz for follower growth.",
337
+ "client": "ZugaTV",
338
+ "type": "partner",
339
+ "status": "active",
8
340
  "projects": [
9
- {
10
- "name": "arka-os",
11
- "role": "product",
12
- "stack": "Python + Node.js + React",
13
- "path": "/Users/andreagroferreira/AIProjects/arka-os",
14
- "skill": "/platform-arka",
15
- "description": "ArkaOS — The Operating System for AI Agent Teams"
16
- }
17
- ]
341
+ "raiox-ideologico"
342
+ ],
343
+ "squad": {
344
+ "roles": [
345
+ "project-manager",
346
+ "frontend-developer",
347
+ "content-creator",
348
+ "seo-marketing",
349
+ "security-engineer",
350
+ "qa-tester"
351
+ ],
352
+ "description": "Dedicated ZugaTV squad for viral content platforms"
353
+ },
354
+ "tech_stack": {
355
+ "frontend": ["Nuxt 4", "Vue 3", "TypeScript", "Tailwind CSS 4", "Nuxt UI 4", "Chart.js", "vue-chartjs"],
356
+ "content": ["@nuxt/content v3"],
357
+ "composables": ["@vueuse/nuxt"],
358
+ "seo": ["@nuxtjs/seo", "@nuxtjs/robots", "nuxt-og-image"],
359
+ "analytics": ["nuxt-plausible"],
360
+ "fonts": ["@nuxt/fonts (Inter)"],
361
+ "testing": ["Vitest", "@vue/test-utils", "happy-dom"],
362
+ "build": ["pnpm", "SSR/SPA hybrid", "Vercel or Cloudflare Pages"]
363
+ },
364
+ "constraints": {
365
+ "architecture": "100% client-side scoring — NO backend, NO database, NO auth",
366
+ "privacy": "RGPD by design — no personal data stored server-side",
367
+ "language": "Portuguese (pt-PT) only — no i18n"
368
+ },
369
+ "created_at": "2026-03-28"
18
370
  }
19
371
  }
20
372
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "The Operating System for AI Agent Teams",
5
5
  "type": "module",
6
6
  "bin": {
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arkaos-core"
3
- version = "2.7.0"
3
+ version = "2.9.0"
4
4
  description = "Core engine for ArkaOS — The Operating System for AI Agent Teams"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}