arkaos 4.3.6 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/VERSION +1 -1
  2. package/bin/arka-py +22 -7
  3. package/config/hooks/_lib/arka_python.ps1 +31 -0
  4. package/config/hooks/_lib/arka_python.sh +38 -0
  5. package/config/hooks/post-tool-use.ps1 +8 -0
  6. package/config/hooks/post-tool-use.sh +11 -5
  7. package/config/hooks/pre-tool-use.ps1 +11 -6
  8. package/config/hooks/pre-tool-use.sh +11 -6
  9. package/config/hooks/session-start.ps1 +10 -0
  10. package/config/hooks/session-start.sh +5 -0
  11. package/config/hooks/stop.ps1 +9 -1
  12. package/config/hooks/stop.sh +11 -5
  13. package/config/hooks/user-prompt-submit.ps1 +18 -0
  14. package/config/hooks/user-prompt-submit.sh +11 -5
  15. package/config/mcp-policy.yaml +8 -8
  16. package/core/agents/__pycache__/__init__.cpython-312.pyc +0 -0
  17. package/core/agents/__pycache__/loader.cpython-312.pyc +0 -0
  18. package/core/agents/__pycache__/registry_gen.cpython-313.pyc +0 -0
  19. package/core/agents/__pycache__/schema.cpython-312.pyc +0 -0
  20. package/core/agents/registry_gen.py +3 -2
  21. package/core/cognition/scheduler/__pycache__/daemon.cpython-313.pyc +0 -0
  22. package/core/cognition/scheduler/daemon.py +7 -3
  23. package/core/forge/__pycache__/orchestrator.cpython-313.pyc +0 -0
  24. package/core/forge/orchestrator.py +2 -1
  25. package/core/hooks/__pycache__/_shared.cpython-313.pyc +0 -0
  26. package/core/hooks/__pycache__/_shared.cpython-314.pyc +0 -0
  27. package/core/hooks/__pycache__/stop.cpython-313.pyc +0 -0
  28. package/core/hooks/__pycache__/stop.cpython-314.pyc +0 -0
  29. package/core/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  30. package/core/hooks/_shared.py +29 -9
  31. package/core/hooks/stop.py +4 -3
  32. package/core/hooks/user_prompt_submit.py +5 -4
  33. package/core/knowledge/__pycache__/indexer.cpython-313.pyc +0 -0
  34. package/core/knowledge/__pycache__/vector_store.cpython-313.pyc +0 -0
  35. package/core/knowledge/indexer.py +1 -1
  36. package/core/knowledge/vector_store.py +10 -3
  37. package/core/runtime/__pycache__/model_routing_check.cpython-313.pyc +0 -0
  38. package/core/runtime/__pycache__/model_routing_context.cpython-313.pyc +0 -0
  39. package/core/runtime/__pycache__/native_usage.cpython-313.pyc +0 -0
  40. package/core/runtime/__pycache__/native_usage.cpython-314.pyc +0 -0
  41. package/core/runtime/gateway/__pycache__/__init__.cpython-313.pyc +0 -0
  42. package/core/runtime/gateway/__pycache__/__main__.cpython-313.pyc +0 -0
  43. package/core/runtime/gateway/__pycache__/litellm_config.cpython-313.pyc +0 -0
  44. package/core/runtime/native_usage.py +2 -1
  45. package/core/shared/__pycache__/temp_paths.cpython-313.pyc +0 -0
  46. package/core/shared/__pycache__/temp_paths.cpython-314.pyc +0 -0
  47. package/core/shared/temp_paths.py +40 -0
  48. package/core/synapse/__pycache__/kb_cache.cpython-313.pyc +0 -0
  49. package/core/synapse/__pycache__/kb_cache.cpython-314.pyc +0 -0
  50. package/core/synapse/kb_cache.py +3 -2
  51. package/core/sync/__pycache__/agent_provisioner.cpython-313.pyc +0 -0
  52. package/core/sync/__pycache__/ai_mcp_decider.cpython-313.pyc +0 -0
  53. package/core/sync/__pycache__/content_syncer.cpython-313.pyc +0 -0
  54. package/core/sync/__pycache__/descriptor_syncer.cpython-313.pyc +0 -0
  55. package/core/sync/__pycache__/discovery.cpython-313.pyc +0 -0
  56. package/core/sync/__pycache__/engine.cpython-313.pyc +0 -0
  57. package/core/sync/__pycache__/manifest.cpython-313.pyc +0 -0
  58. package/core/sync/__pycache__/mcp_optimizer.cpython-313.pyc +0 -0
  59. package/core/sync/__pycache__/mcp_syncer.cpython-313.pyc +0 -0
  60. package/core/sync/__pycache__/policy_loader.cpython-313.pyc +0 -0
  61. package/core/sync/__pycache__/reporter.cpython-313.pyc +0 -0
  62. package/core/sync/__pycache__/settings_syncer.cpython-313.pyc +0 -0
  63. package/core/sync/agent_provisioner.py +5 -5
  64. package/core/sync/ai_mcp_decider.py +2 -2
  65. package/core/sync/content_syncer.py +14 -14
  66. package/core/sync/descriptor_syncer.py +2 -2
  67. package/core/sync/discovery.py +4 -4
  68. package/core/sync/engine.py +4 -4
  69. package/core/sync/manifest.py +1 -1
  70. package/core/sync/mcp_optimizer.py +5 -5
  71. package/core/sync/mcp_syncer.py +7 -3
  72. package/core/sync/policy_loader.py +1 -1
  73. package/core/sync/reporter.py +1 -1
  74. package/core/sync/settings_syncer.py +2 -2
  75. package/core/terminal/__pycache__/session.cpython-313.pyc +0 -0
  76. package/core/terminal/__pycache__/session_windows.cpython-313.pyc +0 -0
  77. package/core/terminal/session.py +66 -11
  78. package/core/terminal/session_windows.py +211 -0
  79. package/core/workflow/__pycache__/flow_authorization.cpython-313.pyc +0 -0
  80. package/core/workflow/__pycache__/flow_authorization.cpython-314.pyc +0 -0
  81. package/core/workflow/__pycache__/flow_enforcer.cpython-313.pyc +0 -0
  82. package/core/workflow/__pycache__/flow_enforcer.cpython-314.pyc +0 -0
  83. package/core/workflow/__pycache__/marker_cache.cpython-313.pyc +0 -0
  84. package/core/workflow/__pycache__/marker_cache.cpython-314.pyc +0 -0
  85. package/core/workflow/__pycache__/research_gate.cpython-313.pyc +0 -0
  86. package/core/workflow/__pycache__/research_gate.cpython-314.pyc +0 -0
  87. package/core/workflow/flow_authorization.py +2 -1
  88. package/core/workflow/flow_enforcer.py +2 -1
  89. package/core/workflow/marker_cache.py +2 -1
  90. package/core/workflow/research_gate.py +2 -1
  91. package/dashboard/app/pages/index.vue +6 -1
  92. package/departments/dev/skills/mcp/SKILL.md +3 -1
  93. package/departments/ops/skills/update/references/sync-engine.md +2 -1
  94. package/departments/quality/agents/copy-director.yaml +2 -0
  95. package/departments/quality/agents/tech-director.yaml +2 -0
  96. package/installer/cli.js +5 -4
  97. package/installer/core-snapshot.js +53 -0
  98. package/installer/doctor.js +8 -3
  99. package/installer/index.js +29 -6
  100. package/installer/migrate.js +7 -4
  101. package/installer/update.js +13 -0
  102. package/knowledge/agents-registry-v2.json +487 -120
  103. package/package.json +1 -1
  104. package/pyproject.toml +2 -1
  105. package/scripts/__pycache__/dashboard-api.cpython-313.pyc +0 -0
  106. package/scripts/__pycache__/synapse-bridge.cpython-313.pyc +0 -0
  107. package/scripts/dashboard-api.py +69 -33
  108. package/scripts/knowledge-index.py +35 -2
  109. package/scripts/start-dashboard.ps1 +34 -14
  110. package/scripts/synapse-bridge.py +3 -1
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.3.6
1
+ 4.5.0
package/bin/arka-py CHANGED
@@ -30,14 +30,29 @@ done
30
30
  : "${ARKA_PY:=python3}"
