arkaos 2.7.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.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.7.0
1
+ 2.8.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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "2.7.0",
3
+ "version": "2.8.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.8.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"}