arkaos 5.13.0 → 5.15.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 (77) hide show
  1. package/THE-ARKAOS-GUIDE.md +1 -1
  2. package/VERSION +1 -1
  3. package/config/evals/marketing.yaml +4 -4
  4. package/config/hooks/_lib/arka_python.sh +104 -0
  5. package/config/hooks/pre-tool-use.cjs +79 -1
  6. package/config/hooks/pre-tool-use.sh +19 -2
  7. package/core/cognition/dreaming.py +323 -26
  8. package/core/cognition/reorganizer.py +18 -6
  9. package/core/cognition/reorganizer_cli.py +61 -14
  10. package/core/governance/evidence_checks.py +1001 -37
  11. package/core/hooks/_shared.py +132 -0
  12. package/core/hooks/post_tool_use.py +38 -3
  13. package/core/hooks/pre_tool_use.py +13 -0
  14. package/core/hooks/stop.py +38 -1
  15. package/core/hooks/stop_governance.py +6 -2
  16. package/core/runtime/user_paths.py +40 -8
  17. package/core/sync/engine.py +2 -0
  18. package/core/sync/feature_injector.py +182 -0
  19. package/core/sync/features/workflow-tiers.yaml +1 -1
  20. package/core/sync/marker_audit.py +253 -0
  21. package/core/sync/reporter.py +74 -2
  22. package/core/sync/schema.py +103 -1
  23. package/core/terminal/session.py +64 -32
  24. package/departments/dev/skills/security-compliance/SKILL.md +0 -5
  25. package/departments/dev/skills/threejs/SKILL.md +2 -2
  26. package/departments/landing/skills/offer-create/references/offer-formats.md +2 -2
  27. package/departments/marketing/skills/ad-creative/SKILL.md +1 -1
  28. package/departments/marketing/skills/ad-creative/references/creative-review-page.md +5 -5
  29. package/departments/ops/skills/gdpr-compliance/SKILL.md +0 -5
  30. package/departments/ops/skills/iso27001/SKILL.md +0 -5
  31. package/departments/ops/skills/quality-management/SKILL.md +0 -5
  32. package/departments/ops/skills/risk-management/SKILL.md +0 -5
  33. package/departments/ops/skills/soc2-compliance/SKILL.md +0 -5
  34. package/departments/ops/skills/update/references/sync-engine.md +1 -1
  35. package/departments/ops/skills/update/references/workflows.md +2 -1
  36. package/departments/sales/skills/prospecting/references/demand-signals.md +1 -1
  37. package/harness/codex/AGENTS.md +1 -1
  38. package/harness/copilot/copilot-instructions.md +1 -1
  39. package/harness/cursor/rules/arkaos.mdc +2 -2
  40. package/harness/gemini/GEMINI.md +1 -1
  41. package/harness/opencode/AGENTS.md +1 -1
  42. package/harness/opencode/agents/arka-architect-gabriel.md +1 -1
  43. package/harness/opencode/agents/arka-brand-director-valentina.md +1 -1
  44. package/harness/opencode/agents/arka-cfo-helena.md +1 -1
  45. package/harness/opencode/agents/arka-chief-of-staff-afonso.md +1 -1
  46. package/harness/opencode/agents/arka-community-strategist-beatriz.md +1 -1
  47. package/harness/opencode/agents/arka-content-strategist-rafael.md +1 -1
  48. package/harness/opencode/agents/arka-conversion-strategist-ines.md +1 -1
  49. package/harness/opencode/agents/arka-coo-sofia.md +1 -1
  50. package/harness/opencode/agents/arka-copy-director-eduardo.md +1 -1
  51. package/harness/opencode/agents/arka-cqo-marta.md +1 -1
  52. package/harness/opencode/agents/arka-cto-marco.md +1 -1
  53. package/harness/opencode/agents/arka-design-ops-lead-iris.md +1 -1
  54. package/harness/opencode/agents/arka-ecom-director-ricardo.md +1 -1
  55. package/harness/opencode/agents/arka-knowledge-director-clara.md +1 -1
  56. package/harness/opencode/agents/arka-leadership-director-rodrigo.md +1 -1
  57. package/harness/opencode/agents/arka-marketing-director-luna.md +1 -1
  58. package/harness/opencode/agents/arka-ops-lead-daniel.md +1 -1
  59. package/harness/opencode/agents/arka-pm-director-carolina.md +1 -1
  60. package/harness/opencode/agents/arka-revops-lead-vicente.md +1 -1
  61. package/harness/opencode/agents/arka-saas-strategist-tiago.md +1 -1
  62. package/harness/opencode/agents/arka-sales-director-miguel.md +1 -1
  63. package/harness/opencode/agents/arka-strategy-director-tomas.md +1 -1
  64. package/harness/opencode/agents/arka-tech-director-francisca.md +1 -1
  65. package/harness/opencode/agents/arka-tech-lead-paulo.md +1 -1
  66. package/harness/opencode/agents/arka-video-producer-simao.md +1 -1
  67. package/harness/zed/.rules +1 -1
  68. package/installer/claude-md.js +42 -4
  69. package/knowledge/skills-manifest.json +1 -1
  70. package/package.json +3 -1
  71. package/pyproject.toml +41 -2
  72. package/scripts/dashboard-api.py +16 -1
  73. package/scripts/fenced-code-allowlist.json +308 -0
  74. package/scripts/lint_fenced_code.mjs +591 -0
  75. package/scripts/skills_catalog_gen.py +21 -8
  76. package/scripts/start-dashboard.ps1 +14 -0
  77. package/scripts/tools/docs_stats.py +42 -2