31
31
 
32
32
  # ─── Make `-m core.*` resolvable regardless of cwd ────────────────────────
33
- # ARKAOS_ROOT (env) wins; else the installed repo pointer; else the repo this
34
- # shim lives in (dev checkout: bin/ -> repo root).
33
+ # ARKAOS_ROOT (env) wins unconditionally an explicit operator override is
34
+ # honored even if wrong, so misconfiguration stays loud and debuggable.
35
+ # The guessed candidates are validated before winning: `.repo-path` points
36
+ # at an npx cache that `npm cache clean` can purge, and ~/.arkaos/core is
37
+ # the cognitive scheduler's minimal copy (no core/sync). A candidate only
38
+ # counts when it holds the full package (core/sync/__init__.py marker).
39
+ # Chain: .repo-path → dev checkout (bin/ -> repo root) → ~/.arkaos/lib
40
+ # (stable snapshot written by the installer, survives cache purges).
35
41
  _root="${ARKAOS_ROOT:-}"
36
- if [ -z "$_root" ] && [ -f "$HOME/.arkaos/.repo-path" ]; then
37
- _root="$(cat "$HOME/.arkaos/.repo-path" 2>/dev/null || true)"
38
- fi
39
- if [ -z "$_root" ] && [ -f "$_self/../core/hooks/__init__.py" ]; then
40
- _root="$(cd "$_self/.." && pwd)"
42
+ if [ -z "$_root" ]; then
43
+ _repo_ptr=""
44
+ if [ -f "$HOME/.arkaos/.repo-path" ]; then
45
+ _repo_ptr="$(cat "$HOME/.arkaos/.repo-path" 2>/dev/null || true)"
46
+ fi
47
+ for _cand in \
48
+ "$_repo_ptr" \
49
+ "$_self/.." \
50
+ "$HOME/.arkaos/lib"; do
51
+ if [ -n "$_cand" ] && [ -f "$_cand/core/sync/__init__.py" ]; then
52
+ _root="$(cd "$_cand" && pwd)"
53
+ break
54
+ fi
55
+ done
41
56
  fi
