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 CHANGED
@@ -1 +1 @@
1
- 4.3.4
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
- eval "$("$ARKA_PY" -c "
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 = '$NEW_CWD'
35
- eco_file = os.path.expanduser('$ECOSYSTEMS_FILE')
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('ecosystems', {})
49
+ ecosystems = data.get("ecosystems", {})
40
50
 
41
51
  for eco_id, eco in ecosystems.items():
42
- projects = eco.get('projects', [])
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
- print(f'ECOSYSTEM=\"{eco_id}\"')
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
- # No match by project name, try by path patterns
51
- if '/herd/' in cwd or '/Herd/' in cwd:
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
- for proj in eco.get('projects', []):
55
- if proj == dir_name:
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('ECOSYSTEM=\"\"')
63
- print('ECOSYSTEM_NAME=\"\"')
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
- echo "{\"additionalContext\": \"${CONTEXT}\"}"
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
- "$ARKA_PY" -c "
188
- import json
189
- msg = '''$(echo -e "$MSG")'''
190
- print(json.dumps({'systemMessage': msg}))
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.4",
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arkaos-core"
3
- version = "4.3.4"
3
+ version = "4.3.5"
4
4
  description = "Core engine for ArkaOS — The Operating System for AI Agent Teams"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -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)"