@@ -1,6 +1,6 @@
1
1
  # The ArkaOS Guide
2
2
 
3
- > v5.13.0 — 89 agents, 17 departments, 340 skills, 306 commands, 20 ADRs.
3
+ > v5.14.0 — 89 agents, 17 departments, 340 skills, 306 commands, 20 ADRs.
4
4
  > One file, everything you need to start. Generated by `scripts/guide_gen.py` — never hand-edited.
5
5
 
6
6
  ## What it is
package/VERSION CHANGED
@@ -1 +1 @@
1
- 5.13.0
1
+ 5.15.0
@@ -389,7 +389,7 @@
389
389
  the carousel frames, and the different headline options they can compare. Can you put
390
390
  that together?
391
391
  expected_properties:
392
- - Produces a creative review page from the HTML template, not plain markdown
392
+ - Produces a self-contained HTML creative review page, not plain markdown
393
393
  - Populates the DATA object (concept tabs, in-feed preview, frame storyboard, headline variations,
394
394
  copy, destination)
395
395
  - Labels storyboard frames by narrative job rather than by pictured content
@@ -398,9 +398,9 @@
398
398
  - Does not present invented stats or stock imagery as the brand's real assets
399
399
  - Uses placeholders for unrendered frames and keeps image paths relative
400
400
  - Explains how to deliver the page (open locally / host / hand off the file)
401
- rubric: Should recognize this as a creative review page request and apply references/creative-review-page.md
402
- + the assets/creative-review-template.html template rather than producing plain markdown.
403
- Should copy the template into the output folder and populate its DATA object with the
401
+ rubric: Should recognize this as a creative review page request and apply the build spec in
402
+ references/creative-review-page.md rather than producing plain markdown. Should build a
403
+ single self-contained review.html in the output folder and populate its DATA block with the
404
404
  four concepts as tabs, each with an in-feed Instagram preview, a labeled frame-by-frame
405
405
  storyboard (frames labeled by narrative job — Hook / Problem / Proof / Ask — not by pictured
406
406
  content), selectable headline variations, primary text, and destination/CTA. Should curate
@@ -154,3 +154,107 @@ arka_resolve_root() {
154
154
  fi
155
155
  printf '%s\n' "${ARKA_OS:-$HOME/.claude/skills/arkaos}"
156
156
  }