42
57
  if [ -n "$_root" ] && [ -d "$_root" ]; then
43
58
  export PYTHONPATH="${_root}${PYTHONPATH:+:$PYTHONPATH}"
@@ -40,4 +40,35 @@ function Resolve-ArkaPython {
40
40
  return "python"
41
41
  }
42
42
 
43
+ # Windows mirror of arka_resolve_root() in arka_python.sh: env override wins
44
+ # unconditionally; guessed candidates must contain core/sync/__init__.py
45
+ # (the full-package marker — `.repo-path` points at an npx cache that
46
+ # `npm cache clean` can purge; ~/.arkaos/lib is the installer's snapshot).
47
+ function Resolve-ArkaRoot {
48
+ if (-not [string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
49
+ return $env:ARKAOS_ROOT
50
+ }
51
+ $base = if ($env:USERPROFILE) { $env:USERPROFILE } elseif ($HOME) { $HOME } else { "" }
52
+ $repo = ""
53
+ $repoPathFile = Join-Path $base ".arkaos\.repo-path"
54
+ if ($base -and (Test-Path -LiteralPath $repoPathFile)) {
55
+ $repo = (Get-Content $repoPathFile -Raw).Trim()
56
+ }
57
+ if ($repo -and (Test-Path -LiteralPath (Join-Path $repo "core\sync\__init__.py"))) {
58
+ return $repo
59
+ }
60
+ $lib = Join-Path $base ".arkaos\lib"
61
+ if ($base -and (Test-Path -LiteralPath (Join-Path $lib "core\sync\__init__.py"))) {
62
+ return $lib
63
+ }
64
+ if ($repo -and (Test-Path -LiteralPath $repo)) {
65
+ return $repo
66
+ }
67
+ if ($base -and (Test-Path -LiteralPath (Join-Path $base ".arkaos"))) {
68
+ return (Join-Path $base ".arkaos")
69
+ }
70
+ if ($env:ARKA_OS) { return $env:ARKA_OS }
71
+ return (Join-Path $base ".claude\skills\arkaos")
72
+ }
73
+
43
74
  $env:ARKA_PY = Resolve-ArkaPython
@@ -61,3 +61,41 @@ arka_resolve_python() {
61
61
  # keep the export unconditional.
62
62
  ARKA_PY="$(arka_resolve_python)" || true
63
63
  export ARKA_PY
64
+
65
+ # Contract of arka_resolve_root():
66
+ # Echoes the ArkaOS root for `-m core.*` execution. env ARKAOS_ROOT wins
67
+ # unconditionally (explicit operator override stays loud and debuggable).
68
+ # Guessed candidates are validated on core/sync/__init__.py — the marker
69
+ # that distinguishes the full package from the cognitive scheduler's
70
+ # partial ~/.arkaos/core copy — because `.repo-path` points at an npx
71
+ # cache that `npm cache clean` can purge at any time. Chain:
72
+ # .repo-path (validated) → ~/.arkaos/lib snapshot (validated, written by
73
+ # the installer) → .repo-path even without core (legacy VERSION readers)
74
+ # → ~/.arkaos → ARKA_OS env → ~/.claude/skills/arkaos.
75
+ arka_resolve_root() {
76
+ if [ -n "${ARKAOS_ROOT:-}" ]; then
77
+ printf '%s\n' "$ARKAOS_ROOT"
78
+ return 0
79
+ fi
80
+ local repo=""
81
+ if [ -f "$HOME/.arkaos/.repo-path" ]; then
82
+ repo="$(cat "$HOME/.arkaos/.repo-path" 2>/dev/null || true)"
83
+ fi
84
+ if [ -n "$repo" ] && [ -f "$repo/core/sync/__init__.py" ]; then
85
+ printf '%s\n' "$repo"
86
+ return 0
87
+ fi
88
+ if [ -f "$HOME/.arkaos/lib/core/sync/__init__.py" ]; then
89
+ printf '%s\n' "$HOME/.arkaos/lib"
90
+ return 0
91
+ fi
92
+ if [ -n "$repo" ] && [ -d "$repo" ]; then
93
+ printf '%s\n' "$repo"
94
+ return 0
95
+ fi
96
+ if [ -d "$HOME/.arkaos" ]; then
97
+ printf '%s\n' "$HOME/.arkaos"
98
+ return 0
99
+ fi
100
+ printf '%s\n' "${ARKA_OS:-$HOME/.claude/skills/arkaos}"
101
+ }
@@ -150,6 +150,14 @@ if ($shouldProcessGotchas -and $null -ne $payload) {
150
150
  $arkaosRootPtu = (Get-Content -Raw -LiteralPath $repoPathFile -Encoding UTF8).Trim()
151
151
  } catch { }
152
152
  }
153
+ # .repo-path may point at a purged npx cache — fall through
154
+ # to the ~/.arkaos/lib snapshot when core is missing.
155
+ if (-not ($arkaosRootPtu -and (Test-Path -LiteralPath (Join-Path $arkaosRootPtu 'core\sync\__init__.py')))) {
156
+ $libPtu = Join-Path $env:USERPROFILE '.arkaos\lib'
157
+ if (Test-Path -LiteralPath (Join-Path $libPtu 'core\sync\__init__.py')) {
158
+ $arkaosRootPtu = $libPtu
159
+ }
160
+ }
153
161
  }
