arkaos 4.7.0 → 4.7.1

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 (61) hide show
  1. package/VERSION +1 -1
  2. package/arka/SKILL.md +2 -2
  3. package/arka/skills/flow/SKILL.md +1 -1
  4. package/bin/arka-py.ps1 +9 -2
  5. package/config/hooks/user-prompt-submit.sh +7 -0
  6. package/core/budget/__pycache__/__init__.cpython-314.pyc +0 -0
  7. package/core/budget/__pycache__/manager.cpython-314.pyc +0 -0
  8. package/core/budget/__pycache__/schema.cpython-314.pyc +0 -0
  9. package/core/forge/__pycache__/__init__.cpython-314.pyc +0 -0
  10. package/core/forge/__pycache__/complexity.cpython-314.pyc +0 -0
  11. package/core/forge/__pycache__/handoff.cpython-314.pyc +0 -0
  12. package/core/forge/__pycache__/orchestrator.cpython-314.pyc +0 -0
  13. package/core/forge/__pycache__/persistence.cpython-314.pyc +0 -0
  14. package/core/forge/__pycache__/renderer.cpython-314.pyc +0 -0
  15. package/core/forge/__pycache__/runtime_dispatcher.cpython-314.pyc +0 -0
  16. package/core/forge/__pycache__/schema.cpython-314.pyc +0 -0
  17. package/core/governance/__pycache__/agent_experiences.cpython-314.pyc +0 -0
  18. package/core/governance/__pycache__/phantom_action_check.cpython-313.pyc +0 -0
  19. package/core/governance/__pycache__/phantom_action_check.cpython-314.pyc +0 -0
  20. package/core/governance/__pycache__/qg_verdict.cpython-313.pyc +0 -0
  21. package/core/governance/__pycache__/quality_api.cpython-314.pyc +0 -0
  22. package/core/governance/__pycache__/quality_router.cpython-314.pyc +0 -0
  23. package/core/governance/__pycache__/review_workflow.cpython-314.pyc +0 -0
  24. package/core/governance/phantom_action_check.py +19 -4
  25. package/core/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  26. package/core/hooks/__pycache__/user_prompt_submit.cpython-314.pyc +0 -0
  27. package/core/hooks/user_prompt_submit.py +9 -2
  28. package/core/knowledge/__pycache__/__init__.cpython-314.pyc +0 -0
  29. package/core/knowledge/__pycache__/chunker.cpython-314.pyc +0 -0
  30. package/core/knowledge/__pycache__/embedder.cpython-314.pyc +0 -0
  31. package/core/knowledge/__pycache__/pattern_cards.cpython-314.pyc +0 -0
  32. package/core/knowledge/__pycache__/vector_store.cpython-314.pyc +0 -0
  33. package/core/memory/__pycache__/rehydrator.cpython-314.pyc +0 -0
  34. package/core/runtime/__pycache__/claude_code.cpython-313.pyc +0 -0
  35. package/core/runtime/__pycache__/codex_cli.cpython-313.pyc +0 -0
  36. package/core/runtime/__pycache__/gemini_cli.cpython-313.pyc +0 -0
  37. package/core/runtime/claude_code.py +2 -1
  38. package/core/runtime/codex_cli.py +2 -0
  39. package/core/runtime/gemini_cli.py +2 -0
  40. package/core/synapse/__pycache__/agent_experiences_layer.cpython-313.pyc +0 -0
  41. package/core/synapse/__pycache__/agent_experiences_layer.cpython-314.pyc +0 -0
  42. package/core/synapse/__pycache__/engine.cpython-313.pyc +0 -0
  43. package/core/synapse/__pycache__/engine.cpython-314.pyc +0 -0
  44. package/core/synapse/__pycache__/graph_context_layer.cpython-313.pyc +0 -0
  45. package/core/synapse/__pycache__/graph_context_layer.cpython-314.pyc +0 -0
  46. package/core/synapse/__pycache__/layers.cpython-313.pyc +0 -0
  47. package/core/synapse/__pycache__/layers.cpython-314.pyc +0 -0
  48. package/core/synapse/__pycache__/pattern_library_layer.cpython-313.pyc +0 -0
  49. package/core/synapse/__pycache__/pattern_library_layer.cpython-314.pyc +0 -0
  50. package/core/synapse/agent_experiences_layer.py +4 -0
  51. package/core/synapse/engine.py +9 -0
  52. package/core/synapse/graph_context_layer.py +4 -0
  53. package/core/synapse/layers.py +28 -0
  54. package/core/synapse/pattern_library_layer.py +4 -0
  55. package/departments/dev/skills/scaffold/SKILL.md +15 -11
  56. package/knowledge/commands-registry.json +3006 -1676
  57. package/knowledge/commands-registry.json.bak +4121 -0
  58. package/package.json +1 -1
  59. package/pyproject.toml +1 -1
  60. package/scripts/__pycache__/synapse-bridge.cpython-314.pyc +0 -0
  61. package/scripts/tools/__pycache__/prompt_lint.cpython-313.pyc +0 -0
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.7.0
1
+ 4.7.1
package/arka/SKILL.md CHANGED
@@ -152,7 +152,7 @@ Example first lines (pick the right department for the ask):
152
152
  After the routing line, in order:
153
153
 
154
154
  1. State the workflow name and its phase count.
155
- 2. Run Phase 1 (usually spec via `arka-spec` or plan via `arka-forge`) BEFORE writing any code.
155
+ 2. Run Phase 1 (usually spec via `arka-dev-spec` or plan via `arka-forge`) BEFORE writing any code.
156
156
  3. Execute sequential phases with visibility (one at a time, report status).
157
157
  4. Run the Quality Gate (Marta CQO + Eduardo Copy + Francisca Tech, model Opus) BEFORE marking done.
158
158
 
@@ -186,7 +186,7 @@ violation (squad-routing, arka-supremacy, spec-driven, mandatory-qa).
186
186
  | `/arka search <query>` | Semantic search in knowledge base |
187
187
  | `/arka keys` | Manage API keys (OpenAI, Google, fal.ai) |
188
188
  | `/arka personas` | Manage AI personas (create, clone to agent) |
189
- | `/arka resume <PR_URL>` | Re-enter the Claude Code session that produced a PR (GitHub / GitLab / Bitbucket). Wraps the native `/resume` from Claude Code 2.1.122+. Useful with `arka-spec` and `arka-release` archaeology. |
189
+ | `/arka resume <PR_URL>` | Re-enter the Claude Code session that produced a PR (GitHub / GitLab / Bitbucket). Wraps the native `/resume` from Claude Code 2.1.122+. Useful with `arka-dev-spec` and `arka-release` archaeology. |
190
190
  | `/do <description>` | Universal routing — natural language to department command |
191
191
 
192
192
  ## Universal Orchestrator (/do)
@@ -154,7 +154,7 @@ no six-reviewer role-play. One marker per gate transition.
154
154
  ## Related skills
155
155
 
156
156
  - `/arka-forge` — complexity-aware planning for MEDIUM/HIGH Gate 2.
157
- - `/arka-spec` — spec gate when Gate 2 scope needs a full spec.
157
+ - `arka-dev-spec` (`/dev spec`) — spec gate when Gate 2 scope needs a full spec.
158
158
  - `/arka-quality` — Gate 4 orchestration.
159
159
  - `/arka-checkpoint` — user-in-the-loop fragmentation for >30s dispatches.
160
160
 
package/bin/arka-py.ps1 CHANGED
@@ -12,9 +12,15 @@ $ErrorActionPreference = "Stop"
12
12
 
13
13
  # ─── Source the shared resolver, from the repo or the installed location ──
14
14
  $self = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
