arkaos 4.3.4 → 4.3.5
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/config/hooks/cwd-changed.sh +27 -22
- package/config/hooks/session-start.sh +7 -4
- package/package.json +13 -2
- package/pyproject.toml +1 -1
- package/bin/arka-registry-gen +0 -185
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.3.
|
|
1
|
+
4.3.5
|
|
@@ -28,40 +28,43 @@ ECOSYSTEM=""
|
|
|
28
28
|
ECOSYSTEM_NAME=""
|
|
29
29
|
|
|
30
30
|
if [ -f "$ECOSYSTEMS_FILE" ] && command -v "$ARKA_PY" >/dev/null 2>&1; then
|
|
31
|
-
|
|
31
|
+
# OWASP A03: NEW_CWD is untrusted harness input. It is passed through the
|
|
32
|
+
# environment (never interpolated into the Python source), and the result
|
|
33
|
+
# is emitted as JSON read by jq — no `eval`, so a crafted cwd can neither
|
|
34
|
+
# break the source string nor inject a shell command.
|
|
35
|
+
_ECO_JSON=$(ARKA_CWD="$NEW_CWD" ARKA_ECO_FILE="$ECOSYSTEMS_FILE" "$ARKA_PY" -c '
|
|
32
36
|
import json, os, sys
|
|
33
37
|
|
|
34
|
-
cwd =
|
|
35
|
-
eco_file = os.path.expanduser(
|
|
38
|
+
cwd = os.environ["ARKA_CWD"]
|
|
39
|
+
eco_file = os.path.expanduser(os.environ["ARKA_ECO_FILE"])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def emit(eco_id, name):
|
|
43
|
+
print(json.dumps({"ecosystem": eco_id, "name": name}))
|
|
44
|
+
sys.exit(0)
|
|
45
|
+
|
|
36
46
|
|
|
37
47
|
try:
|
|
38
48
|
data = json.load(open(eco_file))
|
|
39
|
-
ecosystems = data.get(
|
|
49
|
+
ecosystems = data.get("ecosystems", {})
|
|
40
50
|
|
|
41
51
|
for eco_id, eco in ecosystems.items():
|
|
42
|
-
|
|
43
|
-
for proj in projects:
|
|
44
|
-
# Check if cwd contains the project name
|
|
52
|
+
for proj in eco.get("projects", []):
|
|
45
53
|
if proj in cwd:
|
|
46
|
-
|
|
47
|
-
print(f'ECOSYSTEM_NAME=\"{eco.get(\"name\", eco_id)}\"')
|
|
48
|
-
sys.exit(0)
|
|
54
|
+
emit(eco_id, eco.get("name", eco_id))
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dir_name = os.path.basename(cwd.rstrip('/'))
|
|
56
|
+
if "/herd/" in cwd or "/Herd/" in cwd:
|
|
57
|
+
dir_name = os.path.basename(cwd.rstrip("/"))
|
|
53
58
|
for eco_id, eco in ecosystems.items():
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
print(f'ECOSYSTEM=\"{eco_id}\"')
|
|
57
|
-
print(f'ECOSYSTEM_NAME=\"{eco.get(\"name\", eco_id)}\"')
|
|
58
|
-
sys.exit(0)
|
|
59
|
+
if dir_name in eco.get("projects", []):
|
|
60
|
+
emit(eco_id, eco.get("name", eco_id))
|
|
59
61
|
except Exception:
|
|
60
62
|
pass
|
|
61
63
|
|
|
62
|
-
print(
|
|
63
|
-
|
|
64
|
-
" 2>/dev/null)
|
|
64
|
+
print(json.dumps({"ecosystem": "", "name": ""}))
|
|
65
|
+
' 2>/dev/null)
|
|
66
|
+
ECOSYSTEM=$(echo "$_ECO_JSON" | jq -r '.ecosystem // ""' 2>/dev/null)
|
|
67
|
+
ECOSYSTEM_NAME=$(echo "$_ECO_JSON" | jq -r '.name // ""' 2>/dev/null)
|
|
65
68
|
fi
|
|
66
69
|
|
|
67
70
|
# ─── Detect stack ──────────────────────────────────────────────────────
|
|
@@ -113,5 +116,7 @@ if [ -n "$DESCRIPTOR" ]; then
|
|
|
113
116
|
fi
|
|
114
117
|
|
|
115
118
|
if [ -n "$CONTEXT" ]; then
|
|
116
|
-
|
|
119
|
+
# Build the JSON with jq so any quote/backslash in the ecosystem name or
|
|
120
|
+
# descriptor path is escaped, never breaking the envelope (OWASP A03).
|
|
121
|
+
jq -nc --arg ctx "$CONTEXT" '{additionalContext: $ctx}'
|
|
117
122
|
fi
|
|
@@ -184,8 +184,11 @@ except Exception:
|
|
|
184
184
|
fi
|
|
185
185
|
|
|
186
186
|
# ─── Output as systemMessage (same protocol as claude-mem) ─────────────
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
# OWASP A03: MSG carries profile-derived NAME/COMPANY. Pass it through the
|
|
188
|
+
# environment (with \n already expanded) rather than interpolating it into
|
|
189
|
+
# the Python source, so a name containing quotes or ''' cannot break the
|
|
190
|
+
# script or the JSON envelope.
|
|
191
|
+
ARKA_MSG="$(echo -e "$MSG")" "$ARKA_PY" -c "
|
|
192
|
+
import json, os
|
|
193
|
+
print(json.dumps({'systemMessage': os.environ['ARKA_MSG']}))
|
|
191
194
|
"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arkaos",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.5",
|
|
4
4
|
"description": "The Operating System for AI Agent Teams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -45,7 +45,18 @@
|
|
|
45
45
|
"departments/",
|
|
46
46
|
"scripts/",
|
|
47
47
|
"config/",
|
|
48
|
-
"bin/",
|
|
48
|
+
"bin/arka",
|
|
49
|
+
"bin/arka-claude",
|
|
50
|
+
"bin/arka-claude.cmd",
|
|
51
|
+
"bin/arka-claude.ps1",
|
|
52
|
+
"bin/arka-doctor",
|
|
53
|
+
"bin/arka-providers",
|
|
54
|
+
"bin/arka-py",
|
|
55
|
+
"bin/arka-py.cmd",
|
|
56
|
+
"bin/arka-py.ps1",
|
|
57
|
+
"bin/arka-skill",
|
|
58
|
+
"bin/arkaos",
|
|
59
|
+
"bin/scheduler-daemon.py",
|
|
49
60
|
"arka/",
|
|
50
61
|
"knowledge/",
|
|
51
62
|
"dashboard/app/",
|
package/pyproject.toml
CHANGED
package/bin/arka-registry-gen
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
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)"
|