154
162
  if (-not $arkaosRootPtu) {
155
163
  $arkaosRootPtu = Join-Path $env:USERPROFILE '.arkaos'
@@ -20,7 +20,17 @@
20
20
  # - Hook metrics. Output: JSON to stdout. Timeout: 5s.
21
21
  # ============================================================================
22
22
 
23
- if [ -z "${ARKAOS_ROOT:-}" ]; then
23
+ # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
24
+ _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
25
+ if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
26
+
27
+ # ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
28
+ # .repo-path can point at a purged npx cache; the shared resolver falls
29
+ # through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
30
+ if command -v arka_resolve_root >/dev/null 2>&1; then
31
+ ARKAOS_ROOT="$(arka_resolve_root)"
32
+ elif [ -z "${ARKAOS_ROOT:-}" ]; then
33
+ # Legacy chain (pre-snapshot _lib deployment)
24
34
  if [ -f "$HOME/.arkaos/.repo-path" ]; then
25
35
  ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
26
36
  elif [ -d "$HOME/.arkaos" ]; then
@@ -31,10 +41,6 @@ if [ -z "${ARKAOS_ROOT:-}" ]; then
31
41
  fi
32
42
  export ARKAOS_ROOT
33
43
 
34
- # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
35
- _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
36
- if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
37
-
38
44
  if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
39
45
  echo '{}'
40
46
  exit 0
@@ -27,8 +27,17 @@ $transcriptPath = [string]$inp.transcript_path
27
27
  $sessionId = [string]$inp.session_id
28
28
  $cwd = [string]$inp.cwd
29
29
 
30
- # --- Resolve ARKAOS_ROOT ---
31
- if ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
30
+ # Shared resolver (venv-first, yaml-verified). Mirrors _lib/arka_python.sh.
31
+ $arkaLib = Join-Path $PSScriptRoot "_lib\arka_python.ps1"
32
+ if (Test-Path -LiteralPath $arkaLib) { . $arkaLib }
33
+
34
+ # --- Resolve ARKAOS_ROOT (validated — see Resolve-ArkaRoot in _lib) ---
35
+ # .repo-path can point at a purged npx cache; the shared resolver falls
36
+ # through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
37
+ if (Get-Command Resolve-ArkaRoot -ErrorAction SilentlyContinue) {
38
+ $env:ARKAOS_ROOT = Resolve-ArkaRoot
39
+ } elseif ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
40
+ # Legacy chain (pre-snapshot _lib deployment)
32
41
  $repoPathFile = Join-Path $HOME ".arkaos/.repo-path"
33
42
  if (Test-Path $repoPathFile) {
34
43
  $env:ARKAOS_ROOT = (Get-Content $repoPathFile -Raw).Trim()
@@ -38,10 +47,6 @@ if ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
38
47
  $env:ARKAOS_ROOT = if ($env:ARKA_OS) { $env:ARKA_OS } else { Join-Path $HOME ".claude/skills/arkaos" }
39
48
  }
40
49
  }
41
-
42
- # Shared resolver (venv-first, yaml-verified). Mirrors _lib/arka_python.sh.
43
- $arkaLib = Join-Path $PSScriptRoot "_lib\arka_python.ps1"
44
- if (Test-Path -LiteralPath $arkaLib) { . $arkaLib }
45
50
  $pythonExe = $env:ARKA_PY
46
51
  if (-not $pythonExe) { exit 0 }
