arkaos 4.13.2 → 4.14.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.
- package/VERSION +1 -1
- package/arka/SKILL.md +16 -0
- package/bin/arka-doctor +20 -1
- package/config/cognition/schedules.yaml +16 -0
- package/config/hooks/_lib/fastpath/engine.cjs +337 -0
- package/config/hooks/gate-manifest.json +741 -0
- package/config/hooks/post-tool-use.cjs +113 -0
- package/config/hooks/pre-tool-use.cjs +109 -0
- package/config/hooks/session-end.ps1 +40 -0
- package/config/hooks/session-end.sh +55 -0
- package/config/hooks/session-start.sh +25 -189
- package/config/hooks/subagent-stop.ps1 +40 -0
- package/config/hooks/subagent-stop.sh +56 -0
- package/config/mcp-policy.yaml +8 -0
- package/config/skills-curated.yaml +39 -0
- package/config/statusline.sh +57 -1
- package/core/cognition/capture/__pycache__/store.cpython-313.pyc +0 -0
- package/core/cognition/capture/store.py +7 -2
- package/core/evals/__pycache__/__init__.cpython-314.pyc +0 -0
- package/core/evals/__pycache__/sanitizer.cpython-314.pyc +0 -0
- package/core/evals/__pycache__/schema.cpython-314.pyc +0 -0
- package/core/evals/__pycache__/verdict_labels.cpython-314.pyc +0 -0
- package/core/forge/__pycache__/complexity.cpython-314.pyc +0 -0
- package/core/governance/__pycache__/evidence_checks.cpython-313.pyc +0 -0
- package/core/governance/__pycache__/judge.cpython-314.pyc +0 -0
- package/core/governance/__pycache__/leak_scanner.cpython-314.pyc +0 -0
- package/core/governance/__pycache__/qg_verdict.cpython-314.pyc +0 -0
- package/core/governance/__pycache__/routing_feedback.cpython-313.pyc +0 -0
- package/core/governance/__pycache__/routing_feedback.cpython-314.pyc +0 -0
- package/core/governance/__pycache__/routing_feedback_cli.cpython-313.pyc +0 -0
- package/core/governance/evidence_checks.py +42 -7
- package/core/governance/routing_feedback.py +229 -0
- package/core/governance/routing_feedback_cli.py +49 -0
- package/core/hooks/__pycache__/_shared.cpython-312.pyc +0 -0
- package/core/hooks/__pycache__/gate_manifest.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/post_tool_use.cpython-312.pyc +0 -0
- package/core/hooks/__pycache__/post_tool_use.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/pre_tool_use.cpython-312.pyc +0 -0
- package/core/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
- package/core/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/stop.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/stop.cpython-314.pyc +0 -0
- package/core/hooks/__pycache__/subagent_stop.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/subagent_stop.cpython-314.pyc +0 -0
- package/core/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
- package/core/hooks/__pycache__/user_prompt_submit.cpython-314.pyc +0 -0
- package/core/hooks/gate_manifest.py +366 -0
- package/core/hooks/post_tool_use.py +5 -2
- package/core/hooks/session_end.py +127 -0
- package/core/hooks/session_start.py +322 -0
- package/core/hooks/stop.py +69 -0
- package/core/hooks/subagent_stop.py +186 -0
- package/core/hooks/user_prompt_submit.py +10 -6
- package/core/knowledge/__pycache__/embedding_backends.cpython-313.pyc +0 -0
- package/core/knowledge/__pycache__/embedding_backends.cpython-314.pyc +0 -0
- package/core/knowledge/__pycache__/pattern_cards.cpython-313.pyc +0 -0
- package/core/knowledge/__pycache__/pattern_cards.cpython-314.pyc +0 -0
- package/core/knowledge/__pycache__/recipes.cpython-314.pyc +0 -0
- package/core/knowledge/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/core/knowledge/__pycache__/vector_store.cpython-314.pyc +0 -0
- package/core/knowledge/embedding_backends.py +278 -0
- package/core/knowledge/pattern_cards.py +49 -1
- package/core/knowledge/vector_store.py +14 -2
- package/core/memory/__pycache__/semantic_store.cpython-312.pyc +0 -0
- package/core/memory/__pycache__/semantic_store.cpython-313.pyc +0 -0
- package/core/memory/__pycache__/semantic_store.cpython-314.pyc +0 -0
- package/core/memory/__pycache__/turn_capture.cpython-313.pyc +0 -0
- package/core/memory/__pycache__/turn_capture.cpython-314.pyc +0 -0
- package/core/memory/semantic_store.py +301 -0
- package/core/memory/turn_capture.py +277 -0
- package/core/registry/__pycache__/generator.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/claude_code.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/codex_cli.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/cost_governor.cpython-314.pyc +0 -0
- package/core/runtime/__pycache__/gemini_cli.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/llm_cost_telemetry.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/mcp_telemetry.cpython-312.pyc +0 -0
- package/core/shared/__pycache__/decay.cpython-313.pyc +0 -0
- package/core/shared/__pycache__/decay.cpython-314.pyc +0 -0
- package/core/shared/__pycache__/sqlite_recovery.cpython-312.pyc +0 -0
- package/core/shared/__pycache__/sqlite_recovery.cpython-313.pyc +0 -0
- package/core/shared/__pycache__/sqlite_recovery.cpython-314.pyc +0 -0
- package/core/shared/decay.py +94 -0
- package/core/shared/sqlite_recovery.py +266 -0
- package/core/synapse/__pycache__/agent_experiences_layer.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/agent_experiences_layer.cpython-314.pyc +0 -0
- package/core/synapse/__pycache__/engine.cpython-312.pyc +0 -0
- package/core/synapse/__pycache__/engine.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/engine.cpython-314.pyc +0 -0
- package/core/synapse/__pycache__/layers.cpython-312.pyc +0 -0
- package/core/synapse/__pycache__/pattern_library_layer.cpython-314.pyc +0 -0
- package/core/synapse/__pycache__/recipe_layer.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/recipe_layer.cpython-314.pyc +0 -0
- package/core/synapse/__pycache__/routing_feedback_layer.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/routing_feedback_layer.cpython-314.pyc +0 -0
- package/core/synapse/__pycache__/session_memory_layer.cpython-312.pyc +0 -0
- package/core/synapse/__pycache__/session_memory_layer.cpython-313.pyc +0 -0
- package/core/synapse/__pycache__/session_memory_layer.cpython-314.pyc +0 -0
- package/core/synapse/agent_experiences_layer.py +42 -3
- package/core/synapse/engine.py +13 -0
- package/core/synapse/recipe_layer.py +27 -4
- package/core/synapse/routing_feedback_layer.py +132 -0
- package/core/synapse/session_memory_layer.py +152 -0
- package/core/workflow/__pycache__/__init__.cpython-312.pyc +0 -0
- package/core/workflow/__pycache__/design_authorization.cpython-314.pyc +0 -0
- package/core/workflow/__pycache__/frontend_gate.cpython-314.pyc +0 -0
- package/core/workflow/__pycache__/specialist_enforcer.cpython-314.pyc +0 -0
- package/installer/adapters/claude-code.js +37 -0
- package/installer/claude-plugins.js +6 -0
- package/installer/cli.js +23 -2
- package/installer/config-seed.js +25 -16
- package/installer/doctor.js +116 -1
- package/installer/hook-lib.js +28 -0
- package/installer/index.js +48 -153
- package/installer/mcp-runner.js +108 -0
- package/installer/skill-deploy.js +189 -0
- package/installer/skills-mode.js +64 -0
- package/installer/update.js +55 -79
- package/knowledge/commands-registry.json.bak +171 -4
- package/knowledge/skills-manifest.json +2337 -0
- package/mcps/arka-prompts/commands.py +451 -0
- package/mcps/arka-prompts/pyproject.toml +15 -0
- package/mcps/arka-prompts/server.py +156 -0
- package/mcps/arka-tools/__pycache__/server.cpython-313.pyc +0 -0
- package/mcps/arka-tools/pyproject.toml +10 -0
- package/mcps/arka-tools/server.py +319 -0
- package/mcps/profiles/base.json +19 -0
- package/mcps/profiles/brand.json +19 -0
- package/mcps/profiles/comms.json +13 -0
- package/mcps/profiles/content.json +20 -0
- package/mcps/profiles/ecommerce.json +13 -0
- package/mcps/profiles/full-stack.json +15 -0
- package/mcps/profiles/laravel.json +12 -0
- package/mcps/profiles/nextjs.json +13 -0
- package/mcps/profiles/nuxt.json +13 -0
- package/mcps/profiles/react.json +12 -0
- package/mcps/profiles/vue.json +12 -0
- package/mcps/registry.json +423 -0
- package/mcps/scripts/apply-mcps.sh +282 -0
- package/mcps/stacks/laravel-packages.json +49 -0
- package/mcps/stacks/react-packages.json +58 -0
- package/package.json +2 -1
- package/pyproject.toml +9 -1
- package/scripts/__pycache__/marketplace_gen.cpython-313.pyc +0 -0
- package/scripts/__pycache__/synapse-bridge.cpython-314.pyc +0 -0
- package/scripts/marketplace_gen.py +310 -0
- package/scripts/tools/__pycache__/docs_stats.cpython-313.pyc +0 -0
- package/scripts/tools/__pycache__/skill_budget.cpython-313.pyc +0 -0
- package/scripts/tools/docs_stats.py +6 -4
- package/scripts/tools/skill_budget.py +209 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* ArkaOS — PostToolUse fast-path shim (F2-6).
|
|
5
|
+
*
|
|
6
|
+
* Fast-exits ("{}", exit 0) only when the manifest proves the Python
|
|
7
|
+
* chain would do exactly that with no pending decision-bearing write:
|
|
8
|
+
* benign exit code, no error-trigger in the output, tool outside the
|
|
9
|
+
* stateful set (ExitPlanMode/Task/Agent), and the flow-auth confirm
|
|
10
|
+
* rescan provably redundant (enforcement off, or confirmed auth fresh).
|
|
11
|
+
* MCP usage telemetry — the one write on this path — is replicated
|
|
12
|
+
* inline. Everything else delegates to the sibling post-tool-use.sh.
|
|
13
|
+
*
|
|
14
|
+
* Kill switch: ARKA_HOOK_FASTPATH=0. Fail-open on internal error: try
|
|
15
|
+
* to delegate; if even that fails, print "{}" and exit 0 — the exact
|
|
16
|
+
* degraded form of post-tool-use.sh (NOTE: differs from the PreToolUse
|
|
17
|
+
* fail-open, which is empty stdout).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require("node:fs");
|
|
21
|
+
const path = require("node:path");
|
|
22
|
+
|
|
23
|
+
function readStdin() {
|
|
24
|
+
try {
|
|
25
|
+
return fs.readFileSync(0, "utf8");
|
|
26
|
+
} catch {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function failOpen() {
|
|
32
|
+
process.stdout.write("{}\n");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function delegate(rawStdin) {
|
|
37
|
+
const sibling = path.join(__dirname, "post-tool-use.sh");
|
|
38
|
+
if (!fs.existsSync(sibling)) {
|
|
39
|
+
// Missing sibling → bash would exit 127; the contract is fail-open
|
|
40
|
+
// with the Post degraded form ("{}").
|
|
41
|
+
failOpen();
|
|
42
|
+
}
|
|
43
|
+
// Lazy require: the fast path never pays for child_process.
|
|
44
|
+
const { spawnSync } = require("node:child_process");
|
|
45
|
+
const result = spawnSync("bash", [sibling], {
|
|
46
|
+
input: rawStdin,
|
|
47
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
48
|
+
env: { ...process.env, ARKA_HOOK_FASTPATH: "0" },
|
|
49
|
+
});
|
|
50
|
+
if (result.error || result.status === null) {
|
|
51
|
+
failOpen();
|
|
52
|
+
}
|
|
53
|
+
process.exit(result.status);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function main() {
|
|
57
|
+
const rawStdin = readStdin();
|
|
58
|
+
if ((process.env.ARKA_HOOK_FASTPATH || "").trim() === "0") {
|
|
59
|
+
delegate(rawStdin);
|
|
60
|
+
}
|
|
61
|
+
// QG B3 (redo 1): the engine require lives INSIDE the fail-open
|
|
62
|
+
// boundary — a split deploy (.cjs present, _lib/fastpath absent)
|
|
63
|
+
// must delegate to the sibling .sh, not crash with a stack trace.
|
|
64
|
+
let engine;
|
|
65
|
+
try {
|
|
66
|
+
engine = require(path.join(__dirname, "_lib", "fastpath", "engine.cjs"));
|
|
67
|
+
} catch {
|
|
68
|
+
delegate(rawStdin);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let payload;
|
|
72
|
+
try {
|
|
73
|
+
payload = JSON.parse(rawStdin);
|
|
74
|
+
} catch {
|
|
75
|
+
payload = null;
|
|
76
|
+
}
|
|
77
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
78
|
+
delegate(rawStdin);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const manifest = engine.readJsonFile(
|
|
82
|
+
fs, path.join(__dirname, "gate-manifest.json")
|
|
83
|
+
).data;
|
|
84
|
+
const homeDir = process.env.HOME || require("node:os").homedir();
|
|
85
|
+
const ctx = {
|
|
86
|
+
homeDir,
|
|
87
|
+
env: process.env,
|
|
88
|
+
fs,
|
|
89
|
+
config: engine.readJsonFile(fs, path.join(homeDir, ".arkaos", "config.json")),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const decision = engine.decidePost(payload, manifest, ctx);
|
|
93
|
+
if (decision.action !== "fast-exit") {
|
|
94
|
+
delegate(rawStdin);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (const write of decision.writes) {
|
|
98
|
+
try {
|
|
99
|
+
fs.mkdirSync(path.dirname(write.path), { recursive: true });
|
|
100
|
+
fs.appendFileSync(write.path, write.line, { flag: "a" });
|
|
101
|
+
} catch {
|
|
102
|
+
// Telemetry must never break the hook.
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
process.stdout.write(decision.stdout + "\n");
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
main();
|
|
111
|
+
} catch {
|
|
112
|
+
failOpen();
|
|
113
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* ArkaOS — PreToolUse fast-path shim (F2-6).
|
|
5
|
+
*
|
|
6
|
+
* An 18ms-p50 Node process (measured; ~10ms of it is bare Node startup)
|
|
7
|
+
* replaces the 82ms-p50 bash->Python chain for the
|
|
8
|
+
* decisions the manifest proves trivial: non-flow-gated tools and
|
|
9
|
+
* discovery Bash with no active budget cap fast-allow here (with the
|
|
10
|
+
* same telemetry appends the Python chain would make); EVERYTHING else
|
|
11
|
+
* delegates to the sibling pre-tool-use.sh, byte-for-byte the current
|
|
12
|
+
* behavior. This shim has no deny path — see engine.cjs invariant #0.
|
|
13
|
+
*
|
|
14
|
+
* Kill switch: ARKA_HOOK_FASTPATH=0 delegates unconditionally (and is
|
|
15
|
+
* re-exported to the child as a recursion guard). Fail-open contract on
|
|
16
|
+
* internal error: try to delegate; if even that fails, exit 0 with
|
|
17
|
+
* empty stdout — identical to pre-tool-use.sh degraded mode.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require("node:fs");
|
|
21
|
+
const path = require("node:path");
|
|
22
|
+
|
|
23
|
+
const FAIL_OPEN_EXIT = 0;
|
|
24
|
+
|
|
25
|
+
function readStdin() {
|
|
26
|
+
try {
|
|
27
|
+
return fs.readFileSync(0, "utf8");
|
|
28
|
+
} catch {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function delegate(rawStdin) {
|
|
34
|
+
const sibling = path.join(__dirname, "pre-tool-use.sh");
|
|
35
|
+
if (!fs.existsSync(sibling)) {
|
|
36
|
+
// Missing sibling → bash would exit 127; the contract is fail-open.
|
|
37
|
+
process.exit(FAIL_OPEN_EXIT);
|
|
38
|
+
}
|
|
39
|
+
// Lazy require: the fast path never pays for child_process.
|
|
40
|
+
const { spawnSync } = require("node:child_process");
|
|
41
|
+
const result = spawnSync("bash", [sibling], {
|
|
42
|
+
input: rawStdin,
|
|
43
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
44
|
+
env: { ...process.env, ARKA_HOOK_FASTPATH: "0" },
|
|
45
|
+
});
|
|
46
|
+
if (result.error || result.status === null) {
|
|
47
|
+
process.exit(FAIL_OPEN_EXIT);
|
|
48
|
+
}
|
|
49
|
+
process.exit(result.status);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function main() {
|
|
53
|
+
const rawStdin = readStdin();
|
|
54
|
+
if ((process.env.ARKA_HOOK_FASTPATH || "").trim() === "0") {
|
|
55
|
+
delegate(rawStdin);
|
|
56
|
+
}
|
|
57
|
+
// QG B3 (redo 1): the engine require lives INSIDE the fail-open
|
|
58
|
+
// boundary — a split deploy (.cjs present, _lib/fastpath absent)
|
|
59
|
+
// must delegate to the sibling .sh, not crash with a stack trace.
|
|
60
|
+
let engine;
|
|
61
|
+
try {
|
|
62
|
+
engine = require(path.join(__dirname, "_lib", "fastpath", "engine.cjs"));
|
|
63
|
+
} catch {
|
|
64
|
+
delegate(rawStdin);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let payload;
|
|
68
|
+
try {
|
|
69
|
+
payload = JSON.parse(rawStdin);
|
|
70
|
+
} catch {
|
|
71
|
+
payload = null;
|
|
72
|
+
}
|
|
73
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
74
|
+
delegate(rawStdin);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const manifest = engine.readJsonFile(
|
|
78
|
+
fs, path.join(__dirname, "gate-manifest.json")
|
|
79
|
+
).data;
|
|
80
|
+
const homeDir = process.env.HOME || require("node:os").homedir();
|
|
81
|
+
const ctx = {
|
|
82
|
+
homeDir,
|
|
83
|
+
env: process.env,
|
|
84
|
+
fs,
|
|
85
|
+
config: engine.readJsonFile(fs, path.join(homeDir, ".arkaos", "config.json")),
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const decision = engine.decidePre(payload, manifest, ctx);
|
|
89
|
+
if (decision.action !== "fast-allow") {
|
|
90
|
+
delegate(rawStdin);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const write of decision.writes) {
|
|
94
|
+
try {
|
|
95
|
+
fs.mkdirSync(path.dirname(write.path), { recursive: true });
|
|
96
|
+
fs.appendFileSync(write.path, write.line, { flag: "a" });
|
|
97
|
+
} catch {
|
|
98
|
+
// Telemetry must never break the hook (same contract as the
|
|
99
|
+
// Python try/except pass around record_telemetry).
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
process.exit(0); // allow: empty stdout, exit 0
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
main();
|
|
107
|
+
} catch {
|
|
108
|
+
process.exit(FAIL_OPEN_EXIT);
|
|
109
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# ArkaOS — SessionEnd Hook (Windows / PowerShell 5.1+)
|
|
3
|
+
#
|
|
4
|
+
# Parity with config/hooks/session-end.sh. Thin wrapper: reads the stdin JSON
|
|
5
|
+
# payload and pipes it to ONE python process (core.hooks.session_end), which
|
|
6
|
+
# owns the entire behaviour. Fail-open: no usable interpreter => exit 0.
|
|
7
|
+
# ============================================================================
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference = 'SilentlyContinue'
|
|
10
|
+
$stdinText = [Console]::In.ReadToEnd()
|
|
11
|
+
|
|
12
|
+
# Shared resolver (venv-first, yaml-verified). Mirrors _lib/arka_python.sh.
|
|
13
|
+
$arkaLib = Join-Path $PSScriptRoot "_lib\arka_python.ps1"
|
|
14
|
+
if (Test-Path -LiteralPath $arkaLib) { . $arkaLib }
|
|
15
|
+
|
|
16
|
+
if (Get-Command Resolve-ArkaRoot -ErrorAction SilentlyContinue) {
|
|
17
|
+
$env:ARKAOS_ROOT = Resolve-ArkaRoot
|
|
18
|
+
} elseif ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
|
|
19
|
+
$repoPathFile = Join-Path $HOME ".arkaos/.repo-path"
|
|
20
|
+
if (Test-Path $repoPathFile) {
|
|
21
|
+
$env:ARKAOS_ROOT = (Get-Content $repoPathFile -Raw).Trim()
|
|
22
|
+
} elseif (Test-Path (Join-Path $HOME ".arkaos")) {
|
|
23
|
+
$env:ARKAOS_ROOT = (Join-Path $HOME ".arkaos")
|
|
24
|
+
} else {
|
|
25
|
+
$env:ARKAOS_ROOT = if ($env:ARKA_OS) { $env:ARKA_OS } else { Join-Path $HOME ".claude/skills/arkaos" }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$pythonExe = $env:ARKA_PY
|
|
30
|
+
if (-not $pythonExe) { exit 0 }
|
|
31
|
+
if (-not (Test-Path -LiteralPath (Join-Path $env:ARKAOS_ROOT "core/hooks/session_end.py"))) {
|
|
32
|
+
$selfRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
|
|
33
|
+
if (Test-Path -LiteralPath (Join-Path $selfRoot "core/hooks/session_end.py")) {
|
|
34
|
+
$env:ARKAOS_ROOT = $selfRoot
|
|
35
|
+
} else { exit 0 }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
$env:PYTHONPATH = "$($env:ARKAOS_ROOT)$([IO.Path]::PathSeparator)$($env:PYTHONPATH)"
|
|
39
|
+
$stdinText | & $pythonExe -m core.hooks.session_end
|
|
40
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# ArkaOS v2 — session-end Hook (thin wrapper, F2-4)
|
|
4
|
+
#
|
|
5
|
+
# Delegates the ENTIRE event to ONE python process:
|
|
6
|
+
# python3 -m core.hooks.session_end
|
|
7
|
+
#
|
|
8
|
+
# Writes a final session digest immediately (PreCompact only fires on
|
|
9
|
+
# compaction) and marks the session ended. Best-effort, never blocks.
|
|
10
|
+
# Fail-open: no usable interpreter => exit 0. Timeout: 15s.
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
# ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
|
|
14
|
+
_ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
|
|
15
|
+
if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
|
|
16
|
+
|
|
17
|
+
# ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
|
|
18
|
+
# .repo-path can point at a purged npx cache; the shared resolver falls
|
|
19
|
+
# through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
|
|
20
|
+
if command -v arka_resolve_root >/dev/null 2>&1; then
|
|
21
|
+
ARKAOS_ROOT="$(arka_resolve_root)"
|
|
22
|
+
elif [ -z "${ARKAOS_ROOT:-}" ]; then
|
|
23
|
+
# Legacy chain (pre-snapshot _lib deployment)
|
|
24
|
+
if [ -f "$HOME/.arkaos/.repo-path" ]; then
|
|
25
|
+
ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
|
|
26
|
+
elif [ -d "$HOME/.arkaos" ]; then
|
|
27
|
+
ARKAOS_ROOT="$HOME/.arkaos"
|
|
28
|
+
else
|
|
29
|
+
ARKAOS_ROOT="${ARKA_OS:-$HOME/.claude/skills/arkaos}"
|
|
30
|
+
fi
|
|
31
|
+
fi
|
|
32
|
+
export ARKAOS_ROOT
|
|
33
|
+
|
|
34
|
+
# ─── Degrade gracefully (fail open, same as before) ─────────────────────
|
|
35
|
+
if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
# Self-root fallback: the wrapper ships next to its python entrypoint, so
|
|
39
|
+
# when ARKAOS_ROOT points at a pre-PR-6 install without core/hooks/, use
|
|
40
|
+
# the root this script lives in.
|
|
41
|
+
if [ ! -f "$ARKAOS_ROOT/core/hooks/session_end.py" ]; then
|
|
42
|
+
_SELF_ROOT="$(cd "$(dirname "$0")/../.." 2>/dev/null && pwd)"
|
|
43
|
+
if [ -n "$_SELF_ROOT" ] && [ -f "$_SELF_ROOT/core/hooks/session_end.py" ]; then
|
|
44
|
+
ARKAOS_ROOT="$_SELF_ROOT"
|
|
45
|
+
export ARKAOS_ROOT
|
|
46
|
+
else
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# ─── Single python process; stdin/stdout/stderr/exit-code pass through ──
|
|
52
|
+
# Interpreter resolution handled by the shared resolver (ARKA_PY): prefers
|
|
53
|
+
# the ArkaOS venv (has pyyaml/pydantic), falls back to a yaml-capable python3.
|
|
54
|
+
PYTHONPATH="$ARKAOS_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
55
|
+
exec "$ARKA_PY" -m core.hooks.session_end
|
|
@@ -1,201 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ============================================================================
|
|
3
|
-
# ArkaOS — SessionStart Hook
|
|
4
|
-
#
|
|
3
|
+
# ArkaOS — SessionStart Hook (thin wrapper, F2-2 hook-hygiene completion)
|
|
4
|
+
#
|
|
5
|
+
# ONE python process (core.hooks.session_start) builds the entire
|
|
6
|
+
# systemMessage — the 13 inline python spawns of the previous version
|
|
7
|
+
# live there now (baseline 251ms p50 before consolidation). This file
|
|
8
|
+
# only resolves the interpreter and execs; with no usable interpreter
|
|
9
|
+
# it emits a static banner and exits 0 (fail-open, stdlib-free).
|
|
5
10
|
# ============================================================================
|
|
6
11
|
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
# _HOOK_CWD captured BEFORE any cd — inside a compound command $PWD
|
|
13
|
+
# would expand after the cd (QG blocker, F1-A3: cross-project leak).
|
|
14
|
+
_HOOK_CWD="$PWD"
|
|
15
|
+
export ARKA_HOOK_CWD="$_HOOK_CWD"
|
|
11
16
|
|
|
12
17
|
# ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
|
|
13
18
|
_ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
|
|
14
19
|
if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
COMPANY=$("$ARKA_PY" -c "import json; print(json.load(open('$HOME/.arkaos/profile.json')).get('company', 'WizardingCode'))" 2>/dev/null || echo "WizardingCode")
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
if [ -f "$HOME/.arkaos/.repo-path" ]; then
|
|
22
|
-
REPO=$(cat "$HOME/.arkaos/.repo-path")
|
|
23
|
-
[ -f "$REPO/VERSION" ] && VERSION=$(cat "$REPO/VERSION" | tr -d '[:space:]')
|
|
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
|
|
30
|
-
|
|
31
|
-
# ─── Static greeting (cache-friendly) ──────────────────────────────────
|
|
32
|
-
# Time-of-day branching removed: it invalidated prompt cache 3x/day without
|
|
33
|
-
# meaningful signal. Static greeting keeps SessionStart output stable.
|
|
34
|
-
GREETING="Olá"
|
|
35
|
-
|
|
36
|
-
# ─── Version drift ─────────────────────────────────────────────────────
|
|
37
|
-
SYNC_STATE="$HOME/.arkaos/sync-state.json"
|
|
38
|
-
DRIFT=""
|
|
39
|
-
|
|
40
|
-
if [ -f "$SYNC_STATE" ]; then
|
|
41
|
-
SYNCED=$("$ARKA_PY" -c "import json; print(json.load(open('$SYNC_STATE'))['version'])" 2>/dev/null || echo "none")
|
|
42
|
-
if [ "$SYNCED" != "$VERSION" ]; then
|
|
43
|
-
DRIFT="\\n[arka:update-available] Core v${VERSION} != synced v${SYNCED}. Run /arka update."
|
|
44
|
-
fi
|
|
45
|
-
else
|
|
46
|
-
DRIFT="\\n[arka:update-available] Never synced. Run /arka update."
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
# ─── Build message ─────────────────────────────────────────────────────
|
|
50
|
-
MSG="\\n╔══════════════════════════════════════════════╗\\n"
|
|
51
|
-
MSG+="║ ║\\n"
|
|
52
|
-
MSG+="║ A R K A O S ║\\n"
|
|
53
|
-
MSG+="║ ║\\n"
|
|
54
|
-
MSG+="║ The Operating System for AI Teams ║\\n"
|
|
55
|
-
MSG+="║ by WizardingCode ║\\n"
|
|
56
|
-
MSG+="║ ║\\n"
|
|
57
|
-
MSG+="╚══════════════════════════════════════════════╝\\n"
|
|
58
|
-
MSG+="\\n"
|
|
59
|
-
MSG+="${GREETING}, ${NAME} (${COMPANY})\\n"
|
|
60
|
-
# ─── Active Workflow ──────────────────────────────────────────────────
|
|
61
|
-
STATE_READER="$REPO/core/workflow/state_reader.sh"
|
|
62
|
-
if [ -n "$REPO" ] && [ -f "$STATE_READER" ] && bash "$STATE_READER" active 2>/dev/null; then
|
|
63
|
-
WF_SUMMARY=$(bash "$STATE_READER" summary 2>/dev/null)
|
|
64
|
-
WF_NAME=$(echo "$WF_SUMMARY" | cut -d'|' -f1)
|
|
65
|
-
WF_PHASE=$(echo "$WF_SUMMARY" | cut -d'|' -f2)
|
|
66
|
-
WF_PROGRESS=$(echo "$WF_SUMMARY" | cut -d'|' -f3)
|
|
67
|
-
WF_BRANCH=$(echo "$WF_SUMMARY" | cut -d'|' -f4)
|
|
68
|
-
WF_VIOLATIONS=$(echo "$WF_SUMMARY" | cut -d'|' -f5)
|
|
69
|
-
MSG+="\\nWorkflow: ${WF_NAME} (${WF_PROGRESS})"
|
|
70
|
-
[ -n "$WF_BRANCH" ] && MSG+=" branch:${WF_BRANCH}"
|
|
71
|
-
[ "$WF_VIOLATIONS" != "0" ] && MSG+=" VIOLATIONS:${WF_VIOLATIONS}"
|
|
72
|
-
MSG+="\\n"
|
|
73
|
-
fi
|
|
74
|
-
|
|
75
|
-
# --- Forge Plan Display ---
|
|
76
|
-
_FORGE_PLANS="$HOME/.arkaos/plans"
|
|
77
|
-
_FORGE_ACTIVE="$_FORGE_PLANS/active.yaml"
|
|
78
|
-
_FORGE_LINE=""
|
|
79
|
-
|
|
80
|
-
if [ -f "$_FORGE_ACTIVE" ]; then
|
|
81
|
-
_FORGE_ID=$(cat "$_FORGE_ACTIVE" 2>/dev/null)
|
|
82
|
-
_FORGE_FILE="$_FORGE_PLANS/${_FORGE_ID}.yaml"
|
|
83
|
-
if [ -f "$_FORGE_FILE" ] && command -v "$ARKA_PY" >/dev/null 2>&1; then
|
|
84
|
-
_FORGE_NAME=$(FORGE_FILE="$_FORGE_FILE" "$ARKA_PY" -c "import yaml,os; d=yaml.safe_load(open(os.environ['FORGE_FILE'])); print(d.get('name',''))" 2>/dev/null)
|
|
85
|
-
_FORGE_STATUS=$(FORGE_FILE="$_FORGE_FILE" "$ARKA_PY" -c "import yaml,os; d=yaml.safe_load(open(os.environ['FORGE_FILE'])); print(d.get('status',''))" 2>/dev/null)
|
|
86
|
-
_FORGE_PHASES=$(FORGE_FILE="$_FORGE_FILE" "$ARKA_PY" -c "import yaml,os; d=yaml.safe_load(open(os.environ['FORGE_FILE'])); print(len(d.get('plan_phases',[])))" 2>/dev/null)
|
|
87
|
-
_FORGE_BRANCH=$(FORGE_FILE="$_FORGE_FILE" "$ARKA_PY" -c "import yaml,os; d=yaml.safe_load(open(os.environ['FORGE_FILE'])); print(d.get('governance',{}).get('branch_strategy',''))" 2>/dev/null)
|
|
88
|
-
|
|
89
|
-
if [ "$_FORGE_STATUS" = "approved" ]; then
|
|
90
|
-
_FORGE_LINE=" ⚒ Forge plan pending: ${_FORGE_NAME} | Phases: ${_FORGE_PHASES} | /forge resume"
|
|
91
|
-
elif [ "$_FORGE_STATUS" = "executing" ]; then
|
|
92
|
-
_FORGE_LINE=" ⚒ Forge executing: ${_FORGE_NAME} | Phases: ${_FORGE_PHASES} | Branch: ${_FORGE_BRANCH}"
|
|
93
|
-
fi
|
|
94
|
-
fi
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
# Counts intentionally omitted (prompt-surface P0 2026-07-08): hand-typed
|
|
98
|
-
# numbers drift from docs_stats.py truth and change no model behavior.
|
|
99
|
-
MSG+="ArkaOS v${VERSION}"
|
|
100
|
-
[ -n "$_FORGE_LINE" ] && MSG+="\\n${_FORGE_LINE}"
|
|
101
|
-
MSG+="${DRIFT}"
|
|
102
|
-
|
|
103
|
-
# ─── Evidence Flow Contract (top-of-session, highest priority) ──────────
|
|
104
|
-
MSG+="\\n\\n[ARKA:EVIDENCE-FLOW] NON-NEGOTIABLE. Every non-trivial request runs the 4-gate evidence flow (constitution rule evidence-flow; source arka/skills/flow/SKILL.md):"
|
|
105
|
-
MSG+="\\n G1 CONTEXT ([arka:routing] <dept> -> <lead> + KB/graph grounding, cite or declare gap)"
|
|
106
|
-
MSG+="\\n G2 PLAN (short plan -> EXPLICIT user approval; silence != approval)"
|
|
107
|
-
MSG+="\\n G3 EXECUTE (closes only with real test run on record: command + exit 0)"
|
|
108
|
-
MSG+="\\n G4 REVIEW (executable checks: lint/type/coverage/security/spell -> honest summary)"
|
|
109
|
-
MSG+="\\nEmit [arka:gate:N] at each gate start. Gates pass on evidence, never on narration."
|
|
110
|
-
MSG+="\\nBypass ONLY via [arka:trivial] <reason> for single-file edits under 10 lines."
|
|
111
|
-
|
|
112
|
-
# ─── Transparency tag contract (PR12 v2.34.0) ───────────────────────────
|
|
113
|
-
MSG+="\\n\\n[ARKA:META-TAG] Every substantive response ends with a single line:"
|
|
114
|
-
MSG+="\\n [arka:meta] kb=N research=X persona=Y gap=Z critic=W"
|
|
115
|
-
MSG+="\\nFields: kb=N (Obsidian/KB notes consulted), research=X (MCPs invoked: perplexity,exa,context7,firecrawl,xmcp or 'none'), persona=Y (advisor name or 'orchestrator'), gap=Z (KB gap topic or 'none'), critic=W (passed|failed|skipped)."
|
|
116
|
-
MSG+="\\nMandatory after: EFFECT tool calls, plan/recommendation outputs, QG verdicts. Optional for pure read-only status replies."
|
|
117
|
-
MSG+="\\nAbsence is measured by the Stop hook (warn-only in v2.34.0) before promotion to hard enforcement."
|
|
118
|
-
|
|
119
|
-
# ─── Model Fabric routing (consumption layer) ───────────────────────────
|
|
120
|
-
# Feed the operator's ~/.arkaos/models.yaml back to the orchestrator so
|
|
121
|
-
# dashboard/CLI model choices actually govern agent dispatch. Cheap
|
|
122
|
-
# (single python read); skipped silently if the config can't be resolved.
|
|
123
|
-
if [ -n "$REPO" ]; then
|
|
124
|
-
# ARKA_PY already resolves to the venv python (has pydantic + yaml); the
|
|
125
|
-
# ambient python3 usually lacks them and routing_directive() would return "".
|
|
126
|
-
if command -v "$ARKA_PY" >/dev/null 2>&1 || [ -x "$ARKA_PY" ]; then
|
|
127
|
-
_MF_DIRECTIVE=$(cd "$REPO" && PYTHONPATH="$REPO" "$ARKA_PY" -c "
|
|
128
|
-
try:
|
|
129
|
-
from core.runtime.model_routing_context import routing_directive
|
|
130
|
-
print(routing_directive())
|
|
131
|
-
except Exception:
|
|
132
|
-
pass
|
|
133
|
-
" 2>/dev/null)
|
|
134
|
-
if [ -n "$_MF_DIRECTIVE" ]; then
|
|
135
|
-
MSG+="\\n\\n${_MF_DIRECTIVE}"
|
|
136
|
-
fi
|
|
137
|
-
fi
|
|
138
|
-
fi
|
|
139
|
-
|
|
140
|
-
# ─── Stale-aware reorganizer trigger (PR24 v2.46.0) ─────────────────────
|
|
141
|
-
# If today's proposal file is missing, fire the reorganizer in the
|
|
142
|
-
# background with a 30s timeout. Best-effort, never blocks session
|
|
143
|
-
# start. Multiple sessions per day no-op because the file now exists.
|
|
144
|
-
if [ -n "$REPO" ] && command -v "$ARKA_PY" >/dev/null 2>&1; then
|
|
145
|
-
_PROPOSAL_DIR="$HOME/.arkaos/reorganize-proposals"
|
|
146
|
-
_TODAY="$(date -u +%Y-%m-%d).md"
|
|
147
|
-
if [ ! -f "$_PROPOSAL_DIR/$_TODAY" ]; then
|
|
148
|
-
(
|
|
149
|
-
cd "$REPO" && timeout 30s "$ARKA_PY" -m core.cognition.reorganizer_cli >/dev/null 2>&1
|
|
150
|
-
) &
|
|
151
|
-
disown 2>/dev/null || true
|
|
152
|
-
fi
|
|
153
|
-
fi
|
|
154
|
-
|
|
155
|
-
# ─── Dashboard ensure (v4.1.2) ──────────────────────────────────────────
|
|
156
|
-
# Safety net for the login autostart (`npx arkaos autostart enable`): if the
|
|
157
|
-
# dashboard is healthy this is two curl health checks (~50ms); if not, it
|
|
158
|
-
# starts API+UI. Background + disown so it never touches the 5s budget.
|
|
159
|
-
# Toggle off: ~/.arkaos/config.json -> {"dashboard": {"ensure_on_session": false}}
|
|
160
|
-
if [ -n "$REPO" ] && [ -f "$REPO/scripts/start-dashboard.sh" ]; then
|
|
161
|
-
_DASH_ENSURE=$("$ARKA_PY" -c "import json; print(json.load(open('$HOME/.arkaos/config.json')).get('dashboard',{}).get('ensure_on_session', True))" 2>/dev/null || echo "True")
|
|
162
|
-
if [ "$_DASH_ENSURE" = "True" ] || [ "$_DASH_ENSURE" = "true" ]; then
|
|
163
|
-
mkdir -p "$HOME/.arkaos/logs"
|
|
164
|
-
(
|
|
165
|
-
# GNU `timeout` is absent on stock macOS — degrade to an unbounded
|
|
166
|
-
# run; the launcher itself is bounded (health wait + start).
|
|
167
|
-
if command -v timeout >/dev/null 2>&1; then
|
|
168
|
-
ARKAOS_NO_BROWSER=1 timeout 90s bash "$REPO/scripts/start-dashboard.sh" ensure >> "$HOME/.arkaos/logs/dashboard-ensure.log" 2>&1
|
|
169
|
-
else
|
|
170
|
-
ARKAOS_NO_BROWSER=1 bash "$REPO/scripts/start-dashboard.sh" ensure >> "$HOME/.arkaos/logs/dashboard-ensure.log" 2>&1
|
|
171
|
-
fi
|
|
172
|
-
) &
|
|
173
|
-
disown 2>/dev/null || true
|
|
174
|
-
fi
|
|
175
|
-
fi
|
|
21
|
+
REPO=""
|
|
22
|
+
[ -f "$HOME/.arkaos/.repo-path" ] && REPO=$(cat "$HOME/.arkaos/.repo-path")
|
|
176
23
|
|
|
177
|
-
#
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
ctx = build_resume_context()
|
|
185
|
-
if ctx:
|
|
186
|
-
print('\\n[SESSION] ' + ctx.replace('\\n', '\\n[SESSION] '))
|
|
187
|
-
except Exception:
|
|
188
|
-
pass
|
|
189
|
-
" 2>/dev/null)
|
|
190
|
-
[ -n "$_SESSION_CTX" ] && MSG+="\\n${_SESSION_CTX}"
|
|
24
|
+
# The MODULE file is the guard, not just core/: an older installed
|
|
25
|
+
# snapshot without it would exec into "No module named ..." (exit 1,
|
|
26
|
+
# empty output — a broken SessionStart instead of a degraded banner).
|
|
27
|
+
if [ -n "$REPO" ] && [ -f "$REPO/core/hooks/session_start.py" ] \
|
|
28
|
+
&& command -v "$ARKA_PY" >/dev/null 2>&1; then
|
|
29
|
+
cd "$REPO" 2>/dev/null || true
|
|
30
|
+
PYTHONPATH="$REPO" exec "$ARKA_PY" -m core.hooks.session_start
|
|
191
31
|
fi
|
|
192
32
|
|
|
193
|
-
# ───
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
ARKA_MSG="$(echo -e "$MSG")" "$ARKA_PY" -c "
|
|
199
|
-
import json, os
|
|
200
|
-
print(json.dumps({'systemMessage': os.environ['ARKA_MSG']}))
|
|
201
|
-
"
|
|
33
|
+
# ─── Degraded fallback: static banner, valid JSON, exit 0 ──────────────
|
|
34
|
+
cat <<'EOF'
|
|
35
|
+
{"systemMessage": "\n╔══════════════════════════════════════════════╗\n║ A R K A O S ║\n║ The Operating System for AI Teams ║\n╚══════════════════════════════════════════════╝\nOlá, founder (WizardingCode)\nArkaOS (degraded: no usable interpreter — run npx arkaos doctor)"}
|
|
36
|
+
EOF
|
|
37
|
+
exit 0
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# ArkaOS — SubagentStop Hook (Windows / PowerShell 5.1+)
|
|
3
|
+
#
|
|
4
|
+
# Parity with config/hooks/subagent-stop.sh. Thin wrapper: reads the stdin JSON
|
|
5
|
+
# payload and pipes it to ONE python process (core.hooks.subagent_stop), which
|
|
6
|
+
# owns the entire behaviour. Fail-open: no usable interpreter => exit 0.
|
|
7
|
+
# ============================================================================
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference = 'SilentlyContinue'
|
|
10
|
+
$stdinText = [Console]::In.ReadToEnd()
|
|
11
|
+
|
|
12
|
+
# Shared resolver (venv-first, yaml-verified). Mirrors _lib/arka_python.sh.
|
|
13
|
+
$arkaLib = Join-Path $PSScriptRoot "_lib\arka_python.ps1"
|
|
14
|
+
if (Test-Path -LiteralPath $arkaLib) { . $arkaLib }
|
|
15
|
+
|
|
16
|
+
if (Get-Command Resolve-ArkaRoot -ErrorAction SilentlyContinue) {
|
|
17
|
+
$env:ARKAOS_ROOT = Resolve-ArkaRoot
|
|
18
|
+
} elseif ([string]::IsNullOrWhiteSpace($env:ARKAOS_ROOT)) {
|
|
19
|
+
$repoPathFile = Join-Path $HOME ".arkaos/.repo-path"
|
|
20
|
+
if (Test-Path $repoPathFile) {
|
|
21
|
+
$env:ARKAOS_ROOT = (Get-Content $repoPathFile -Raw).Trim()
|
|
22
|
+
} elseif (Test-Path (Join-Path $HOME ".arkaos")) {
|
|
23
|
+
$env:ARKAOS_ROOT = (Join-Path $HOME ".arkaos")
|
|
24
|
+
} else {
|
|
25
|
+
$env:ARKAOS_ROOT = if ($env:ARKA_OS) { $env:ARKA_OS } else { Join-Path $HOME ".claude/skills/arkaos" }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$pythonExe = $env:ARKA_PY
|
|
30
|
+
if (-not $pythonExe) { exit 0 }
|
|
31
|
+
if (-not (Test-Path -LiteralPath (Join-Path $env:ARKAOS_ROOT "core/hooks/subagent_stop.py"))) {
|
|
32
|
+
$selfRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
|
|
33
|
+
if (Test-Path -LiteralPath (Join-Path $selfRoot "core/hooks/subagent_stop.py")) {
|
|
34
|
+
$env:ARKAOS_ROOT = $selfRoot
|
|
35
|
+
} else { exit 0 }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
$env:PYTHONPATH = "$($env:ARKAOS_ROOT)$([IO.Path]::PathSeparator)$($env:PYTHONPATH)"
|
|
39
|
+
$stdinText | & $pythonExe -m core.hooks.subagent_stop
|
|
40
|
+
exit 0
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# ArkaOS v2 — subagent-stop Hook (thin wrapper, F2-4)
|
|
4
|
+
#
|
|
5
|
+
# Delegates the ENTIRE event to ONE python process:
|
|
6
|
+
# python3 -m core.hooks.subagent_stop
|
|
7
|
+
#
|
|
8
|
+
# Persists each dispatched subagent's output + runs warn-only honesty
|
|
9
|
+
# checks (phantom-action, meta-tag), nudging deliverable-shaped output
|
|
10
|
+
# toward the Quality Gate. Never blocks (the subagent already ran).
|
|
11
|
+
# Fail-open: no usable interpreter => exit 0. Timeout: 10s.
|
|
12
|
+
# ============================================================================
|
|
13
|
+
|
|
14
|
+
# ─── Shared Python resolver (exports ARKA_PY) ──────────────────────────
|
|
15
|
+
_ARKA_LIB="$(dirname "${BASH_SOURCE[0]:-$0}")/_lib/arka_python.sh"
|
|
16
|
+
if [ -f "$_ARKA_LIB" ]; then . "$_ARKA_LIB"; else ARKA_PY="python3"; fi
|
|
17
|
+
|
|
18
|
+
# ─── Resolve ARKAOS_ROOT (validated — see arka_resolve_root in _lib) ────
|
|
19
|
+
# .repo-path can point at a purged npx cache; the shared resolver falls
|
|
20
|
+
# through to the ~/.arkaos/lib snapshot instead of exporting a dead root.
|
|
21
|
+
if command -v arka_resolve_root >/dev/null 2>&1; then
|
|
22
|
+
ARKAOS_ROOT="$(arka_resolve_root)"
|
|
23
|
+
elif [ -z "${ARKAOS_ROOT:-}" ]; then
|
|
24
|
+
# Legacy chain (pre-snapshot _lib deployment)
|
|
25
|
+
if [ -f "$HOME/.arkaos/.repo-path" ]; then
|
|
26
|
+
ARKAOS_ROOT=$(cat "$HOME/.arkaos/.repo-path")
|
|
27
|
+
elif [ -d "$HOME/.arkaos" ]; then
|
|
28
|
+
ARKAOS_ROOT="$HOME/.arkaos"
|
|
29
|
+
else
|
|
30
|
+
ARKAOS_ROOT="${ARKA_OS:-$HOME/.claude/skills/arkaos}"
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
export ARKAOS_ROOT
|
|
34
|
+
|
|
35
|
+
# ─── Degrade gracefully (fail open, same as before) ─────────────────────
|
|
36
|
+
if ! command -v "$ARKA_PY" >/dev/null 2>&1; then
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
# Self-root fallback: the wrapper ships next to its python entrypoint, so
|
|
40
|
+
# when ARKAOS_ROOT points at a pre-PR-6 install without core/hooks/, use
|
|
41
|
+
# the root this script lives in.
|
|
42
|
+
if [ ! -f "$ARKAOS_ROOT/core/hooks/subagent_stop.py" ]; then
|
|
43
|
+
_SELF_ROOT="$(cd "$(dirname "$0")/../.." 2>/dev/null && pwd)"
|
|
44
|
+
if [ -n "$_SELF_ROOT" ] && [ -f "$_SELF_ROOT/core/hooks/subagent_stop.py" ]; then
|
|
45
|
+
ARKAOS_ROOT="$_SELF_ROOT"
|
|
46
|
+
export ARKAOS_ROOT
|
|
47
|
+
else
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# ─── Single python process; stdin/stdout/stderr/exit-code pass through ──
|
|
53
|
+
# Interpreter resolution handled by the shared resolver (ARKA_PY): prefers
|
|
54
|
+
# the ArkaOS venv (has pyyaml/pydantic), falls back to a yaml-capable python3.
|
|
55
|
+
PYTHONPATH="$ARKAOS_ROOT${PYTHONPATH:+:$PYTHONPATH}" \
|
|
56
|
+
exec "$ARKA_PY" -m core.hooks.subagent_stop
|