15
+ # Windows PowerShell 5.1 cannot parse an inline `if`-expression passed as a
16
+ # command argument (e.g. `Join-Path (if (...) {...} else {...}) "..."`); it is
17
+ # a PowerShell 7-only construct, so the whole script fails to parse under 5.1
18
+ # and every `arka-py ...` call dies. Resolve the home base into a variable
19
+ # first — the assignment form of `if` IS valid in 5.1.
20
+ $base = if ($env:USERPROFILE) { $env:USERPROFILE } else { $HOME }
15
21
  $libs = @(
16
22
  (Join-Path $self "..\config\hooks\_lib\arka_python.ps1"),
17
- (Join-Path (if ($env:USERPROFILE) { $env:USERPROFILE } else { $HOME }) ".arkaos\config\hooks\_lib\arka_python.ps1")
23
+ (Join-Path $base ".arkaos\config\hooks\_lib\arka_python.ps1")
18
24
  )
19
25
  foreach ($lib in $libs) {
20
26
  if (Test-Path -LiteralPath $lib) { . $lib; break }
@@ -24,7 +30,8 @@ if (-not $env:ARKA_PY) { $env:ARKA_PY = "python" }
24
30
  # ─── Make `-m core.*` resolvable regardless of cwd ────────────────────────
25
31
  $root = $env:ARKAOS_ROOT
26
32
  if (-not $root) {
27
- $rp = Join-Path (if ($env:USERPROFILE) { $env:USERPROFILE } else { $HOME }) ".arkaos\.repo-path"
33
+ # Reuse $base (5.1-safe) instead of an inline `if`-expression argument.
34
+ $rp = Join-Path $base ".arkaos\.repo-path"
28
35
  if (Test-Path -LiteralPath $rp) { $root = (Get-Content -LiteralPath $rp -Raw).Trim() }
29
36
  }
30
37
  if ($root -and (Test-Path -LiteralPath $root)) {
@@ -46,6 +46,13 @@ export ARKAOS_ROOT
46
46
 
47
47
  _ARKA_L0_FALLBACK='{"additionalContext": "[Constitution] NON-NEGOTIABLE: branch-isolation, security-gate, mandatory-qa, evidence-flow, arkaos-not-yes-man, excellence-mandate | QUALITY-GATE: marta-cqo, eduardo-copy, francisca-tech-ux | MUST (28) incl.: squad-routing, spec-driven, conventional-commits, test-coverage, subagent-discipline, persona-vs-artifact"}'
48
48
 
49
+ # Test seam: bats asserts the fallback CONTENT deterministically —
50
+ # the shared resolver overwrites ARKA_PY, so an env flag is the only
51
+ # reliable way to force this path (tests/constitution.bats L0 tests).
52
+ if [ -n "${ARKA_HOOK_FORCE_FALLBACK:-}" ]; then
53
+ echo "$_ARKA_L0_FALLBACK"
54
+ exit 0
55
+ fi
49
56
  if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
50
57
  echo "$_ARKA_L0_FALLBACK"
51
58
  exit 0
@@ -36,6 +36,19 @@ _EFFECT_OBJECT = (
36
36
  r"|commands?|builds?)\b|\.[a-z]{2,4}\b|`[^`]+`)"
37
37
  )
38
38
 
39
+ # Analytic/mental nouns: a verb whose nearest object is one of these is
40
+ # narrating the RESPONSE, not a tool effect ("updated my understanding of
41
+ # the file", "adicionei contexto sobre os testes") — the effect object
42
+ # match must not cross them (QG condition on #255 before enforcement).
43
+ _ANALYTIC_NOUN = (
44
+ r"\b(?:understanding|context|summary|notes?|thinking|thoughts?"
45
+ r"|takeaways?|impressions?|sense|grasp|view|idea|picture"
46
+ r"|mental\s+model|contexto|resumo|notas?|entendimento"
47
+ r"|perce[çc][ãa]o|an[áa]lise|analysis|ideia|vis[ãa]o|imagem"
48
+ r"|no[çc][ãa]o|perspe[ct]?tiva|opini[ãa]o|conhecimento|knowledge)\b"
49
+ )
50
+ _GAP = r"(?:(?!" + _ANALYTIC_NOUN + r")[^.\n!?]){0,60}?"
51
+
39
52
  # Verbs whose completion is unambiguous on its own (git/publish/install).
40
53
  _STANDALONE_PT = (
41
54
  r"(?<!não )\b(instalei|publiquei|gravei|renomeei|implementei"
@@ -46,15 +59,17 @@ _STANDALONE_EN = (
46
59
  r"\bI(?:'ve| have)?\s+(?:just\s+)?(committed|pushed|merged|published"
47
60
  r"|released|deployed|installed)\b"
48
61
  )
49
- # Ambiguous verbs — only a claim when bound to an effect object nearby.
62
+ # Ambiguous verbs — only a claim when bound to an effect object nearby,
63
+ # without an analytic noun in between. "ran into"/"ran through" are
64
+ # idioms, never executions.
50
65
  _BOUND_PT = (
51
66
  r"(?<!não )\b(criei|escrevi|atualizei|editei|apaguei|removi|adicionei"
52
- r"|movi|apliquei|corri|executei)\b[^.\n!?]{0,60}?" + _EFFECT_OBJECT
67
+ r"|movi|apliquei|corri|executei)\b" + _GAP + _EFFECT_OBJECT
53
68
  )
54
69
  _BOUND_EN = (
55
70
  r"\bI(?:'ve| have)?\s+(?:just\s+)?(created|wrote|updated|deleted"
56
- r"|added|moved|applied|renamed|ran|executed)\b[^.\n!?]{0,60}?"
57
- + _EFFECT_OBJECT
71
+ r"|added|moved|applied|renamed|ran(?!\s+(?:into|through|over|across))"
72
+ r"|executed)\b" + _GAP + _EFFECT_OBJECT
58
73
  )
59
74
  _PASSIVE = (
60
75
  r"\b(commit|push|merge|deploy|release|PR)\s+(feito|criado|efetuado"
@@ -531,8 +531,15 @@ def main(stdin_json: dict | None = None, raw: str = "") -> int:
531
531
  except OSError:
532
532
  pass
533
533
 
534
- user_input = get_str(stdin_json, "userInput") or get_str(
535
- stdin_json, "message"
534
+ # Claude Code sends the user's text under "prompt" (UserPromptSubmit
535
+ # hook schema); "userInput"/"message" cover other runtimes. Missing
536
+ # "prompt" here meant the raw JSON line fell through as user_input,
537
+ # so L1/L5/L2.5 computed on JSON garbage every turn (found 2026-07-09
538
+ # by the un-swallowed orchestrator bats test).
539
+ user_input = (
540
+ get_str(stdin_json, "prompt")
541
+ or get_str(stdin_json, "userInput")
542
+ or get_str(stdin_json, "message")
536
543
  )
537
544
  session_id = get_str(stdin_json, "session_id")
538
545
  effort_level = get_str(stdin_json, "effort", "level") or os.environ.get(
@@ -152,7 +152,8 @@ def _run_claude_cli(cmd: list[str]) -> subprocess.CompletedProcess:
152
152
 
153
153
  try:
154
154
  return subprocess.run(
155
- cmd, capture_output=True, text=True, timeout=60, check=False
155
+ cmd, capture_output=True, text=True, encoding="utf-8",
156
+ errors="replace", timeout=60, check=False
156
157
  )
157
158
  except subprocess.TimeoutExpired as exc:
158
159
  raise LLMUnavailable("claude CLI timed out after 60s") from exc
@@ -170,6 +170,8 @@ def _run_codex_cli(cmd: list[str]) -> subprocess.CompletedProcess:
170
170
  cmd,
171
171
  capture_output=True,
172
172
  text=True,
173
+ encoding="utf-8",
174
+ errors="replace",
173
175
  timeout=_TIMEOUT_SECONDS,
174
176
  check=False,
175
177
  # CRITICAL: with a prompt arg AND piped stdin, codex exec
@@ -147,6 +147,8 @@ def _run_gemini_cli(cmd: list[str]) -> subprocess.CompletedProcess:
147
147
  cmd,
148
148
  capture_output=True,
149
149
  text=True,
150
+ encoding="utf-8",
151
+ errors="replace",
150
152
  timeout=_TIMEOUT_SECONDS,
151
153
  check=False,
152
154
  )
@@ -46,6 +46,10 @@ class AgentExperiencesLayer(Layer):
46
46
  def name(self) -> str:
47
47
  return "AgentExperiences"
48
48
 
49
+ @property
50
+ def input_sensitive(self) -> bool:
51
+ return True
52
+
49
53
  @property
50
54
  def cache_ttl(self) -> int:
51
55
  return 30
@@ -8,6 +8,7 @@ Design goals:
8
8
  - Relevance filtering (skip irrelevant layers)
9
9
  """
10
10
 
11
+ import hashlib
11
12
  import time
12
13
  from dataclasses import dataclass, field
13
14
  from typing import Any
@@ -109,6 +110,14 @@ class SynapseEngine:
109
110
  def _compute_layer(self, layer: Layer, ctx: PromptContext) -> LayerResult:
110
111
  """Compute a single layer with caching."""
111
112
  cache_key = f"{layer.id}:{ctx.cwd}:{ctx.active_agent}"
113
+ if layer.input_sensitive:
114
+ # Input-dependent layers (hints, department, KB retrieval)
115
+ # must not serve one prompt's result to a different prompt
116
+ # within the TTL window.
117
+ digest = hashlib.sha1(
118
+ (ctx.user_input or "").encode("utf-8", "replace")
119
+ ).hexdigest()[:12]
120
+ cache_key += f":{digest}"
112
121
 
113
122
  # Check cache
114
123
  if layer.cache_ttl > 0:
@@ -141,6 +141,10 @@ class GraphContextLayer(Layer):
141
141
  def name(self) -> str:
142
142
  return "GraphContext"
143
143
 
144
+ @property
145
+ def input_sensitive(self) -> bool:
146
+ return True
147
+
144
148
  @property
145
149
  def cache_ttl(self) -> int:
146
150
  return 30
@@ -74,6 +74,18 @@ class Layer(ABC):
74
74
  """Cache TTL in seconds. 0 = no caching."""
75
75
  return 0
76
76
 
77
+ @property
78
+ def input_sensitive(self) -> bool:
79
+ """True when compute() depends on ctx.user_input.
80
+
81
+ Input-sensitive layers get the prompt hashed into their cache
82
+ key — without it, a cached result from one prompt is served for
83
+ a DIFFERENT prompt within the TTL window (found 2026-07-09: L5
84
+ served 'hello' hints for an explicit '/dev feature' command,
85
+ defeating its own slash-suppression rule).
86
+ """
87
+ return False
88
+
77
89
  @property
78
90
  def priority(self) -> int:
79
91
  """Layer priority (lower = computed first)."""
@@ -166,6 +178,10 @@ class DepartmentLayer(Layer):
166
178
  def name(self) -> str:
167
179
  return "Department"
168
180
 
181
+ @property
182
+ def input_sensitive(self) -> bool:
183
+ return True
184
+
169
185
  @property
170
186
  def priority(self) -> int:
171
187
  return 10
@@ -392,6 +408,10 @@ class CommandHintsLayer(Layer):
392
408
  def name(self) -> str:
393
409
  return "CommandHints"
394
410
 
411
+ @property
412
+ def input_sensitive(self) -> bool:
413
+ return True
414
+
395
415
  @property
396
416
  def cache_ttl(self) -> int:
397
417
  return 30
@@ -522,6 +542,10 @@ class KnowledgeRetrievalLayer(Layer):
522
542
  def name(self) -> str:
523
543
  return "KnowledgeRetrieval"
524
544
 
545
+ @property
546
+ def input_sensitive(self) -> bool:
547
+ return True
548
+
525
549
  @property
526
550
  def cache_ttl(self) -> int:
527
551
  return 30
@@ -1027,6 +1051,10 @@ class KBContextLayer(Layer):
1027
1051
  def name(self) -> str:
1028
1052
  return "KBContext"
1029
1053
 
1054
+ @property
1055
+ def input_sensitive(self) -> bool:
1056
+ return True
1057
+
1030
1058
  @property
1031
1059
  def cache_ttl(self) -> int:
1032
1060
  return 0
@@ -71,6 +71,10 @@ class PatternLibraryLayer(Layer):
71
71
  def name(self) -> str:
72
72
  return "PatternLibrary"
73
73
 
74
+ @property
75
+ def input_sensitive(self) -> bool:
76
+ return True
77
+
74
78
  @property
75
79
  def cache_ttl(self) -> int:
76
80
  return 60
@@ -14,17 +14,21 @@ Create new projects from real git repositories with full automation: dependencie
14
14
 
15
15
  ## Commands
16
16
 
17
- | Command | Git Repository | Stack |
18
- |---------|---------------|-------|
19
- | `/dev scaffold laravel <name>` | `https://${GIT_HOST}/laravel/laravel.git` (override with `ARKAOS_LARAVEL_STARTER_REPO` env) | Laravel + Herd |
20
- | `/dev scaffold nuxt-saas <name>` | `https://github.com/nuxt-ui-templates/dashboard.git` | Nuxt 3 Dashboard |
21
- | `/dev scaffold nuxt-landing <name>` | `https://github.com/nuxt-ui-templates/landing.git` | Nuxt 3 Landing |
22
- | `/dev scaffold nuxt-docs <name>` | `https://github.com/nuxt-ui-templates/docs.git` | Nuxt 3 Docs |
23
- | `/dev scaffold vue-saas <name>` | `https://github.com/nuxt-ui-templates/dashboard-vue.git` | Vue 3 Dashboard |
24
- | `/dev scaffold vue-landing <name>` | `https://github.com/nuxt-ui-templates/starter-vue.git` | Vue 3 Landing |
25
- | `/dev scaffold full-stack <name>` | Laravel + Nuxt (both repos) | Full-stack |
26
- | `/dev scaffold react <name>` | React starter (TBD) | React SPA |
27
- | `/dev scaffold nextjs <name>` | Next.js starter (TBD) | Next.js App |
17
+ <!-- Column convention: command | DESCRIPTION | repo. The registry
18
+ generator (bin/arka-registry-gen) reads column 2 as the user-facing
19
+ description a repo URL there ships garbled command help (QG
20
+ blocker, 2026-07-09). -->
21
+ | Command | Description | Git Repository |
22
+ |---------|-------------|----------------|
23
+ | `/dev scaffold laravel <name>` | Scaffold a Laravel app into ~/Herd from the starter repo | `https://${GIT_HOST}/laravel/laravel.git` (override with `ARKAOS_LARAVEL_STARTER_REPO` env) |
24
+ | `/dev scaffold nuxt-saas <name>` | Scaffold a Nuxt 3 SaaS dashboard into ~/Work | `https://github.com/nuxt-ui-templates/dashboard.git` |
25
+ | `/dev scaffold nuxt-landing <name>` | Scaffold a Nuxt 3 landing page into ~/Work | `https://github.com/nuxt-ui-templates/landing.git` |
26
+ | `/dev scaffold nuxt-docs <name>` | Scaffold a Nuxt 3 docs site into ~/Work | `https://github.com/nuxt-ui-templates/docs.git` |
27
+ | `/dev scaffold vue-saas <name>` | Scaffold a Vue 3 SaaS dashboard into ~/Work | `https://github.com/nuxt-ui-templates/dashboard-vue.git` |
28
+ | `/dev scaffold vue-landing <name>` | Scaffold a Vue 3 landing page into ~/Work | `https://github.com/nuxt-ui-templates/starter-vue.git` |
29
+ | `/dev scaffold full-stack <name>` | Scaffold Laravel (~/Herd) + Nuxt (~/Work) as a linked pair | Laravel + Nuxt starter repos above |
30
+ | `/dev scaffold react <name>` | Scaffold a React SPA — starter repo not yet selected | (not yet selected) |
31
+ | `/dev scaffold nextjs <name>` | Scaffold a Next.js app — starter repo not yet selected | (not yet selected) |
28
32
 
29
33
  ## Workflow: /dev scaffold <type> <name>
30
34