47
52
 
@@ -22,8 +22,17 @@
22
22
  # flags are honored inside the python modules. Timeout: 10s.
23
23
  # ============================================================================
24
24
 
25
- # ─── Resolve ARKAOS_ROOT (env → .repo-path → ~/.arkaos → portable) ──────
26
- if [ -z "${ARKAOS_ROOT:-}" ]; then
25
+ # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
26
+ _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
27
+ if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
28
+
29
+ # ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
30
+ # .repo-path can point at a purged npx cache; the shared resolver falls
31
+ # through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
32
+ if command -v arka_resolve_root >/dev/null 2>&1; then
33
+ ARKAOS_ROOT="$(arka_resolve_root)"
34
+ elif [ -z "${ARKAOS_ROOT:-}" ]; then
35
+ # Legacy chain (pre-snapshot _lib deployment)
27
36
  if [ -f "$HOME/.arkaos/.repo-path" ]; then
28
37
  ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
29
38
  elif [ -d "$HOME/.arkaos" ]; then
@@ -34,10 +43,6 @@ if [ -z "${ARKAOS_ROOT:-}" ]; then
34
43
  fi
35
44
  export ARKAOS_ROOT
36
45
 
37
- # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
38
- _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
39
- if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
40
-
41
46
  # ─── Degrade gracefully (fail open, same as before) ─────────────────────
42
47
  if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
43
48
  exit 0
@@ -46,6 +46,16 @@ if (Test-Path -LiteralPath $repoPathFile) {
46
46
  }
47
47
  } catch { }
48
48
  }
49
+ # .repo-path may point at a purged npx cache — the installer's snapshot
50
+ # keeps the drift banner alive ('2.x' is the untouched default above).
51
+ if ($version -eq '2.x') {
52
+ $libVersionFile = Join-Path $arkaosHome 'lib\VERSION'
53
+ if (Test-Path -LiteralPath $libVersionFile) {
54
+ try {
55
+ $version = (Get-Content -Raw -LiteralPath $libVersionFile -Encoding UTF8).Trim()
56
+ } catch { }
57
+ }
58
+ }
49
59
 
50
60
  # ─── Time greeting ─────────────────────────────────────────────────────
51
61
  $hour = [int](Get-Date -Format 'HH')
@@ -22,6 +22,11 @@ if [ -f "$HOME/.arkaos/.repo-path" ]; then
22
22
  REPO=$(cat "$HOME/.arkaos/.repo-path")
23
23
  [ -f "$REPO/VERSION" ] && VERSION=$(cat "$REPO/VERSION" | tr -d '[:space:]')
24
24
  fi
25
+ # .repo-path may point at a purged npx cache — the installer's snapshot
26
+ # keeps the drift banner alive ("2.x" is the untouched default above).
27
+ if [ "$VERSION" = "2.x" ] && [ -f "$HOME/.arkaos/lib/VERSION" ]; then
28
+ VERSION=$(tr -d '[:space:]' < "$HOME/.arkaos/lib/VERSION")
29
+ fi
25
30
 
26
31
  # ─── Static greeting (cache-friendly) ──────────────────────────────────
27
32
  # Time-of-day branching removed: it invalidated prompt cache 3x/day without
@@ -29,7 +29,15 @@ if ([string]::IsNullOrWhiteSpace($sessionId) -or -not (Test-Path $wfMarker)) {
29
29
  exit 0
30
30
  }
31
31
 
32
- if ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
32
+ # Resolve ARKAOS_ROOT via the validated shared resolver: .repo-path can
33
+ # point at a purged npx cache; fall through to the ~/.arkaos/lib snapshot
34
+ # instead of exporting a dead root.
35
+ $arkaLibEarly = Join-Path $PSScriptRoot "_lib\arka_python.ps1"
36
+ if (Test-Path -LiteralPath $arkaLibEarly) { . $arkaLibEarly }
37
+ if (Get-Command Resolve-ArkaRoot -ErrorAction SilentlyContinue) {
38
+ $env:ARKAOS_ROOT = Resolve-ArkaRoot
39
+ } elseif ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
40
+ # Legacy chain (pre-snapshot _lib deployment)
33
41
  $repoPathFile = Join-Path $HOME ".arkaos/.repo-path"
