arkaos 4.3.1 → 4.3.3
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/README.md +1 -1
- package/VERSION +1 -1
- package/arka/SKILL.md +4 -4
- package/arka/skills/costs/SKILL.md +1 -1
- package/arka/skills/fusion/SKILL.md +3 -3
- package/bin/arka +225 -0
- package/bin/arka-claude +64 -0
- package/bin/arka-claude.cmd +11 -0
- package/bin/arka-claude.ps1 +126 -0
- package/bin/arka-doctor +391 -0
- package/bin/arka-providers +261 -0
- package/bin/arka-py +46 -0
- package/bin/arka-py.cmd +9 -0
- package/bin/arka-py.ps1 +36 -0
- package/bin/arka-registry-gen +185 -0
- package/bin/arka-skill +300 -0
- package/bin/scheduler-daemon.py +48 -0
- package/config/claude-agents/marta-cqo.md +1 -1
- package/config/claude-agents/paulo-tech-lead.md +1 -1
- package/config/constitution.yaml +5 -5
- package/config/hooks/_lib/arka_python.ps1 +43 -0
- package/config/hooks/_lib/arka_python.sh +63 -0
- package/config/hooks/agent-provision.sh +8 -1
- package/config/hooks/cwd-changed.sh +6 -2
- package/config/hooks/post-tool-use-v2.sh +6 -2
- package/config/hooks/post-tool-use.sh +8 -17
- package/config/hooks/pre-tool-use.ps1 +8 -6
- package/config/hooks/pre-tool-use.sh +8 -17
- package/config/hooks/session-start.sh +23 -21
- package/config/hooks/stop.ps1 +7 -5
- package/config/hooks/stop.sh +8 -17
- package/config/hooks/token-hygiene.sh +5 -1
- package/config/hooks/user-prompt-submit-v2.sh +13 -9
- package/config/hooks/user-prompt-submit.sh +8 -17
- package/core/hooks/__pycache__/post_tool_use.cpython-312.pyc +0 -0
- package/core/hooks/__pycache__/pre_tool_use.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/cost_governor.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/llm_provider.cpython-312.pyc +0 -0
- package/core/runtime/__pycache__/openrouter_provider.cpython-312.pyc +0 -0
- package/core/workflow/state_reader.sh +12 -5
- package/departments/ops/skills/update/SKILL.md +2 -2
- package/departments/ops/skills/update/references/sync-engine.md +1 -1
- package/departments/quality/SKILL.md +1 -1
- package/installer/index.js +14 -0
- package/installer/update.js +31 -0
- package/package.json +6 -3
- package/pyproject.toml +1 -1
- package/scripts/seed_initial_patterns.py +1 -1
package/bin/arka-py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# ArkaOS — Python entrypoint for agents and scripts.
|
|
4
|
+
#
|
|
5
|
+
# Resolves the ArkaOS interpreter (venv-first, via the shared resolver) and
|
|
6
|
+
# execs it, so callers never depend on the ambient `python` having ArkaOS
|
|
7
|
+
# deps (pyyaml, pydantic, ...). This is what SKILL.md commands invoke instead
|
|
8
|
+
# of a bare `python -m core...` — the failure mode that broke `/arka update`
|
|
9
|
+
# when the session's `python` had no yaml.
|
|
10
|
+
#
|
|
11
|
+
# Usage: arka-py -m core.sync.update_orchestrator ...
|
|
12
|
+
# arka-py path/to/script.py ...
|
|
13
|
+
# arka-py -c "import core; ..."
|
|
14
|
+
# ============================================================================
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# ─── Source the shared resolver, from the repo or the installed location ──
|
|
18
|
+
_self="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
|
19
|
+
for _lib in \
|
|
20
|
+
"$_self/../config/hooks/_lib/arka_python.sh" \
|
|
21
|
+
"$HOME/.arkaos/config/hooks/_lib/arka_python.sh"; do
|
|
22
|
+
if [ -f "$_lib" ]; then
|
|
23
|
+
# shellcheck source=/dev/null
|
|
24
|
+
# The resolver's ARKA_PY assignment is `|| true`-guarded internally, so
|
|
25
|
+
# sourcing never aborts under `set -e` even when it falls back.
|
|
26
|
+
. "$_lib"
|
|
27
|
+
break
|
|
28
|
+
fi
|
|
29
|
+
done
|
|
30
|
+
: "${ARKA_PY:=python3}"
|
|
31
|
+
|
|
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).
|
|
35
|
+
_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)"
|
|
41
|
+
fi
|
|
42
|
+
if [ -n "$_root" ] && [ -d "$_root" ]; then
|
|
43
|
+
export PYTHONPATH="${_root}${PYTHONPATH:+:$PYTHONPATH}"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
exec "$ARKA_PY" "$@"
|
package/bin/arka-py.cmd
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM ==========================================================================
|
|
3
|
+
REM ArkaOS - Python entrypoint (cmd shim)
|
|
4
|
+
REM
|
|
5
|
+
REM Dispatches to bin\arka-py.ps1, forwarding all arguments, so `arka-py ...`
|
|
6
|
+
REM works from cmd.exe, PowerShell, and Windows Terminal alike.
|
|
7
|
+
REM ==========================================================================
|
|
8
|
+
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%~dp0arka-py.ps1" %*
|
|
9
|
+
exit /b %ERRORLEVEL%
|
package/bin/arka-py.ps1
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# ArkaOS - Python entrypoint (Windows / PowerShell 5.1+)
|
|
3
|
+
#
|
|
4
|
+
# Port of bin/arka-py. Resolves the ArkaOS interpreter (venv-first, via the
|
|
5
|
+
# shared PowerShell resolver) and execs it, so SKILL.md commands never run a
|
|
6
|
+
# bare `python` that lacks ArkaOS deps (pyyaml, ...).
|
|
7
|
+
#
|
|
8
|
+
# Usage: arka-py -m core.sync.update_orchestrator ...
|
|
9
|
+
# Normally invoked through its .cmd shim (bin/arka-py.cmd).
|
|
10
|
+
# ============================================================================
|
|
11
|
+
$ErrorActionPreference = "Stop"
|
|
12
|
+
|
|
13
|
+
# ─── Source the shared resolver, from the repo or the installed location ──
|
|
14
|
+
$self = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
|
|
15
|
+
$libs = @(
|
|
16
|
+
(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")
|
|
18
|
+
)
|
|
19
|
+
foreach ($lib in $libs) {
|
|
20
|
+
if (Test-Path -LiteralPath $lib) { . $lib; break }
|
|
21
|
+
}
|
|
22
|
+
if (-not $env:ARKA_PY) { $env:ARKA_PY = "python" }
|
|
23
|
+
|
|
24
|
+
# ─── Make `-m core.*` resolvable regardless of cwd ────────────────────────
|
|
25
|
+
$root = $env:ARKAOS_ROOT
|
|
26
|
+
if (-not $root) {
|
|
27
|
+
$rp = Join-Path (if ($env:USERPROFILE) { $env:USERPROFILE } else { $HOME }) ".arkaos\.repo-path"
|
|
28
|
+
if (Test-Path -LiteralPath $rp) { $root = (Get-Content -LiteralPath $rp -Raw).Trim() }
|
|
29
|
+
}
|
|
30
|
+
if ($root -and (Test-Path -LiteralPath $root)) {
|
|
31
|
+
$sep = [IO.Path]::PathSeparator
|
|
32
|
+
$env:PYTHONPATH = if ($env:PYTHONPATH) { "$root$sep$env:PYTHONPATH" } else { $root }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
& $env:ARKA_PY @args
|
|
36
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# ARKA OS — Commands Registry Generator
|
|
4
|
+
# Scans SKILL.md files + keyword data to generate commands-registry.json
|
|
5
|
+
# Usage: bash bin/arka-registry-gen
|
|
6
|
+
# ============================================================================
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
11
|
+
KEYWORDS_FILE="$REPO_DIR/knowledge/commands-keywords.json"
|
|
12
|
+
OUTPUT_FILE="$REPO_DIR/knowledge/commands-registry.json"
|
|
13
|
+
ARKA_OS="${ARKA_OS:-$HOME/.claude/skills/arka}"
|
|
14
|
+
TEMP_COMMANDS=$(mktemp)
|
|
15
|
+
trap 'rm -f "$TEMP_COMMANDS"' EXIT
|
|
16
|
+
|
|
17
|
+
# Require jq
|
|
18
|
+
command -v jq &>/dev/null || { echo "Error: jq is required. Install: brew install jq"; exit 1; }
|
|
19
|
+
|
|
20
|
+
# ─── Helper: Map department directory name to command prefix ───────────────
|
|
21
|
+
dept_prefix_for() {
|
|
22
|
+
case "$1" in
|
|
23
|
+
dev) echo "dev" ;;
|
|
24
|
+
marketing) echo "mkt" ;;
|
|
25
|
+
ecommerce) echo "ecom" ;;
|
|
26
|
+
finance) echo "fin" ;;
|
|
27
|
+
operations) echo "ops" ;;
|
|
28
|
+
strategy) echo "strat" ;;
|
|
29
|
+
knowledge) echo "kb" ;;
|
|
30
|
+
brand) echo "brand" ;;
|
|
31
|
+
*) echo "$1" ;;
|
|
32
|
+
esac
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# ─── Helper: Detect metadata for a command ─────────────────────────────────
|
|
36
|
+
get_metadata() {
|
|
37
|
+
local command="$1"
|
|
38
|
+
local rw="false" mc="false" tier=2
|
|
39
|
+
|
|
40
|
+
case "$command" in
|
|
41
|
+
"/dev feature"*|"/dev api"*|"/dev debug"*|"/dev refactor"*|"/dev db"*)
|
|
42
|
+
rw="true"; mc="true"; tier=1 ;;
|
|
43
|
+
"/dev scaffold"*|"/dev deploy"*|"/dev test"*)
|
|
44
|
+
mc="true" ;;
|
|
45
|
+
"/dev security-audit"*)
|
|
46
|
+
tier=1 ;;
|
|
47
|
+
esac
|
|
48
|
+
echo "$rw $mc $tier"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# ─── Helper: Extract commands from a SKILL.md file ────────────────────────
|
|
52
|
+
# Parses markdown tables: | `/<prefix> <command> [args]` | description |
|
|
53
|
+
extract_commands() {
|
|
54
|
+
local file="$1"
|
|
55
|
+
local department="$2"
|
|
56
|
+
local source="${3:-builtin}"
|
|
57
|
+
|
|
58
|
+
[ -f "$file" ] || return 0
|
|
59
|
+
|
|
60
|
+
# Extract lead agent from frontmatter
|
|
61
|
+
local lead_agent=""
|
|
62
|
+
lead_agent=$(sed -n '/^---$/,/^---$/{ /^name:/s/.*: *//p; }' "$file" 2>/dev/null | head -1 | xargs 2>/dev/null || echo "")
|
|
63
|
+
|
|
64
|
+
# Parse command table rows
|
|
65
|
+
# Match: | `/<word> <word>...` | description |
|
|
66
|
+
# The backtick-wrapped command must START with / immediately after the backtick
|
|
67
|
+
grep -E '^\| *`/[a-z]' "$file" 2>/dev/null | while IFS= read -r line; do
|
|
68
|
+
# Extract command from backticks
|
|
69
|
+
local command
|
|
70
|
+
command=$(echo "$line" | sed -n 's/.*`\(\/[^`]*\)`.*/\1/p' | xargs 2>/dev/null)
|
|
71
|
+
[ -z "$command" ] && continue
|
|
72
|
+
|
|
73
|
+
# Extract description (second column)
|
|
74
|
+
local description
|
|
75
|
+
description=$(echo "$line" | sed 's/^[^|]*|[^|]*| *//' | sed 's/ *|.*//' | sed 's/^ *//;s/ *$//' | sed 's/^— *//;s/^- *//')
|
|
76
|
+
[ -z "$description" ] && continue
|
|
77
|
+
# Skip if description looks like a separator
|
|
78
|
+
echo "$description" | grep -qE '^[-]+$' && continue
|
|
79
|
+
|
|
80
|
+
# Generate command ID: /dev feature <desc> -> dev-feature
|
|
81
|
+
local id
|
|
82
|
+
id=$(echo "$command" | sed 's/ *<[^>]*>//g' | sed 's/ *\[.*//g' | sed 's/^\/\([^ ]*\) *\(.*\)/\1-\2/' | sed 's/-$//' | sed 's/ /-/g')
|
|
83
|
+
[ -z "$id" ] && continue
|
|
84
|
+
|
|
85
|
+
# Get metadata
|
|
86
|
+
local meta
|
|
87
|
+
meta=$(get_metadata "$command")
|
|
88
|
+
local rw mc tier
|
|
89
|
+
rw=$(echo "$meta" | cut -d' ' -f1)
|
|
90
|
+
mc=$(echo "$meta" | cut -d' ' -f2)
|
|
91
|
+
tier=$(echo "$meta" | cut -d' ' -f3)
|
|
92
|
+
|
|
93
|
+
# Output JSON line
|
|
94
|
+
jq -nc \
|
|
95
|
+
--arg id "$id" \
|
|
96
|
+
--arg command "$command" \
|
|
97
|
+
--arg department "$department" \
|
|
98
|
+
--arg description "$description" \
|
|
99
|
+
--arg lead_agent "$lead_agent" \
|
|
100
|
+
--argjson tier "$tier" \
|
|
101
|
+
--argjson requires_branch "$rw" \
|
|
102
|
+
--argjson modifies_code "$mc" \
|
|
103
|
+
--arg source "$source" \
|
|
104
|
+
'{id:$id,command:$command,department:$department,description:$description,lead_agent:$lead_agent,tier:$tier,requires_branch:$requires_branch,modifies_code:$modifies_code,keywords:[],examples:[],source:$source}'
|
|
105
|
+
done
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# ─── Collect commands from all SKILL.md files ─────────────────────────────
|
|
109
|
+
|
|
110
|
+
# Main orchestrator
|
|
111
|
+
extract_commands "$REPO_DIR/arka/SKILL.md" "arka" >> "$TEMP_COMMANDS"
|
|
112
|
+
|
|
113
|
+
# Department SKILL.md files
|
|
114
|
+
for dept_dir in "$REPO_DIR"/departments/*/; do
|
|
115
|
+
[ -d "$dept_dir" ] || continue
|
|
116
|
+
dept_name=$(basename "$dept_dir")
|
|
117
|
+
dept_prefix=$(dept_prefix_for "$dept_name")
|
|
118
|
+
|
|
119
|
+
# Main department skill
|
|
120
|
+
[ -f "${dept_dir}SKILL.md" ] && extract_commands "${dept_dir}SKILL.md" "$dept_prefix" >> "$TEMP_COMMANDS"
|
|
121
|
+
|
|
122
|
+
# Sub-skills
|
|
123
|
+
for sub_skill in "${dept_dir}skills"/*/SKILL.md; do
|
|
124
|
+
[ -f "$sub_skill" ] || continue
|
|
125
|
+
extract_commands "$sub_skill" "$dept_prefix" >> "$TEMP_COMMANDS"
|
|
126
|
+
done
|
|
127
|
+
done
|
|
128
|
+
|
|
129
|
+
# External skills
|
|
130
|
+
for ext_skill in "$HOME/.claude/skills"/arka-ext-*/SKILL.md; do
|
|
131
|
+
[ -f "$ext_skill" ] || continue
|
|
132
|
+
ext_name=$(basename "$(dirname "$ext_skill")" | sed 's/^arka-ext-//')
|
|
133
|
+
extract_commands "$ext_skill" "$ext_name" "external" >> "$TEMP_COMMANDS"
|
|
134
|
+
done
|
|
135
|
+
|
|
136
|
+
# Pro skills
|
|
137
|
+
for pro_skill in "$HOME/.claude/skills"/arka-pro-*/SKILL.md; do
|
|
138
|
+
[ -f "$pro_skill" ] || continue
|
|
139
|
+
pro_name=$(basename "$(dirname "$pro_skill")" | sed 's/^arka-pro-//')
|
|
140
|
+
extract_commands "$pro_skill" "$pro_name" "pro" >> "$TEMP_COMMANDS"
|
|
141
|
+
done
|
|
142
|
+
|
|
143
|
+
# ─── Build commands array from temp file ───────────────────────────────────
|
|
144
|
+
if [ -s "$TEMP_COMMANDS" ]; then
|
|
145
|
+
COMMANDS_JSON=$(jq -s '.' "$TEMP_COMMANDS")
|
|
146
|
+
else
|
|
147
|
+
COMMANDS_JSON="[]"
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# ─── Deduplicate by command ID (keep first occurrence) ─────────────────────
|
|
151
|
+
COMMANDS_JSON=$(echo "$COMMANDS_JSON" | jq '[group_by(.id) | .[] | .[0]]')
|
|
152
|
+
|
|
153
|
+
# ─── Merge keywords and examples from seed data ───────────────────────────
|
|
154
|
+
if [ -f "$KEYWORDS_FILE" ]; then
|
|
155
|
+
COMMANDS_JSON=$(jq --slurpfile kw "$KEYWORDS_FILE" '
|
|
156
|
+
[.[] | . as $cmd |
|
|
157
|
+
if $kw[0][$cmd.id] then
|
|
158
|
+
.keywords = ($kw[0][$cmd.id].keywords // []) |
|
|
159
|
+
.examples = ($kw[0][$cmd.id].examples // [])
|
|
160
|
+
else . end
|
|
161
|
+
]
|
|
162
|
+
' <<< "$COMMANDS_JSON")
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# ─── Build final registry ─────────────────────────────────────────────────
|
|
166
|
+
TOTAL=$(echo "$COMMANDS_JSON" | jq 'length')
|
|
167
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
168
|
+
|
|
169
|
+
jq -n \
|
|
170
|
+
--arg version "1.0.0" \
|
|
171
|
+
--arg generated "$NOW" \
|
|
172
|
+
--argjson total "$TOTAL" \
|
|
173
|
+
--arg generator "bin/arka-registry-gen" \
|
|
174
|
+
--argjson commands "$COMMANDS_JSON" \
|
|
175
|
+
'{
|
|
176
|
+
_meta: {
|
|
177
|
+
version: $version,
|
|
178
|
+
generated: $generated,
|
|
179
|
+
total_commands: $total,
|
|
180
|
+
generator: $generator
|
|
181
|
+
},
|
|
182
|
+
commands: $commands
|
|
183
|
+
}' > "$OUTPUT_FILE"
|
|
184
|
+
|
|
185
|
+
echo "Registry generated: $OUTPUT_FILE ($TOTAL commands)"
|
package/bin/arka-skill
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# ARKA OS — External Skill Manager
|
|
4
|
+
# Install, list, remove, and update external skills.
|
|
5
|
+
# ============================================================================
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
CYAN='\033[0;36m'
|
|
9
|
+
GREEN='\033[0;32m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
NC='\033[0m'
|
|
13
|
+
|
|
14
|
+
ARKA_OS="${ARKA_OS:-$HOME/.claude/skills/arka}"
|
|
15
|
+
EXT_DIR="$HOME/.arka-os/ext-skills"
|
|
16
|
+
EXT_REGISTRY="$HOME/.arka-os/ext-registry.json"
|
|
17
|
+
SKILLS_DIR="$HOME/.claude/skills"
|
|
18
|
+
AGENTS_DIR="$HOME/.claude/agents"
|
|
19
|
+
|
|
20
|
+
mkdir -p "$EXT_DIR" "$SKILLS_DIR" "$AGENTS_DIR"
|
|
21
|
+
|
|
22
|
+
# Ensure ext-registry exists
|
|
23
|
+
if [ ! -f "$EXT_REGISTRY" ]; then
|
|
24
|
+
echo '{"_meta":{"format_version":1},"skills":{}}' | jq '.' > "$EXT_REGISTRY"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
usage() {
|
|
28
|
+
echo -e "${CYAN}ARKA OS — External Skill Manager${NC}"
|
|
29
|
+
echo ""
|
|
30
|
+
echo "Usage: arka skill <command> [args]"
|
|
31
|
+
echo ""
|
|
32
|
+
echo "Commands:"
|
|
33
|
+
echo " install <github-url> Install an external skill"
|
|
34
|
+
echo " list List installed external skills"
|
|
35
|
+
echo " remove <name> Remove an external skill"
|
|
36
|
+
echo " update <name> Update an external skill"
|
|
37
|
+
echo " create <name> Scaffold a new skill from template"
|
|
38
|
+
echo ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Version comparison (semver >=)
|
|
42
|
+
version_gte() {
|
|
43
|
+
# $1 = current version, $2 = required version (e.g., ">=0.2.0")
|
|
44
|
+
local required="${2#>=}"
|
|
45
|
+
[ "$(printf '%s\n' "$required" "$1" | sort -V | head -1)" = "$required" ]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
cmd_install() {
|
|
49
|
+
local url="$1"
|
|
50
|
+
if [ -z "$url" ]; then
|
|
51
|
+
echo -e "${RED}Error: GitHub URL required.${NC}"
|
|
52
|
+
echo "Usage: arka skill install <github-url>"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Derive name from URL
|
|
57
|
+
local name
|
|
58
|
+
name=$(basename "$url" .git)
|
|
59
|
+
|
|
60
|
+
echo -e "${CYAN}Installing external skill: ${name}${NC}"
|
|
61
|
+
echo ""
|
|
62
|
+
|
|
63
|
+
# Step 1: Clone
|
|
64
|
+
local clone_dir="$EXT_DIR/$name"
|
|
65
|
+
if [ -d "$clone_dir" ]; then
|
|
66
|
+
echo -e "${YELLOW}Skill already installed. Use 'arka skill update $name' instead.${NC}"
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
git clone "$url" "$clone_dir"
|
|
71
|
+
|
|
72
|
+
# Step 2: Validate
|
|
73
|
+
if [ ! -f "$clone_dir/SKILL.md" ]; then
|
|
74
|
+
echo -e "${RED}Error: SKILL.md not found. Not a valid ARKA OS skill.${NC}"
|
|
75
|
+
rm -rf "$clone_dir"
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
if [ ! -f "$clone_dir/arka-skill.json" ]; then
|
|
79
|
+
echo -e "${RED}Error: arka-skill.json not found. Not a valid ARKA OS skill.${NC}"
|
|
80
|
+
rm -rf "$clone_dir"
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Step 3: Read metadata
|
|
85
|
+
local skill_version skill_desc skill_author requires_arka
|
|
86
|
+
skill_version=$(jq -r '.version' "$clone_dir/arka-skill.json")
|
|
87
|
+
skill_desc=$(jq -r '.description' "$clone_dir/arka-skill.json")
|
|
88
|
+
skill_author=$(jq -r '.author' "$clone_dir/arka-skill.json")
|
|
89
|
+
requires_arka=$(jq -r '.requires_arka_version // ""' "$clone_dir/arka-skill.json")
|
|
90
|
+
|
|
91
|
+
# Step 4: Check version compatibility
|
|
92
|
+
if [ -n "$requires_arka" ] && [ -f "$ARKA_OS/VERSION" ]; then
|
|
93
|
+
local current_version
|
|
94
|
+
current_version=$(cat "$ARKA_OS/VERSION" | tr -d '[:space:]')
|
|
95
|
+
if ! version_gte "$current_version" "$requires_arka"; then
|
|
96
|
+
echo -e "${RED}Error: Skill requires ARKA OS $requires_arka, but you have v$current_version${NC}"
|
|
97
|
+
rm -rf "$clone_dir"
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Step 5: Install SKILL.md
|
|
103
|
+
local skill_install_dir="$SKILLS_DIR/arka-ext-$name"
|
|
104
|
+
mkdir -p "$skill_install_dir"
|
|
105
|
+
cp "$clone_dir/SKILL.md" "$skill_install_dir/SKILL.md"
|
|
106
|
+
echo -e " ${GREEN}✓${NC} Skill: $name"
|
|
107
|
+
|
|
108
|
+
# Step 6: Install agents (if any)
|
|
109
|
+
local agent_count=0
|
|
110
|
+
if [ -d "$clone_dir/agents" ]; then
|
|
111
|
+
for agent_file in "$clone_dir"/agents/*.md; do
|
|
112
|
+
if [ -f "$agent_file" ]; then
|
|
113
|
+
local agent_base
|
|
114
|
+
agent_base=$(basename "$agent_file" .md)
|
|
115
|
+
cp "$agent_file" "$AGENTS_DIR/arka-ext-${name}-${agent_base}.md"
|
|
116
|
+
echo -e " ${GREEN}✓${NC} Agent: $agent_base"
|
|
117
|
+
agent_count=$((agent_count + 1))
|
|
118
|
+
fi
|
|
119
|
+
done
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# Step 7: Merge external MCPs (if any)
|
|
123
|
+
if [ -f "$clone_dir/mcps/registry-ext.json" ] && [ -f "$ARKA_OS/mcps/registry.json" ]; then
|
|
124
|
+
# Merge without overwriting built-in MCPs
|
|
125
|
+
local temp_registry
|
|
126
|
+
temp_registry=$(mktemp)
|
|
127
|
+
jq -s '
|
|
128
|
+
.[0] as $base |
|
|
129
|
+
.[1].mcpServers as $ext |
|
|
130
|
+
$base | .mcpServers += ($ext // {} | to_entries | map(select(.key as $k | $base.mcpServers[$k] == null)) | from_entries)
|
|
131
|
+
' "$ARKA_OS/mcps/registry.json" "$clone_dir/mcps/registry-ext.json" > "$temp_registry"
|
|
132
|
+
cp "$temp_registry" "$ARKA_OS/mcps/registry.json"
|
|
133
|
+
rm "$temp_registry"
|
|
134
|
+
echo -e " ${GREEN}✓${NC} External MCPs merged"
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# Step 8: Register in ext-registry
|
|
138
|
+
jq --arg name "$name" --arg version "$skill_version" --arg desc "$skill_desc" \
|
|
139
|
+
--arg author "$skill_author" --arg url "$url" --arg date "$(date +%Y-%m-%d)" \
|
|
140
|
+
'.skills[$name] = {"version": $version, "description": $desc, "author": $author, "url": $url, "installed": $date}' \
|
|
141
|
+
"$EXT_REGISTRY" > "${EXT_REGISTRY}.tmp" && mv "${EXT_REGISTRY}.tmp" "$EXT_REGISTRY"
|
|
142
|
+
|
|
143
|
+
# Step 9: Report
|
|
144
|
+
echo ""
|
|
145
|
+
echo -e "${GREEN}═══ Skill Installed ═══${NC}"
|
|
146
|
+
echo -e " Name: ${CYAN}$name${NC} v$skill_version"
|
|
147
|
+
echo -e " Author: ${CYAN}$skill_author${NC}"
|
|
148
|
+
echo -e " Desc: $skill_desc"
|
|
149
|
+
echo -e " Agents: ${CYAN}$agent_count${NC}"
|
|
150
|
+
echo -e "${GREEN}═══════════════════════${NC}"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
cmd_list() {
|
|
154
|
+
echo -e "${CYAN}ARKA OS — External Skills${NC}"
|
|
155
|
+
echo ""
|
|
156
|
+
|
|
157
|
+
local count
|
|
158
|
+
count=$(jq '.skills | length' "$EXT_REGISTRY" 2>/dev/null || echo "0")
|
|
159
|
+
|
|
160
|
+
if [ "$count" = "0" ]; then
|
|
161
|
+
echo " No external skills installed."
|
|
162
|
+
echo ""
|
|
163
|
+
echo " Install one: arka skill install <github-url>"
|
|
164
|
+
return
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
jq -r '.skills | to_entries[] | " \(.key)\tv\(.value.version)\t\(.value.description)"' "$EXT_REGISTRY" | column -t -s $'\t'
|
|
168
|
+
echo ""
|
|
169
|
+
echo -e " Total: ${CYAN}$count${NC} skill(s)"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
cmd_remove() {
|
|
173
|
+
local name="$1"
|
|
174
|
+
if [ -z "$name" ]; then
|
|
175
|
+
echo -e "${RED}Error: Skill name required.${NC}"
|
|
176
|
+
echo "Usage: arka skill remove <name>"
|
|
177
|
+
exit 1
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
echo -e "${CYAN}Removing external skill: ${name}${NC}"
|
|
181
|
+
|
|
182
|
+
# Remove cloned source
|
|
183
|
+
[ -d "$EXT_DIR/$name" ] && rm -rf "$EXT_DIR/$name" && echo -e " ${GREEN}✓${NC} Removed source"
|
|
184
|
+
|
|
185
|
+
# Remove installed skill
|
|
186
|
+
[ -d "$SKILLS_DIR/arka-ext-$name" ] && rm -rf "$SKILLS_DIR/arka-ext-$name" && echo -e " ${GREEN}✓${NC} Removed skill"
|
|
187
|
+
|
|
188
|
+
# Remove installed agents
|
|
189
|
+
for agent in "$AGENTS_DIR"/arka-ext-${name}-*.md; do
|
|
190
|
+
[ -f "$agent" ] && rm "$agent" && echo -e " ${GREEN}✓${NC} Removed $(basename "$agent")"
|
|
191
|
+
done
|
|
192
|
+
|
|
193
|
+
# Remove from registry
|
|
194
|
+
jq --arg name "$name" 'del(.skills[$name])' "$EXT_REGISTRY" > "${EXT_REGISTRY}.tmp" && mv "${EXT_REGISTRY}.tmp" "$EXT_REGISTRY"
|
|
195
|
+
echo -e " ${GREEN}✓${NC} Removed from registry"
|
|
196
|
+
|
|
197
|
+
echo -e "${GREEN}Skill '$name' removed.${NC}"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
cmd_update() {
|
|
201
|
+
local name="$1"
|
|
202
|
+
if [ -z "$name" ]; then
|
|
203
|
+
echo -e "${RED}Error: Skill name required.${NC}"
|
|
204
|
+
echo "Usage: arka skill update <name>"
|
|
205
|
+
exit 1
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
local clone_dir="$EXT_DIR/$name"
|
|
209
|
+
if [ ! -d "$clone_dir/.git" ]; then
|
|
210
|
+
echo -e "${RED}Error: Skill '$name' not found.${NC}"
|
|
211
|
+
exit 1
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
echo -e "${CYAN}Updating external skill: ${name}${NC}"
|
|
215
|
+
|
|
216
|
+
# Pull latest
|
|
217
|
+
cd "$clone_dir" && git pull --ff-only
|
|
218
|
+
|
|
219
|
+
# Re-install SKILL.md
|
|
220
|
+
local skill_install_dir="$SKILLS_DIR/arka-ext-$name"
|
|
221
|
+
mkdir -p "$skill_install_dir"
|
|
222
|
+
cp "$clone_dir/SKILL.md" "$skill_install_dir/SKILL.md"
|
|
223
|
+
echo -e " ${GREEN}✓${NC} Skill updated"
|
|
224
|
+
|
|
225
|
+
# Re-install agents
|
|
226
|
+
if [ -d "$clone_dir/agents" ]; then
|
|
227
|
+
for agent_file in "$clone_dir"/agents/*.md; do
|
|
228
|
+
if [ -f "$agent_file" ]; then
|
|
229
|
+
local agent_base
|
|
230
|
+
agent_base=$(basename "$agent_file" .md)
|
|
231
|
+
cp "$agent_file" "$AGENTS_DIR/arka-ext-${name}-${agent_base}.md"
|
|
232
|
+
echo -e " ${GREEN}✓${NC} Agent: $agent_base"
|
|
233
|
+
fi
|
|
234
|
+
done
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# Update registry version
|
|
238
|
+
local skill_version
|
|
239
|
+
skill_version=$(jq -r '.version' "$clone_dir/arka-skill.json" 2>/dev/null || echo "unknown")
|
|
240
|
+
jq --arg name "$name" --arg version "$skill_version" \
|
|
241
|
+
'.skills[$name].version = $version' \
|
|
242
|
+
"$EXT_REGISTRY" > "${EXT_REGISTRY}.tmp" && mv "${EXT_REGISTRY}.tmp" "$EXT_REGISTRY"
|
|
243
|
+
|
|
244
|
+
echo -e "${GREEN}Skill '$name' updated to v$skill_version.${NC}"
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
cmd_create() {
|
|
248
|
+
local name="$1"
|
|
249
|
+
if [ -z "$name" ]; then
|
|
250
|
+
echo -e "${RED}Error: Skill name required.${NC}"
|
|
251
|
+
echo "Usage: arka skill create <name>"
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
local template_dir="$ARKA_OS/skill-template"
|
|
256
|
+
local target_dir="./$name"
|
|
257
|
+
|
|
258
|
+
if [ -d "$target_dir" ]; then
|
|
259
|
+
echo -e "${RED}Error: Directory '$name' already exists.${NC}"
|
|
260
|
+
exit 1
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
echo -e "${CYAN}Creating new skill: ${name}${NC}"
|
|
264
|
+
|
|
265
|
+
mkdir -p "$target_dir/agents" "$target_dir/mcps"
|
|
266
|
+
|
|
267
|
+
# Copy and process templates
|
|
268
|
+
if [ -f "$template_dir/SKILL.md.template" ]; then
|
|
269
|
+
sed "s/{{SKILL_NAME}}/$name/g" "$template_dir/SKILL.md.template" > "$target_dir/SKILL.md"
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
if [ -f "$template_dir/arka-skill.json.template" ]; then
|
|
273
|
+
sed "s/{{SKILL_NAME}}/$name/g" "$template_dir/arka-skill.json.template" > "$target_dir/arka-skill.json"
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
if [ -f "$template_dir/README.md.template" ]; then
|
|
277
|
+
sed "s/{{SKILL_NAME}}/$name/g" "$template_dir/README.md.template" > "$target_dir/README.md"
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
echo -e " ${GREEN}✓${NC} Created $target_dir/"
|
|
281
|
+
echo -e " ${GREEN}✓${NC} SKILL.md"
|
|
282
|
+
echo -e " ${GREEN}✓${NC} arka-skill.json"
|
|
283
|
+
echo -e " ${GREEN}✓${NC} README.md"
|
|
284
|
+
echo ""
|
|
285
|
+
echo -e "Next steps:"
|
|
286
|
+
echo -e " 1. Edit ${CYAN}$target_dir/SKILL.md${NC} with your skill definition"
|
|
287
|
+
echo -e " 2. Edit ${CYAN}$target_dir/arka-skill.json${NC} with metadata"
|
|
288
|
+
echo -e " 3. Add agents to ${CYAN}$target_dir/agents/${NC} (optional)"
|
|
289
|
+
echo -e " 4. Push to GitHub and install with: ${CYAN}arka skill install <url>${NC}"
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
# Main routing
|
|
293
|
+
case "${1:-}" in
|
|
294
|
+
install) shift; cmd_install "$@" ;;
|
|
295
|
+
list) cmd_list ;;
|
|
296
|
+
remove) shift; cmd_remove "$@" ;;
|
|
297
|
+
update) shift; cmd_update "$@" ;;
|
|
298
|
+
create) shift; cmd_create "$@" ;;
|
|
299
|
+
*) usage ;;
|
|
300
|
+
esac
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""ArkaOS Scheduler Daemon — entry point for launchd/systemd/schtasks.
|
|
3
|
+
|
|
4
|
+
Runs in a loop, checking every 60 seconds whether any scheduled cognitive
|
|
5
|
+
task (Dreaming, Research) should execute at the current time.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
# Ensure ArkaOS core is importable
|
|
13
|
+
ARKAOS_ROOT = Path(__file__).resolve().parent.parent
|
|
14
|
+
if str(ARKAOS_ROOT) not in sys.path:
|
|
15
|
+
sys.path.insert(0, str(ARKAOS_ROOT))
|
|
16
|
+
|
|
17
|
+
from core.cognition.scheduler.daemon import ArkaScheduler # noqa: E402
|
|
18
|
+
|
|
19
|
+
HOME = Path.home()
|
|
20
|
+
CONFIG_PATH = str(HOME / ".arkaos" / "schedules.yaml")
|
|
21
|
+
LOG_DIR = str(HOME / ".arkaos" / "logs")
|
|
22
|
+
LOCK_PATH = str(HOME / ".arkaos" / "scheduler.lock")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> None:
|
|
26
|
+
scheduler = ArkaScheduler(
|
|
27
|
+
config_path=CONFIG_PATH,
|
|
28
|
+
log_dir=LOG_DIR,
|
|
29
|
+
lock_path=LOCK_PATH,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if not scheduler.acquire_lock():
|
|
33
|
+
print("Another scheduler instance is already running. Exiting.")
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
|
|
36
|
+
print(f"ArkaOS Scheduler started — {len(scheduler.schedules)} tasks loaded")
|
|
37
|
+
try:
|
|
38
|
+
while True:
|
|
39
|
+
scheduler.run_once()
|
|
40
|
+
time.sleep(60)
|
|
41
|
+
except KeyboardInterrupt:
|
|
42
|
+
print("Scheduler stopped.")
|
|
43
|
+
finally:
|
|
44
|
+
scheduler.release_lock()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
main()
|
|
@@ -23,7 +23,7 @@ evidence, not from model size.
|
|
|
23
23
|
## Review Rubric (evidence interpretation, not role-play)
|
|
24
24
|
|
|
25
25
|
1. Run the engine first — no verdict without a report:
|
|
26
|
-
|
|
26
|
+
`~/.arkaos/bin/arka-py -m core.governance.evidence_checks <project_dir> [--changed-files ...] [--test-command '...'] --json`
|
|
27
27
|
2. Dispatch Eduardo (spellcheck + changed copy) and Francisca
|
|
28
28
|
(lint/typecheck/tests/coverage/security-grep) with the report and the
|
|
29
29
|
structured output schema `QG_VERDICT_JSON_SCHEMA` from
|
|
@@ -24,7 +24,7 @@ not cut corners to look fast.
|
|
|
24
24
|
dispatch with `[arka:dispatch] paulo -> <specialist>`.
|
|
25
25
|
3. Evidence over narration: a task is done when its tests RAN and exited 0
|
|
26
26
|
on record — never when a subagent says it is done. Run
|
|
27
|
-
|
|
27
|
+
`~/.arkaos/bin/arka-py -m core.governance.evidence_checks <project_dir> --json` before
|
|
28
28
|
claiming completion.
|
|
29
29
|
4. Submit to the Quality Gate (marta-cqo) with the evidence report; expect
|
|
30
30
|
a structured `QGVerdict` back. REJECTED means loop, not negotiate.
|