157
+
158
+ # ─── Degraded-run telemetry ────────────────────────────────────────────
159
+ # A hook that fails open and says nothing is indistinguishable from a hook
160
+ # that ran and allowed. That ambiguity is not hypothetical: an ArkaOS venv
161
+ # that could not `import pydantic` made every gate on one machine allow
162
+ # silently for months, and the same silence previously kept two real bugs
163
+ # invisible while manufacturing a third that never existed (Cross-Machine
164
+ # Lab, X3).
165
+ #
166
+ # Two hard rules, both deliberate:
167
+ #
168
+ # 1. NEVER write to stderr. Claude Code surfaces hook stderr to the user
169
+ # as an error, so a diagnostic there converts a silent degradation
170
+ # into visible noise on every event — trading one bad failure mode
171
+ # for a worse one. The record goes to a file; only a reader who wants
172
+ # it pays for it.
173
+ # 2. NEVER change the exit code. Fail-open is the correct posture for a
174
+ # governance hook: a broken interpreter must not block the user's
175
+ # work. This makes the degradation legible, not fatal.
176
+ #
177
+ # One JSON line per event, appended. Failure to write is swallowed —
178
+ # telemetry must never be the thing that breaks a hook.
179
+ #
180
+ # Growth cap: mirrors DEGRADED_LOG_MAX_BYTES in core/hooks/_shared.py. This
181
+ # writer needs it MORE than the Python one, not less — the cases it records
182
+ # (no interpreter, missing entrypoint) fire on every single tool call, so an
183
+ # uncapped log on a broken machine is the runaway, not a corner case.
184
+ ARKA_DEGRADED_MAX_BYTES=5242880
185
+
186
+ arka_hook_degraded() {
187
+ local hook="${1:-unknown}" reason="${2:-unknown}" detail="${3:-}"
188
+ local dir="$HOME/.arkaos/telemetry"
189
+ local file="$dir/hook-degraded.jsonl"
190
+ local stamp bytes
191
+ stamp="$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null)" || stamp=""
192
+ # Keep detail on one line and out of the JSON grammar's way. Every C0
193
+ # control character (and DEL) becomes a space: a raw tab, \r or \001
194
+ # reaching the printf below emits a byte JSON forbids inside a string, so
195
+ # one degraded event carrying a Python traceback used to poison the whole
196
+ # line for every reader. Translated rather than deleted so words do not
197
+ # fuse — "expected\tgot" must stay two tokens. LC_ALL=C keeps the range
198
+ # byte-wise; tr pads set2 by repeating its last character (POSIX).
199
+ detail="$(printf '%s' "$detail" | LC_ALL=C tr '\000-\037\177' ' ' \
200
+ | cut -c1-400)"
201
+ detail="${detail//\\/\\\\}"
202
+ detail="${detail//\"/\\\"}"
203
+ if [ -f "$file" ]; then
204
+ bytes="$(wc -c < "$file" 2>/dev/null | tr -d ' ')"
205
+ case "$bytes" in
206
+ '' | *[!0-9]*) ;;
207
+ *)
208
+ if [ "$bytes" -ge "$ARKA_DEGRADED_MAX_BYTES" ]; then
209
+ mv -f "$file" "$file.1" 2>/dev/null || true
210
+ fi
211
+ ;;
212
+ esac
213
+ fi
214
+ {
215
+ mkdir -p "$dir" 2>/dev/null &&
216
+ printf '{"ts":"%s","hook":"%s","reason":"%s","detail":"%s"}\n' \
217
+ "$stamp" "$hook" "$reason" "$detail" >> "$file"
218
+ } 2>/dev/null || true
219
+ return 0
220
+ }
221
+
222
+ # Run a hook entrypoint under the resolved interpreter, recording the
223
+ # degraded cases instead of exec'ing into silence.
224
+ #
225
+ # ─── Deliberate divergence: this path does NOT `exec` ───────────────────
226
+ # Every other .sh wrapper (post-tool-use, session-start, session-end,
227
+ # subagent-stop, user-prompt-submit) still ends in `exec "$ARKA_PY" -m …`.
228
+ # This one cannot, and the reason is structural rather than stylistic:
229
+ # `exec` REPLACES the shell with Python, so there is no surviving process
230
+ # to read the exit status afterwards. Recording "the entrypoint failed"
231
+ # requires observing the status the entrypoint exited with, which requires
232
+ # outliving it. Restoring `exec` here would silently delete the
233
+ # entrypoint-failed record — the single most valuable one, since it is the
234
+ # only witness to a broken interpreter that resolves but cannot run.
235
+ #
236
+ # Two measured costs, accepted knowingly:
237
+ # 1. One extra live process (this shell) for the hook's lifetime.
238
+ # 2. On a hard kill of the wrapper (Claude Code's 10s timeout), the
239
+ # Python child is reparented to PID 1 instead of dying with the
240
+ # shell — an orphan for the remainder of its own run. Not fixable by
241
+ # trapping: bash defers trap handling until the foreground command
242
+ # returns, and backgrounding the child would redirect its stdin from
243
+ # /dev/null in a non-interactive shell, which breaks the hook's stdin
244
+ # contract outright. The orphan is short-lived and harmless; a hook
245
+ # that cannot report its own failure is neither.
246
+ #
247
+ # Exit codes pass through UNCHANGED. Note which ones are NOT failures:
248
+ # 0 allow
249
+ # 2 the documented deny/block code — a gate doing its job, never logged
250
+ # Anything else means the entrypoint did not get to decide, which is
251
+ # exactly the case worth a record.
252
+ arka_run_hook() {
253
+ local hook="$1" module="$2" status
254
+ "$ARKA_PY" -m "$module"
255
+ status=$?
256
+ if [ "$status" -ne 0 ] && [ "$status" -ne 2 ]; then
257
+ arka_hook_degraded "$hook" "entrypoint-failed" "exit=$status module=$module py=$ARKA_PY"
258
+ fi
259
+ return "$status"
260
+ }
@@ -22,6 +22,62 @@ const path = require("node:path");
22
22
 