34
42
  if (Test-Path $repoPathFile) {
35
43
  $env:ARKAOS_ROOT = (Get-Content $repoPathFile -Raw).Trim()
@@ -22,7 +22,17 @@
22
22
  # Timeout: 5s | Always exit 0.
23
23
  # ============================================================================
24
24
 
25
- if [ -z "${ARKAOS_ROOT:-}" ]; then
25
+ # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
26
+ _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
27
+ if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
28
+
29
+ # ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
30
+ # .repo-path can point at a purged npx cache; the shared resolver falls
31
+ # through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
32
+ if command -v arka_resolve_root >/dev/null 2>&1; then
33
+ ARKAOS_ROOT="$(arka_resolve_root)"
34
+ elif [ -z "${ARKAOS_ROOT:-}" ]; then
35
+ # Legacy chain (pre-snapshot _lib deployment)
26
36
  if [ -f "$HOME/.arkaos/.repo-path" ]; then
27
37
  ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
28
38
  elif [ -d "$HOME/.arkaos" ]; then
@@ -33,10 +43,6 @@ if [ -z "${ARKAOS_ROOT:-}" ]; then
33
43
  fi
34
44
  export ARKAOS_ROOT
35
45
 
36
- # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
37
- _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
38
- if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
39
-
40
46
  if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
41
47
  exit 0
42
48
  fi
@@ -80,6 +80,14 @@ try {
80
80
  $arkaosRootUps = (Get-Content -Raw -LiteralPath $repoPathFileUps -Encoding UTF8).Trim()
81
81
  } catch { }
82
82
  }
83
+ # .repo-path may point at a purged npx cache — fall through to
84
+ # the ~/.arkaos/lib snapshot when the core package is missing.
85
+ if (-not ($arkaosRootUps -and (Test-Path -LiteralPath (Join-Path $arkaosRootUps 'core\sync\__init__.py')))) {
86
+ $libUps = Join-Path $env:USERPROFILE '.arkaos\lib'
87
+ if (Test-Path -LiteralPath (Join-Path $libUps 'core\sync\__init__.py')) {
88
+ $arkaosRootUps = $libUps
89
+ }
90
+ }
83
91
  }
84
92
  if (-not $arkaosRootUps) {
85
93
  $arkaosRootUps = Join-Path $env:USERPROFILE '.arkaos'
@@ -160,6 +168,16 @@ if ($env:ARKAOS_ROOT) {
160
168
  $arkaosRoot = $null
161
169
  }
162
170
  }
