arkaos 2.19.0 → 2.19.2
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 +8 -8
- package/VERSION +1 -1
- package/arka/SKILL.md +44 -0
- package/config/cognition/prompts/dreaming.md +3 -3
- package/config/hooks/user-prompt-submit.sh +34 -1
- package/core/runtime/__pycache__/user_paths.cpython-313.pyc +0 -0
- package/core/sync/__pycache__/engine.cpython-313.pyc +0 -0
- package/core/sync/engine.py +8 -8
- package/installer/adapters/claude-code.js +10 -9
- package/installer/index.js +21 -0
- package/installer/migrate-user-data.js +94 -72
- package/installer/update.js +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/README.md
CHANGED
|
@@ -161,7 +161,7 @@ ArkaOS doesn't just execute — it **learns, dreams, and researches**.
|
|
|
161
161
|
Every solution you implement is captured and indexed. When you need authentication in a new Laravel project, ArkaOS already knows how you did it in the last three projects — with the exact pattern, configuration, and lessons learned.
|
|
162
162
|
|
|
163
163
|
- **Dual-write**: Obsidian (human-readable) + Vector DB (semantic search)
|
|
164
|
-
- **Cross-project**: Knowledge from
|
|
164
|
+
- **Cross-project**: Knowledge from ClientRetail applies to ClientFashion
|
|
165
165
|
- **Confidence scoring**: Patterns validated 3+ times become "validated patterns"
|
|
166
166
|
|
|
167
167
|
### Dreaming (runs at 02:00)
|
|
@@ -185,7 +185,7 @@ Pending reflections from Dreaming:
|
|
|
185
185
|
|
|
186
186
|
2. [technical] Sync retry — improve
|
|
187
187
|
Fixed backoff can cause thundering herd. Use exponential
|
|
188
|
-
backoff with jitter (validated pattern from
|
|
188
|
+
backoff with jitter (validated pattern from ClientRetail).
|
|
189
189
|
|
|
190
190
|
Want me to elaborate?
|
|
191
191
|
```
|
|
@@ -204,11 +204,11 @@ Intelligence Briefing — 2026-04-10
|
|
|
204
204
|
|
|
205
205
|
ACTION REQUIRED:
|
|
206
206
|
- Laravel 12.1.3 security patch — SQL injection in whereHas.
|
|
207
|
-
Affects:
|
|
207
|
+
Affects: ClientFashion, ClientCommerce. Fix: composer update laravel/framework.
|
|
208
208
|
|
|
209
209
|
OPPORTUNITIES:
|
|
210
|
-
- Shopify Winter '26 bulk product API —
|
|
211
|
-
- Nuxt 4 RC2 migration guide published — start preparing
|
|
210
|
+
- Shopify Winter '26 bulk product API — ClientCommerce sync could be 10x faster.
|
|
211
|
+
- Nuxt 4 RC2 migration guide published — start preparing ClientVideo.
|
|
212
212
|
|
|
213
213
|
COMPETITOR WATCH:
|
|
214
214
|
- CrewAI v3 launched memory layer — similar to our Cognitive Layer
|
|
@@ -233,9 +233,9 @@ arkaos scheduler logs # View logs
|
|
|
233
233
|
ArkaOS manages client projects as **ecosystems** — groups of related projects with dedicated squads.
|
|
234
234
|
|
|
235
235
|
```
|
|
236
|
-
/
|
|
237
|
-
/
|
|
238
|
-
/
|
|
236
|
+
/client_retail → ClientRetail ecosystem (4 projects: API, frontend, admin, docs)
|
|
237
|
+
/client_commerce → ClientCommerce ecosystem (supplier sync + Shopify theme)
|
|
238
|
+
/client_fashion → ClientFashion (6 projects: CRM, store, API, migration...)
|
|
239
239
|
/edp → EDP (3 projects: portal, API, analytics)
|
|
240
240
|
```
|
|
241
241
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.19.
|
|
1
|
+
2.19.2
|
package/arka/SKILL.md
CHANGED
|
@@ -12,6 +12,50 @@ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, Agent, WebFetch, WebSearch]
|
|
|
12
12
|
> **The Operating System for AI Agent Teams**
|
|
13
13
|
> 65 agents. 17 departments. 244+ skills. Multi-runtime. Dashboard. Knowledge RAG.
|
|
14
14
|
|
|
15
|
+
## ⛔ Enforcement contract (read before responding)
|
|
16
|
+
|
|
17
|
+
This overrides every default. If the UserPromptSubmit hook injected a
|
|
18
|
+
`[ARKA:WORKFLOW-REQUIRED]` tag, you MUST, on the first line of your reply:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
[arka:routing] <department-slug> -> <lead-agent>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Example first lines (pick the right department for the ask):
|
|
25
|
+
|
|
26
|
+
- `[arka:routing] dev -> Paulo` — code, features, refactors, tests
|
|
27
|
+
- `[arka:routing] brand -> Valentina` — identity, design, logos, voice
|
|
28
|
+
- `[arka:routing] kb -> Clara` — knowledge base, research, Obsidian
|
|
29
|
+
- `[arka:routing] mkt -> Luna` — marketing, growth, SEO, campaigns
|
|
30
|
+
- `[arka:routing] content -> Rafael` — content, video, social, copy
|
|
31
|
+
- `[arka:routing] landing -> Ines` — landing pages, funnels, offers
|
|
32
|
+
- `[arka:routing] ecom -> Ricardo` — e-commerce, stores, conversion
|
|
33
|
+
- `[arka:routing] saas -> Tiago` — SaaS, validation, PLG, metrics
|
|
34
|
+
- `[arka:routing] sales -> Miguel` — pipeline, discovery, negotiation
|
|
35
|
+
- `[arka:routing] pm -> Carolina` — roadmap, sprints, backlog, stories
|
|
36
|
+
- `[arka:routing] ops -> Daniel` — automation, SOPs, workflows
|
|
37
|
+
- `[arka:routing] strat -> Tomas` — strategy, positioning, moats
|
|
38
|
+
- `[arka:routing] fin -> Helena` — finance, modeling, budgets
|
|
39
|
+
- `[arka:routing] lead -> Rodrigo` — team health, feedback, hiring
|
|
40
|
+
- `[arka:routing] org -> Sofia` — org design, COO, operations
|
|
41
|
+
- `[arka:routing] community -> Beatriz` — communities, platforms, retention
|
|
42
|
+
|
|
43
|
+
After the routing line, in order:
|
|
44
|
+
|
|
45
|
+
1. State the workflow name and its phase count.
|
|
46
|
+
2. Run Phase 1 (usually spec via `arka-spec` or plan via `arka-forge`) BEFORE writing any code.
|
|
47
|
+
3. Execute sequential phases with visibility (one at a time, report status).
|
|
48
|
+
4. Run the Quality Gate (Marta CQO + Eduardo Copy + Francisca Tech, model Opus) BEFORE marking done.
|
|
49
|
+
|
|
50
|
+
The only exception is a trivial 1-file edit under 10 lines. In that case emit:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
[arka:trivial] <one-sentence reason>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
and proceed directly. Anything else without a routing line is a constitution
|
|
57
|
+
violation (squad-routing, arka-supremacy, spec-driven, mandatory-qa).
|
|
58
|
+
|
|
15
59
|
## System Commands
|
|
16
60
|
|
|
17
61
|
| Command | Description |
|
|
@@ -70,7 +70,7 @@ vector = VectorWriter(os.path.expanduser("~/.arkaos/knowledge.db"))
|
|
|
70
70
|
|
|
71
71
|
- Compare today's errors with past errors — if same error type appears > 2 times, create Anti-Pattern entry
|
|
72
72
|
- Compare today's solutions with past solutions — if same pattern appears > 2 times, promote to Validated Pattern
|
|
73
|
-
- Detect inconsistencies between projects ("In
|
|
73
|
+
- Detect inconsistencies between projects ("In ClientRetail used X, in ClientFashion used Y for same problem")
|
|
74
74
|
|
|
75
75
|
## Phase 4: Curation and Consolidation
|
|
76
76
|
|
|
@@ -123,7 +123,7 @@ quality_score: 75
|
|
|
123
123
|
entries_created: 4
|
|
124
124
|
entries_updated: 2
|
|
125
125
|
insights_generated: 3
|
|
126
|
-
projects_active: [
|
|
126
|
+
projects_active: [client_commerce, client_retail, client_fashion]
|
|
127
127
|
---
|
|
128
128
|
|
|
129
129
|
# Dreaming Report — YYYY-MM-DD
|
|
@@ -199,7 +199,7 @@ Write structured metrics to `~/.arkaos/logs/dreaming/YYYY-MM-DD.json`:
|
|
|
199
199
|
"entries_updated": 2,
|
|
200
200
|
"insights_generated": 3,
|
|
201
201
|
"captures_processed": 15,
|
|
202
|
-
"projects_reviewed": ["
|
|
202
|
+
"projects_reviewed": ["client_commerce", "client_retail"]
|
|
203
203
|
}
|
|
204
204
|
```
|
|
205
205
|
|
|
@@ -275,8 +275,41 @@ NO generic assistant replies. Announce the squad before responding.
|
|
|
275
275
|
When [knowledge:N chunks] is present, cite at least one source.
|
|
276
276
|
If [knowledge:N chunks] is absent on a non-trivial ArkaOS topic, query Obsidian first."
|
|
277
277
|
|
|
278
|
+
# ─── Workflow Classifier (hard enforcement for creation/implementation) ──
|
|
279
|
+
# Classifies the user prompt. If it looks like a creation/implementation/
|
|
280
|
+
# modification request that is NOT already routed with an explicit /prefix,
|
|
281
|
+
# emits a directive that the agent MUST acknowledge with [arka:routing]
|
|
282
|
+
# BEFORE using any write tool. Trivial quick questions pass through
|
|
283
|
+
# untouched. Explicit slash commands pass through untouched.
|
|
284
|
+
_WORKFLOW_DIRECTIVE=""
|
|
285
|
+
if [ -n "$user_input" ]; then
|
|
286
|
+
# Skip: explicit slash command (already routed)
|
|
287
|
+
_FIRST_CHAR=$(echo "$user_input" | head -c 1)
|
|
288
|
+
if [ "$_FIRST_CHAR" != "/" ] && [ "$_FIRST_CHAR" != "!" ]; then
|
|
289
|
+
# Match creation/implementation verbs in EN and PT (case-insensitive).
|
|
290
|
+
_VERB_PATTERN='(criar?|crie[ms]?|cria[mr]?|adicionar?|adiciona[mr]?|implementar?|implementa[mr]?|desenvolver?|desenvolve[mr]?|construir?|constru[ií]a?[mr]?|fazer?|faz[ae][mr]?|refactor(izar?)?|corrigir?|corrige[mr]?|consertar?|conserta[mr]?|create[sd]?|creating|build(s|ing)?|add(s|ed|ing)?|implement(s|ed|ing)?|develop(s|ed|ing)?|fix(es|ed|ing)?|refactor(s|ed|ing)?|make[sd]?|making)'
|
|
291
|
+
_NOUN_PATTERN='(feature|funcionalidade|skill|squad|agent[e]?|workflow|endpoint|api|component[e]?|module|m[oó]dulo|page|p[aá]gina|hook|pipeline|integration|integra[cç][aã]o|dashboard|report|report[eó]|script|test[es]?)'
|
|
292
|
+
if echo "$user_input" | grep -qiE "\b${_VERB_PATTERN}\b"; then
|
|
293
|
+
_WORKFLOW_DIRECTIVE="
|
|
294
|
+
[ARKA:WORKFLOW-REQUIRED] Your user request matched a CREATION/IMPLEMENTATION pattern.
|
|
295
|
+
You MUST, before using any Write, Edit, Bash with side-effects, or Agent tool:
|
|
296
|
+
1. Output on the first line: [arka:routing] <department-slug> -> <lead-agent>
|
|
297
|
+
(e.g. [arka:routing] dev -> Paulo, [arka:routing] brand -> Valentina,
|
|
298
|
+
[arka:routing] kb -> Clara, [arka:routing] mkt -> Luna)
|
|
299
|
+
2. State the workflow name and phase count in one short sentence.
|
|
300
|
+
3. Begin phase 1 (spec or plan) BEFORE any code is written.
|
|
301
|
+
4. Run the Quality Gate (Marta + Eduardo + Francisca, Opus) before claiming done.
|
|
302
|
+
Trivial override: if the request is a single-file edit under 10 lines AND the user
|
|
303
|
+
used an imperative like 'rename X', 'fix typo', you MAY emit [arka:trivial] <reason>
|
|
304
|
+
and proceed directly. Anything else requires routing. This is enforced, not advisory.
|
|
305
|
+
Skipping routing violates constitution rules squad-routing, arka-supremacy,
|
|
306
|
+
spec-driven, mandatory-qa, sequential-validation."
|
|
307
|
+
fi
|
|
308
|
+
fi
|
|
309
|
+
fi
|
|
310
|
+
|
|
278
311
|
# ─── Output ──────────────────────────────────────────────────────────────
|
|
279
|
-
_OUT_CONTEXT="${_ARKA_GREETING:-}${_SYNC_NOTICE:-}${_ROUTE_REMINDER} $python_result"
|
|
312
|
+
_OUT_CONTEXT="${_ARKA_GREETING:-}${_SYNC_NOTICE:-}${_ROUTE_REMINDER}${_WORKFLOW_DIRECTIVE} $python_result"
|
|
280
313
|
[ -n "$_HYGIENE" ] && _OUT_CONTEXT="$_OUT_CONTEXT $_HYGIENE"
|
|
281
314
|
# Escape for JSON
|
|
282
315
|
_OUT_JSON=$(python3 -c "import json,sys; print(json.dumps(sys.stdin.read()))" <<< "$_OUT_CONTEXT" 2>/dev/null)
|
|
Binary file
|
|
Binary file
|
package/core/sync/engine.py
CHANGED
|
@@ -184,14 +184,14 @@ def _discover_projects(arkaos_home: Path, skills_dir: Path) -> list:
|
|
|
184
184
|
"""
|
|
185
185
|
del skills_dir # retained for signature stability; unused.
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
#
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
187
|
+
# resolve_*() returns None when neither the new nor legacy path exists.
|
|
188
|
+
# `discover_all_projects` requires concrete Path objects but calls
|
|
189
|
+
# `.exists()` internally, so substituting the (non-existent) canonical
|
|
190
|
+
# path keeps the contract: missing → returns an empty project list.
|
|
191
|
+
descriptor_dir = resolve_projects_dir() or (Path.home() / ".arkaos" / "projects")
|
|
192
|
+
ecosystems_path = resolve_ecosystems_file() or (
|
|
193
|
+
Path.home() / ".arkaos" / "ecosystems.json"
|
|
194
|
+
)
|
|
195
195
|
|
|
196
196
|
scan_dirs = _load_scan_dirs_from_profile(arkaos_home)
|
|
197
197
|
|
|
@@ -105,19 +105,20 @@ export default {
|
|
|
105
105
|
];
|
|
106
106
|
|
|
107
107
|
// Statusline — ArkaOS branded status bar
|
|
108
|
+
// Claude Code reads the camelCase "statusLine" key; the lowercase
|
|
109
|
+
// "statusline" variant is silently ignored.
|
|
108
110
|
const configDir = join(installDir, "config");
|
|
109
111
|
const statuslineFile = IS_WINDOWS ? "statusline.ps1" : "statusline.sh";
|
|
110
112
|
const statuslinePath = join(configDir, statuslineFile);
|
|
111
113
|
if (existsSync(statuslinePath)) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
114
|
+
const command = IS_WINDOWS
|
|
115
|
+
? `powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${statuslinePath}"`
|
|
116
|
+
: statuslinePath;
|
|
117
|
+
settings.statusLine = {
|
|
118
|
+
type: "command",
|
|
119
|
+
command,
|
|
120
|
+
padding: 2,
|
|
121
|
+
};
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
package/installer/index.js
CHANGED
|
@@ -259,6 +259,27 @@ export async function install({ runtime, path, force }) {
|
|
|
259
259
|
};
|
|
260
260
|
writeFileSync(join(installDir, "install-manifest.json"), JSON.stringify(manifest, null, 2));
|
|
261
261
|
|
|
262
|
+
// Seed sync-state.json so session-start.sh does not read a missing file as
|
|
263
|
+
// version drift and permanently show [arka:update-available] on a fresh
|
|
264
|
+
// install. Schema aligned with core/sync/reporter.py write_sync_state.
|
|
265
|
+
const syncStatePath = join(installDir, "sync-state.json");
|
|
266
|
+
if (!existsSync(syncStatePath)) {
|
|
267
|
+
writeFileSync(
|
|
268
|
+
syncStatePath,
|
|
269
|
+
JSON.stringify(
|
|
270
|
+
{
|
|
271
|
+
version: VERSION,
|
|
272
|
+
last_sync: new Date().toISOString(),
|
|
273
|
+
projects_synced: 0,
|
|
274
|
+
skills_synced: 0,
|
|
275
|
+
errors: [],
|
|
276
|
+
},
|
|
277
|
+
null,
|
|
278
|
+
2,
|
|
279
|
+
),
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
262
283
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
263
284
|
|
|
264
285
|
console.log(`
|
|
@@ -19,81 +19,16 @@ const LOGS_DIR = join(USER_DATA_ROOT, "logs");
|
|
|
19
19
|
* @returns {{ moved: string[], skipped: string[], conflicts: string[], logPath: string|null }}
|
|
20
20
|
*/
|
|
21
21
|
export function migrateUserData({ dryRun = false } = {}) {
|
|
22
|
-
|
|
23
|
-
const skipped = [];
|
|
24
|
-
const conflicts = [];
|
|
22
|
+
ensureDataRoot();
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
if (!existsSync(NEW_PROJECTS)) {
|
|
30
|
-
mkdirSync(NEW_PROJECTS, { recursive: true });
|
|
31
|
-
}
|
|
24
|
+
const projectsResult = migrateProjects({ dryRun });
|
|
25
|
+
const ecosystemsResult = migrateEcosystems({ dryRun });
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const dst = join(NEW_PROJECTS, entry);
|
|
37
|
-
if (existsSync(dst)) {
|
|
38
|
-
conflicts.push(`projects/${entry}: destination already present, left source untouched`);
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
if (dryRun) {
|
|
42
|
-
moved.push(`projects/${entry} (dry-run)`);
|
|
43
|
-
} else {
|
|
44
|
-
try {
|
|
45
|
-
renameSync(src, dst);
|
|
46
|
-
moved.push(`projects/${entry}`);
|
|
47
|
-
} catch (err) {
|
|
48
|
-
conflicts.push(`projects/${entry}: ${err.message}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
skipped.push("projects/: legacy directory absent");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (existsSync(LEGACY_ECOSYSTEMS)) {
|
|
57
|
-
if (existsSync(NEW_ECOSYSTEMS)) {
|
|
58
|
-
conflicts.push("ecosystems.json: destination already present, left source untouched");
|
|
59
|
-
} else if (dryRun) {
|
|
60
|
-
moved.push("ecosystems.json (dry-run)");
|
|
61
|
-
} else {
|
|
62
|
-
try {
|
|
63
|
-
renameSync(LEGACY_ECOSYSTEMS, NEW_ECOSYSTEMS);
|
|
64
|
-
moved.push("ecosystems.json");
|
|
65
|
-
} catch (err) {
|
|
66
|
-
conflicts.push(`ecosystems.json: ${err.message}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
skipped.push("ecosystems.json: legacy file absent");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
let logPath = null;
|
|
74
|
-
if (moved.length > 0 || conflicts.length > 0) {
|
|
75
|
-
if (!existsSync(LOGS_DIR)) mkdirSync(LOGS_DIR, { recursive: true });
|
|
76
|
-
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
77
|
-
logPath = join(LOGS_DIR, `migration-${stamp}.log`);
|
|
78
|
-
const body = [
|
|
79
|
-
`ArkaOS user-data migration — ${new Date().toISOString()}`,
|
|
80
|
-
`Source: ${LEGACY_SKILLS_ROOT}`,
|
|
81
|
-
`Destination: ${USER_DATA_ROOT}`,
|
|
82
|
-
`Dry-run: ${dryRun}`,
|
|
83
|
-
"",
|
|
84
|
-
`Moved (${moved.length}):`,
|
|
85
|
-
...moved.map(m => ` - ${m}`),
|
|
86
|
-
"",
|
|
87
|
-
`Conflicts (${conflicts.length}):`,
|
|
88
|
-
...conflicts.map(c => ` - ${c}`),
|
|
89
|
-
"",
|
|
90
|
-
`Skipped (${skipped.length}):`,
|
|
91
|
-
...skipped.map(s => ` - ${s}`),
|
|
92
|
-
"",
|
|
93
|
-
].join("\n");
|
|
94
|
-
if (!dryRun) writeFileSync(logPath, body);
|
|
95
|
-
}
|
|
27
|
+
const moved = [...projectsResult.moved, ...ecosystemsResult.moved];
|
|
28
|
+
const skipped = [...projectsResult.skipped, ...ecosystemsResult.skipped];
|
|
29
|
+
const conflicts = [...projectsResult.conflicts, ...ecosystemsResult.conflicts];
|
|
96
30
|
|
|
31
|
+
const logPath = writeReport({ moved, skipped, conflicts, dryRun });
|
|
97
32
|
return { moved, skipped, conflicts, logPath };
|
|
98
33
|
}
|
|
99
34
|
|
|
@@ -108,3 +43,90 @@ export function printMigrationReport(result) {
|
|
|
108
43
|
for (const c of conflicts) console.log(` ! ${c}`);
|
|
109
44
|
if (logPath) console.log(` Log: ${logPath}`);
|
|
110
45
|
}
|
|
46
|
+
|
|
47
|
+
function ensureDataRoot() {
|
|
48
|
+
if (!existsSync(USER_DATA_ROOT)) mkdirSync(USER_DATA_ROOT, { recursive: true });
|
|
49
|
+
if (!existsSync(NEW_PROJECTS)) mkdirSync(NEW_PROJECTS, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function migrateProjects({ dryRun }) {
|
|
53
|
+
const moved = [];
|
|
54
|
+
const skipped = [];
|
|
55
|
+
const conflicts = [];
|
|
56
|
+
|
|
57
|
+
if (!existsSync(LEGACY_PROJECTS) || !statSync(LEGACY_PROJECTS).isDirectory()) {
|
|
58
|
+
skipped.push("projects/: legacy directory absent");
|
|
59
|
+
return { moved, skipped, conflicts };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const entry of readdirSync(LEGACY_PROJECTS)) {
|
|
63
|
+
const src = join(LEGACY_PROJECTS, entry);
|
|
64
|
+
const dst = join(NEW_PROJECTS, entry);
|
|
65
|
+
if (existsSync(dst)) {
|
|
66
|
+
conflicts.push(`projects/${entry}: destination already present, left source untouched`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (dryRun) {
|
|
70
|
+
moved.push(`projects/${entry} (dry-run)`);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
renameSync(src, dst);
|
|
75
|
+
moved.push(`projects/${entry}`);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
conflicts.push(`projects/${entry}: ${err.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { moved, skipped, conflicts };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function migrateEcosystems({ dryRun }) {
|
|
84
|
+
const moved = [];
|
|
85
|
+
const skipped = [];
|
|
86
|
+
const conflicts = [];
|
|
87
|
+
|
|
88
|
+
if (!existsSync(LEGACY_ECOSYSTEMS)) {
|
|
89
|
+
skipped.push("ecosystems.json: legacy file absent");
|
|
90
|
+
return { moved, skipped, conflicts };
|
|
91
|
+
}
|
|
92
|
+
if (existsSync(NEW_ECOSYSTEMS)) {
|
|
93
|
+
conflicts.push("ecosystems.json: destination already present, left source untouched");
|
|
94
|
+
return { moved, skipped, conflicts };
|
|
95
|
+
}
|
|
96
|
+
if (dryRun) {
|
|
97
|
+
moved.push("ecosystems.json (dry-run)");
|
|
98
|
+
return { moved, skipped, conflicts };
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
renameSync(LEGACY_ECOSYSTEMS, NEW_ECOSYSTEMS);
|
|
102
|
+
moved.push("ecosystems.json");
|
|
103
|
+
} catch (err) {
|
|
104
|
+
conflicts.push(`ecosystems.json: ${err.message}`);
|
|
105
|
+
}
|
|
106
|
+
return { moved, skipped, conflicts };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function writeReport({ moved, skipped, conflicts, dryRun }) {
|
|
110
|
+
if (moved.length === 0 && conflicts.length === 0) return null;
|
|
111
|
+
if (!existsSync(LOGS_DIR)) mkdirSync(LOGS_DIR, { recursive: true });
|
|
112
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
113
|
+
const logPath = join(LOGS_DIR, `migration-${stamp}.log`);
|
|
114
|
+
const body = [
|
|
115
|
+
`ArkaOS user-data migration — ${new Date().toISOString()}`,
|
|
116
|
+
`Source: ${LEGACY_SKILLS_ROOT}`,
|
|
117
|
+
`Destination: ${USER_DATA_ROOT}`,
|
|
118
|
+
`Dry-run: ${dryRun}`,
|
|
119
|
+
"",
|
|
120
|
+
`Moved (${moved.length}):`,
|
|
121
|
+
...moved.map(m => ` - ${m}`),
|
|
122
|
+
"",
|
|
123
|
+
`Conflicts (${conflicts.length}):`,
|
|
124
|
+
...conflicts.map(c => ` - ${c}`),
|
|
125
|
+
"",
|
|
126
|
+
`Skipped (${skipped.length}):`,
|
|
127
|
+
...skipped.map(s => ` - ${s}`),
|
|
128
|
+
"",
|
|
129
|
+
].join("\n");
|
|
130
|
+
if (!dryRun) writeFileSync(logPath, body);
|
|
131
|
+
return logPath;
|
|
132
|
+
}
|
package/installer/update.js
CHANGED
|
@@ -267,7 +267,7 @@ export async function update() {
|
|
|
267
267
|
// main `/arka` skill, so any department skill (arka-dev, arka-brand,
|
|
268
268
|
// etc.) or sub-skill (arka-code-review, arka-viral, etc.) or agent
|
|
269
269
|
// persona added after the original install was silently missing on
|
|
270
|
-
// upgrade. Discovered during
|
|
270
|
+
// upgrade. Discovered during ClientAdvisory's bake-in: 233 top-level arka-*
|
|
271
271
|
// skills on his WSL (deployed long ago by install.sh) vs 1 skill on
|
|
272
272
|
// his Windows install (only the main /arka). The Node installer
|
|
273
273
|
// never deployed anything else.
|
package/package.json
CHANGED