23
23
  const FAIL_OPEN_EXIT = 0;
24
24
 
25
+ // Growth cap, mirroring DEGRADED_LOG_MAX_BYTES in core/hooks/_shared.py
26
+ // and ARKA_DEGRADED_MAX_BYTES in _lib/arka_python.sh.
27
+ const DEGRADED_MAX_BYTES = 5 * 1024 * 1024;
28
+
29
+ /**
30
+ * Record that this shim allowed because it could not run, not because it
31
+ * decided — the same JSONL line, in the same file, as record_degraded() in
32
+ * core/hooks/_shared.py and arka_hook_degraded() in _lib/arka_python.sh:
33
+ * {ts,hook,reason,detail}, appended, never on stderr, never fatal, never a
34
+ * change to the exit code.
35
+ *
36
+ * This surface needs it most, not least. On POSIX the installer registers
37
+ * THIS file as the PreToolUse command whenever it and the fastpath engine
38
+ * are deployed (installer/adapters/claude-code.js::hookEntry), so the .sh
39
+ * chain — the one that carries the shell telemetry — is reached only by
40
+ * delegation. Every fail-open below therefore happens BEFORE any other
41
+ * writer exists to observe it: instrumenting only the .sh would have left
42
+ * the default install's three silent exits exactly as silent as before.
43
+ *
44
+ * `via=cjs` leads every detail because `unhandled-fail-open` is a reason
45
+ * the Python entrypoint also emits; the surface has to be readable from
46
+ * the line itself.
47
+ */
48
+ function recordDegraded(reason, detail) {
49
+ try {
50
+ const home = process.env.HOME || require("node:os").homedir();
51
+ const dir = path.join(home, ".arkaos", "telemetry");
52
+ const file = path.join(dir, "hook-degraded.jsonl");
53
+ fs.mkdirSync(dir, { recursive: true });
54
+ try {
55
+ if (fs.statSync(file).size >= DEGRADED_MAX_BYTES) {
56
+ fs.renameSync(file, file + ".1");
57
+ }
58
+ } catch {
59
+ // No log yet, or one that cannot be rotated: append regardless. A
60
+ // cap that suppresses the record defeats the point of recording.
61
+ }
62
+ const line = JSON.stringify({
63
+ // Second precision, no fractional part — byte-identical to the
64
+ // strftime/date formats the other two writers use.
65
+ ts: new Date().toISOString().replace(/\.\d+Z$/, "Z"),
66
+ hook: "pre-tool-use",
67
+ reason,
68
+ detail: String(detail == null ? "" : detail)
69
+ // JSON.stringify would escape control characters rather than emit
70
+ // them raw, but a tab-laden stack trace still makes the line
71
+ // unreadable; normalise for the same reason the shell writer does.
72
+ .replace(/[\u0000-\u001f\u007f]/g, " ")
73
+ .slice(0, 400),
74
+ });
75
+ fs.appendFileSync(file, line + "\n");
76
+ } catch {
77
+ // Telemetry must never be the thing that breaks a hook.
78
+ }
79
+ }
80
+
25
81
  function readStdin() {
26
82
  try {
27
83
  return fs.readFileSync(0, "utf8");
@@ -34,6 +90,10 @@ function delegate(rawStdin) {
34
90
  const sibling = path.join(__dirname, "pre-tool-use.sh");
35
91
  if (!fs.existsSync(sibling)) {
36
92
  // Missing sibling → bash would exit 127; the contract is fail-open.
93
+ // A split deploy that lands the .cjs without the .sh disables every
94
+ // gate for the whole install, so this is the highest-stakes silent
95
+ // allow in the file — it never reaches the shell writer.
96
+ recordDegraded("delegate-target-missing", `via=cjs sibling=${sibling}`);
37
97
  process.exit(FAIL_OPEN_EXIT);
38
98
  }
39
99
  // Lazy require: the fast path never pays for child_process.
@@ -44,6 +104,16 @@ function delegate(rawStdin) {
44
104
  env: { ...process.env, ARKA_HOOK_FASTPATH: "0" },
45
105
  });
46
106
  if (result.error || result.status === null) {
107
+ // Two distinct degradations, both invisible until now: bash could not
108
+ // be spawned at all (result.error — no bash on PATH, EACCES, EMFILE),
109
+ // or it was killed by a signal before deciding (status null). Neither
110
+ // is an allow the gate chain ever made.
111
+ const err = result.error;
112
+ recordDegraded(
113
+ "delegate-spawn-failed",
114
+ `via=cjs error=${err ? err.code || err.message : "none"} ` +
115
+ `status=${result.status} signal=${result.signal || "none"}`
116
+ );
47
117
  process.exit(FAIL_OPEN_EXIT);
48
118
  }
49
119
  process.exit(result.status);
@@ -104,6 +174,14 @@ function main() {
104
174
 
105
175
  try {
106
176
  main();
107
- } catch {
177
+ } catch (err) {
178
+ // The shim's own last resort. Structurally identical to the
179
+ // `unhandled-fail-open` handler at the bottom of core/hooks/
180
+ // pre_tool_use.py, and previously just as silent: exit 0, empty stdout,
181
+ // nothing anywhere to say the gate chain never ran.
182
+ recordDegraded(
183
+ "unhandled-fail-open",
184
+ `via=cjs ${err && err.stack ? err.stack : String(err)}`
185
+ );
108
186
  process.exit(FAIL_OPEN_EXIT);
109
187
  }
@@ -26,6 +26,14 @@
26
26
  _ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
27
27
  if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
28
28
 
29
+ # A split deploy (wrapper present, _lib absent) must still run the hook —
30
+ # telemetry is an observer, never a dependency. These no-op stubs are
31
+ # defined only when the real ones did not arrive.
32
+ command -v arka_hook_degraded >/dev/null 2>&1 || arka_hook_degraded() { :; }
33
+ command -v arka_run_hook >/dev/null 2>&1 || arka_run_hook() {
34
+ shift; "$ARKA_PY" -m "$1"
35
+ }
36
+
29
37
  # ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
30
38
  # .repo-path can point at a purged npx cache; the shared resolver falls
31
39
  # through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
@@ -44,7 +52,10 @@ fi
44
52
  export ARKAOS_ROOT
45
53
 
46
54
  # ─── Degrade gracefully (fail open, same as before) ─────────────────────
55
+ # Still fail-open, but no longer silent: with no interpreter every gate in
56
+ # this hook allows, and that must be distinguishable from a gate that ran.
47
57
  if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
58
+ arka_hook_degraded "pre-tool-use" "no-interpreter" "ARKA_PY=$ARKA_PY"
48
59
  exit 0
49
60
  fi
50
61
  # Self-root fallback: the wrapper ships next to its python entrypoint, so
@@ -56,6 +67,7 @@ if [ ! -f "$ARKAOS_ROOT/core/hooks/pre_tool_use.py" ]; then
56
67
  ARKAOS_ROOT="$_SELF_ROOT"
57
68
  export ARKAOS_ROOT
58
69
  else
70
+ arka_hook_degraded "pre-tool-use" "entrypoint-missing" "root=$ARKAOS_ROOT"
59
71
  exit 0
60
72
  fi
61
73
  fi
@@ -63,5 +75,10 @@ fi
63
75
  # ─── Single python process; stdin/stdout/stderr/exit-code pass through ──
64
76
  # Interpreter resolution handled by the shared resolver (ARKA_PY): prefers
65
77
  # the ArkaOS venv (has pyyaml/pydantic), falls back to a yaml-capable python3.
66
- PYTHONPATH="$ARKAOS_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
67
- exec "$ARKA_PY" -m core.hooks.pre_tool_use
78
+ #
79
+ # NOT `exec`, unlike every other .sh wrapper here — deliberate, and the
80
+ # trade-off is written out in full at arka_run_hook in _lib/arka_python.sh.
81
+ # Short version: exec replaces this shell with Python, leaving nobody to
82
+ # read the exit status, and the status IS the entrypoint-failed signal.
83
+ export PYTHONPATH="$ARKAOS_ROOT${PYTHONPATH:+:$PYTHONPATH}"
84
+ arka_run_hook "pre-tool-use" core.hooks.pre_tool_use