171
+ # .repo-path may point at a purged npx cache — prefer the ~/.arkaos/lib
172
+ # snapshot over a root without the core package (env override untouched).
173
+ if (-not $env:ARKAOS_ROOT) {
174
+ if (-not ($arkaosRoot -and (Test-Path -LiteralPath (Join-Path $arkaosRoot 'core\sync\__init__.py')))) {
175
+ $libRoot = Join-Path $arkaosHome 'lib'
176
+ if (Test-Path -LiteralPath (Join-Path $libRoot 'core\sync\__init__.py')) {
177
+ $arkaosRoot = $libRoot
178
+ }
179
+ }
180
+ }
163
181
  if (-not $arkaosRoot) {
164
182
  if (Test-Path -LiteralPath $arkaosHome -PathType Container) {
165
183
  $arkaosRoot = $arkaosHome
@@ -23,7 +23,17 @@
23
23
  # Timeout: 10s | Output: JSON to stdout | Target: <100ms
24
24
  # ============================================================================
25
25
 
26
- if [ -z "${ARKAOS_ROOT:-}" ]; then
26
+ # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
27
+ _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
28
+ if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
29
+
30
+ # ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
31
+ # .repo-path can point at a purged npx cache; the shared resolver falls
32
+ # through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
33
+ if command -v arka_resolve_root >/dev/null 2>&1; then
34
+ ARKAOS_ROOT="$(arka_resolve_root)"
35
+ elif [ -z "${ARKAOS_ROOT:-}" ]; then
36
+ # Legacy chain (pre-snapshot _lib deployment)
27
37
  if [ -f "$HOME/.arkaos/.repo-path" ]; then
28
38
  ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
29
39
  elif [ -d "$HOME/.arkaos" ]; then
@@ -34,10 +44,6 @@ if [ -z "${ARKAOS_ROOT:-}" ]; then
34
44
  fi
35
45
  export ARKAOS_ROOT
36
46
 
37
- # ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
38
- _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
39
- if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
40
-
41
47
  _ARKA_L0_FALLBACK='{"additionalContext": "[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"}'
42
48
 
43
49
  if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
@@ -16,13 +16,13 @@ policies:
16
16
  - obsidian
17
17
  - context7
18
18
  - gh-grep
19
- - memory-bank
20
19
  - postgres
21
20
  - supabase
22
21
  - laravel-boost
23
22
  - serena
24
23
  - sentry
25
24
  deferred:
25
+ - memory-bank
26
26
  - playwright
27
27
  - nuxt
28
28
  - nuxt-ui
@@ -46,12 +46,12 @@ policies:
46
46
  - obsidian
47
47
  - context7
48
48
  - gh-grep
49
- - memory-bank
50
49
  - playwright
51
50
  - nuxt
52
51
  - nuxt-ui
53
52
  - sentry
54
53
  deferred:
54
+ - memory-bank
55
55
  - postgres
56
56
  - supabase
57
57
  - laravel-boost
@@ -76,11 +76,11 @@ policies:
76
76
  - obsidian
77
77
  - context7
78
78
  - gh-grep
79
- - memory-bank
80
79
  - playwright
81
80
  - next-devtools
82
81
  - sentry
83
82
  deferred:
83
+ - memory-bank
84
84
  - postgres
85
85
  - supabase
86
86
  - laravel-boost
@@ -106,12 +106,12 @@ policies:
106
106
  - obsidian
107
107
  - context7
108
108
  - gh-grep
109
- - memory-bank
110
109
  - playwright
111
110
  - shopify-dev
112
111
  - mirakl
113
112
  - sentry
114
113
  deferred:
114
+ - memory-bank
115
115
  - postgres
116
116
  - supabase
117
117
  - laravel-boost
@@ -136,9 +136,9 @@ policies:
136
136
  - obsidian
137
137
  - context7
138
138
  - gh-grep
139
- - memory-bank
140
139
  - sentry
141
140
  deferred:
141
+ - memory-bank
142
142
  - playwright
143
143
  - postgres
144
144
  - supabase
@@ -165,11 +165,11 @@ policies:
165
165
  - arka-prompts
166
166
  - obsidian
167
167
  - context7
168
- - memory-bank
169
168
  - canva
170
169
  - firecrawl
171
170
  - clickup
172
171
  deferred:
172
+ - memory-bank
173
173
  - gh-grep
174
174
  - postgres
175
175
  - supabase
@@ -195,10 +195,10 @@ policies:
195
195
  - arka-prompts
196
196
  - obsidian
197
197
  - context7
198
- - memory-bank
199
198
  - canva
200
199
  - firecrawl
201
200
  deferred:
201
+ - memory-bank
202
202
  - gh-grep
203
203
  - postgres
204
204
  - supabase
@@ -226,8 +226,8 @@ policies:
226
226
  - obsidian
227
227
  - context7
228
228
  - gh-grep
229
- - memory-bank
230
229
  deferred:
230
+ - memory-bank
231
231
  - postgres
232
232
  - supabase
233
233
  - playwright
@@ -38,6 +38,7 @@ def generate_registry(departments_dir: str | Path, output_path: str | Path) -> d
38
38
  "role": agent.role,
39
39
  "department": agent.department,
40
40
  "tier": agent.tier,
41
+ "model": agent.get_model(),
41
42
  "parent_squad": agent.parent_squad,
42
43
  "sub_squad_role": agent.sub_squad_role,
43
44
  "disc": {
@@ -62,8 +63,8 @@ def generate_registry(departments_dir: str | Path, output_path: str | Path) -> d
62
63
  k: v for k, v in agent.authority.model_dump().items()
63
64
  if v and v != [] and k not in ("delegates_to", "escalates_to")
64
65
  },
65
- "expertise_domains": agent.expertise.domains[:5],
66
- "frameworks": agent.expertise.frameworks[:5],
66
+ "expertise_domains": agent.expertise.domains,
67
+ "frameworks": agent.expertise.frameworks,
67
68
  "knowledge_sources": agent.expertise.knowledge_sources,
68
69
  "file": str(yaml_file.relative_to(departments_dir.parent)),
69
70
  "memory_path": agent.memory_path,
@@ -275,11 +275,15 @@ class ArkaScheduler:
275
275
  extra_paths = [
276
276
  os.path.join(home, ".local", "bin"),
277
277
  os.path.join(home, ".arkaos", "bin"),
278
- "/usr/local/bin",
279
278
  ]
279
+ if os.name != "nt":
280
+ extra_paths.append("/usr/local/bin")
280
281
  env = os.environ.copy()
281
- existing = env.get("PATH", "/usr/bin:/bin")
282
- env["PATH"] = ":".join(extra_paths) + ":" + existing
282
+ existing = env.get("PATH", "" if os.name == "nt" else "/usr/bin:/bin")
283
+ # os.pathsep is ';' on Windows (where drive-letter entries contain
284
+ # ':') and ':' on POSIX, so the joined PATH stays valid on both.
285
+ parts = extra_paths + ([existing] if existing else [])
286
+ env["PATH"] = os.pathsep.join(parts)
283
287
  return env
284
288
 
285
289
  def _run_attempt(
@@ -23,6 +23,7 @@ from enum import Enum
23
23
  from pathlib import Path
24
24
  from typing import Optional
25
25
 
26
+ from core.shared.temp_paths import arkaos_temp_dir
26
27
  from core.forge.schema import (
27
28
  ForgeContext,
28
29
  ForgePlan,
@@ -361,7 +362,7 @@ class ForgeOrchestrator:
361
362
  raise RuntimeError("No active forge plan.")
362
363
 
363
364
  html = render_html(self._current_plan)
364
- path = f"/tmp/forge-{self._current_plan.id}.html"
365
+ path = str(arkaos_temp_dir(f"forge-{self._current_plan.id}.html"))
365
366
  Path(path).write_text(html, encoding="utf-8")
366
367
  return path
367
368
 
@@ -51,21 +51,41 @@ def get_str(data: dict, *keys: str) -> str:
51
51
  return str(cur)
52
52
 
53
53
 
54
+ def _has_core_package(root: str) -> bool:
55
+ # core/sync/__init__.py distinguishes the full package from the
56
+ # cognitive scheduler's minimal core/ copy (cognition + workflow only).
57
+ try:
58
+ return (Path(root) / "core" / "sync" / "__init__.py").is_file()
59
+ except OSError:
60
+ return False
61
+
62
+
54
63
  def resolve_arkaos_root() -> str:
55
- """Resolve ARKAOS_ROOT with the same precedence as the bash hooks.
64
+ """Resolve ARKAOS_ROOT with the hook wrappers' validated chain.
56
65
 
57
- env ARKAOS_ROOT → ~/.arkaos/.repo-path → ~/.arkaos → ARKA_OS env →
58
- ~/.claude/skills/arkaos (portable fallback).
66
+ env ARKAOS_ROOT (unconditional operator override) → ~/.arkaos/.repo-path
67
+ (validated) → ~/.arkaos/lib stable snapshot (validated) .repo-path
68
+ even without the core package (legacy VERSION readers) → ~/.arkaos →
69
+ ARKA_OS env → ~/.claude/skills/arkaos (portable fallback).
70
+
71
+ Mirrors arka_resolve_root() in config/hooks/_lib/arka_python.sh;
72
+ bin/arka-py adds one extra step (its own dev checkout) between
73
+ .repo-path and the snapshot.
74
+
75
+ Validation matters because .repo-path points at an npx cache that
76
+ `npm cache clean` can purge at any time.
59
77
  """
60
78
  env_root = os.environ.get("ARKAOS_ROOT", "").strip()
61
79
  if env_root:
62
80
  return env_root
63
- repo_file = Path.home() / ".arkaos" / ".repo-path"
64
- if repo_file.is_file():
65
- try:
66
- return repo_file.read_text(encoding="utf-8").strip()
67
- except OSError:
68
- pass
81
+ repo = repo_path()
82
+ if repo and _has_core_package(repo):
83
+ return repo
84
+ lib = Path.home() / ".arkaos" / "lib"
85
+ if _has_core_package(str(lib)):
86
+ return str(lib)
87
+ if repo and Path(repo).is_dir():
88
+ return repo
69
89
  if (Path.home() / ".arkaos").is_dir():
70
90
  return str(Path.home() / ".arkaos")
71
91
  return os.environ.get(
@@ -30,6 +30,7 @@ import re
30
30
  from datetime import datetime, timezone
31
31
  from pathlib import Path
32
32
 
33
+ from core.shared.temp_paths import arkaos_temp_dir
33
34
  from core.hooks._shared import (
34
35
  ensure_root_on_path,
35
36
  get_str,
@@ -104,7 +105,7 @@ def _write_tmp_state(subdir: str, safe_sid: str, payload: dict) -> None:
104
105
  """Owner-only /tmp state file (umask 0o077 — PR25 v2.46.1)."""
105
106
  prev_umask = os.umask(0o077)
106
107
  try:
107
- state_dir = Path("/tmp") / subdir
108
+ state_dir = arkaos_temp_dir(subdir)
108
109
  state_dir.mkdir(parents=True, exist_ok=True)
109
110
  (state_dir / f"{safe_sid}.json").write_text(
110
111
  json.dumps(payload), encoding="utf-8"
@@ -220,7 +221,7 @@ def _flow_checks(
220
221
  kb_reported = parse_reported_kb(last)
221
222
  if safe_sid:
222
223
  injected_path = (
223
- Path("/tmp/arkaos-kb-injected") / f"{safe_sid}.json"
224
+ arkaos_temp_dir("arkaos-kb-injected") / f"{safe_sid}.json"
224
225
  )
225
226
  if injected_path.exists():
226
227
  injected_data = json.loads(
@@ -369,7 +370,7 @@ def main(stdin_json: dict | None = None) -> int:
369
370
  _native_usage(transcript_path, session_id, raw)
370
371
 
371
372
  # Only evaluate sessions where the classifier flagged creation intent.
372
- wf_marker = Path("/tmp/arkaos-wf-required") / session_id if session_id else None
373
+ wf_marker = arkaos_temp_dir("arkaos-wf-required") / session_id if session_id else None
373
374
  if wf_marker is None or not safe_session_id(session_id) or not wf_marker.is_file():
374
375
  return 0
375
376