arkaos 4.34.0 → 4.35.0
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/THE-ARKAOS-GUIDE.md +1 -1
- package/VERSION +1 -1
- package/bin/arka-menubar.py +407 -0
- package/config/install-profiles.json +75 -0
- package/core/runtime/opencode.py +113 -0
- package/core/runtime/registry.py +6 -1
- package/harness/codex/AGENTS.md +1 -1
- package/harness/copilot/copilot-instructions.md +1 -1
- package/harness/cursor/rules/arkaos.mdc +2 -2
- package/harness/gemini/GEMINI.md +1 -1
- package/harness/opencode/AGENTS.md +1 -1
- package/harness/opencode/agents/arka-architect-gabriel.md +12 -0
- package/harness/opencode/agents/arka-brand-director-valentina.md +12 -0
- package/harness/opencode/agents/arka-cfo-helena.md +12 -0
- package/harness/opencode/agents/arka-chief-of-staff-afonso.md +12 -0
- package/harness/opencode/agents/arka-community-strategist-beatriz.md +12 -0
- package/harness/opencode/agents/arka-content-strategist-rafael.md +12 -0
- package/harness/opencode/agents/arka-conversion-strategist-ines.md +12 -0
- package/harness/opencode/agents/arka-coo-sofia.md +12 -0
- package/harness/opencode/agents/arka-copy-director-eduardo.md +12 -0
- package/harness/opencode/agents/arka-cqo-marta.md +12 -0
- package/harness/opencode/agents/arka-cto-marco.md +12 -0
- package/harness/opencode/agents/arka-design-ops-lead-iris.md +12 -0
- package/harness/opencode/agents/arka-ecom-director-ricardo.md +12 -0
- package/harness/opencode/agents/arka-knowledge-director-clara.md +12 -0
- package/harness/opencode/agents/arka-leadership-director-rodrigo.md +12 -0
- package/harness/opencode/agents/arka-marketing-director-luna.md +12 -0
- package/harness/opencode/agents/arka-ops-lead-daniel.md +12 -0
- package/harness/opencode/agents/arka-pm-director-carolina.md +12 -0
- package/harness/opencode/agents/arka-revops-lead-vicente.md +12 -0
- package/harness/opencode/agents/arka-saas-strategist-tiago.md +12 -0
- package/harness/opencode/agents/arka-sales-director-miguel.md +12 -0
- package/harness/opencode/agents/arka-strategy-director-tomas.md +12 -0
- package/harness/opencode/agents/arka-tech-director-francisca.md +12 -0
- package/harness/opencode/agents/arka-tech-lead-paulo.md +12 -0
- package/harness/opencode/agents/arka-video-producer-simao.md +12 -0
- package/harness/opencode/commands/arka-brand.md +9 -0
- package/harness/opencode/commands/arka-community.md +9 -0
- package/harness/opencode/commands/arka-content.md +9 -0
- package/harness/opencode/commands/arka-dev.md +9 -0
- package/harness/opencode/commands/arka-ecom.md +9 -0
- package/harness/opencode/commands/arka-fin.md +9 -0
- package/harness/opencode/commands/arka-kb.md +9 -0
- package/harness/opencode/commands/arka-landing.md +9 -0
- package/harness/opencode/commands/arka-lead.md +9 -0
- package/harness/opencode/commands/arka-mkt.md +9 -0
- package/harness/opencode/commands/arka-ops.md +9 -0
- package/harness/opencode/commands/arka-org.md +9 -0
- package/harness/opencode/commands/arka-pm.md +9 -0
- package/harness/opencode/commands/arka-saas.md +9 -0
- package/harness/opencode/commands/arka-sales.md +9 -0
- package/harness/opencode/commands/arka-strat.md +9 -0
- package/harness/opencode/opencode.json +16 -0
- package/harness/zed/.rules +1 -1
- package/installer/adapters/opencode.js +118 -0
- package/installer/cli.js +31 -1
- package/installer/detect-runtime.js +18 -0
- package/installer/doctor.js +202 -2
- package/installer/index.js +174 -88
- package/installer/menubar.js +262 -0
- package/installer/product-stats.js +93 -0
- package/installer/profile.js +75 -0
- package/installer/prompts.js +303 -41
- package/installer/services.js +487 -0
- package/installer/ui.js +190 -0
- package/installer/update.js +212 -95
- package/knowledge/skills-manifest.json +1 -1
- package/package.json +6 -1
- package/pyproject.toml +1 -1
- package/scripts/harness_gen.py +98 -1
package/installer/update.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync, copyFileSync, chmodSync, mkdir
|
|
|
2
2
|
import { join, dirname, resolve } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { execSync } from "node:child_process";
|
|
5
|
-
import {
|
|
5
|
+
import { ensureVenvHealthy, getArkaosPython, pipInstall } from "./python-resolver.js";
|
|
6
6
|
import { copyHookLib, copyHookAssets } from "./hook-lib.js";
|
|
7
7
|
import { deploySkills } from "./skill-deploy.js";
|
|
8
8
|
import { deprecationNotice, resolveSkillsMode } from "./skills-mode.js";
|
|
@@ -12,13 +12,41 @@ import { loadAdapter } from "./index.js";
|
|
|
12
12
|
import { migrateUserData, printMigrationReport } from "./migrate-user-data.js";
|
|
13
13
|
import { resolveFile } from "./path-resolver.js";
|
|
14
14
|
import { IS_WINDOWS, HOOK_EXT } from "./platform.js";
|
|
15
|
+
import { getUi } from "./ui.js";
|
|
15
16
|
import { fileURLToPath } from "node:url";
|
|
16
17
|
|
|
17
18
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
19
|
const ARKAOS_ROOT = resolve(__dirname, "..");
|
|
19
20
|
const VERSION = JSON.parse(readFileSync(join(ARKAOS_ROOT, "package.json"), "utf-8")).version;
|
|
20
21
|
|
|
22
|
+
// UI facade — set at the top of update(). The helpers below delegate to
|
|
23
|
+
// it; the plain facade prints the historical byte-identical strings, so
|
|
24
|
+
// the auto-update daemon's headless logs remain stable. Update normally
|
|
25
|
+
// runs headless (non-TTY), so fancy mode only appears on manual runs.
|
|
26
|
+
let ui = null;
|
|
27
|
+
|
|
28
|
+
function section(n, total, msg) {
|
|
29
|
+
if (ui) return ui.section(n, total, msg);
|
|
30
|
+
console.log(` [${n}/${total}] ${msg}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ok(msg) {
|
|
34
|
+
if (ui) return ui.ok(msg);
|
|
35
|
+
console.log(` ✓ ${msg}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function warn(msg) {
|
|
39
|
+
if (ui) return ui.warn(msg);
|
|
40
|
+
console.log(` ⚠ ${msg}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function detail(msg) {
|
|
44
|
+
if (ui) return ui.detail(msg);
|
|
45
|
+
console.log(msg);
|
|
46
|
+
}
|
|
47
|
+
|
|
21
48
|
export async function update({ skillsFlag = "" } = {}) {
|
|
49
|
+
ui = await getUi();
|
|
22
50
|
const installDir = join(homedir(), ".arkaos");
|
|
23
51
|
const manifestPath = join(installDir, "install-manifest.json");
|
|
24
52
|
const profilePath = join(installDir, "profile.json");
|
|
@@ -40,7 +68,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
40
68
|
try {
|
|
41
69
|
migrateLegacyHookState(homedir(), installDir);
|
|
42
70
|
} catch (err) {
|
|
43
|
-
|
|
71
|
+
warn(`Legacy hook state migration skipped: ${err.message}`);
|
|
44
72
|
}
|
|
45
73
|
|
|
46
74
|
// User-data separation (ADR 2026-04-17): move descriptors and ecosystems
|
|
@@ -48,7 +76,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
48
76
|
try {
|
|
49
77
|
printMigrationReport(migrateUserData());
|
|
50
78
|
} catch (err) {
|
|
51
|
-
|
|
79
|
+
warn(`User-data migration skipped: ${err.message}`);
|
|
52
80
|
}
|
|
53
81
|
|
|
54
82
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -64,13 +92,20 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
64
92
|
}).toString().trim();
|
|
65
93
|
} catch {}
|
|
66
94
|
|
|
67
|
-
|
|
95
|
+
if (ui.isFancy()) {
|
|
96
|
+
ui.intro(`▲ ARKA OS v${VERSION} — Update`);
|
|
97
|
+
ui.clack.log.message(
|
|
98
|
+
`Installed: v${manifest.version}\nPackage: v${VERSION}\nLatest: v${latestVersion}`,
|
|
99
|
+
);
|
|
100
|
+
} else {
|
|
101
|
+
console.log(`
|
|
68
102
|
ArkaOS Update
|
|
69
103
|
─────────────
|
|
70
104
|
Installed: v${manifest.version}
|
|
71
105
|
Package: v${VERSION}
|
|
72
106
|
Latest: v${latestVersion}
|
|
73
107
|
`);
|
|
108
|
+
}
|
|
74
109
|
|
|
75
110
|
// Dev-checkout detection: when ArkaOS is being run from a local git
|
|
76
111
|
// clone (as opposed to a published `npx arkaos@latest` install), the
|
|
@@ -94,38 +129,50 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
94
129
|
const forceRequested = process.argv.includes("--force");
|
|
95
130
|
|
|
96
131
|
if (versionsMatch && !forceRequested && !isDevCheckout) {
|
|
97
|
-
|
|
132
|
+
if (ui.isFancy()) {
|
|
133
|
+
ui.outro("Already up to date.");
|
|
134
|
+
} else {
|
|
135
|
+
console.log(" ✓ Already up to date.\n");
|
|
136
|
+
}
|
|
98
137
|
return;
|
|
99
138
|
}
|
|
100
139
|
|
|
101
140
|
if (isDevCheckout && versionsMatch && !forceRequested) {
|
|
102
|
-
|
|
141
|
+
if (ui.isFancy()) {
|
|
142
|
+
ui.clack.log.info("Dev checkout detected — running update even though version matches.");
|
|
143
|
+
} else {
|
|
144
|
+
console.log(" ℹ Dev checkout detected — running update even though version matches.\n");
|
|
145
|
+
}
|
|
103
146
|
}
|
|
104
147
|
|
|
105
|
-
|
|
148
|
+
if (ui.isFancy()) {
|
|
149
|
+
ui.clack.log.message("Updating (keeping your configuration)...");
|
|
150
|
+
} else {
|
|
151
|
+
console.log(" Updating (keeping your configuration)...\n");
|
|
152
|
+
}
|
|
106
153
|
|
|
107
154
|
// ── 1. Update Python deps (using venv) ──
|
|
108
|
-
|
|
155
|
+
section(1, 9, "Updating Python dependencies...");
|
|
109
156
|
|
|
110
157
|
// Ensure venv is healthy (creates, repairs broken symlinks, or no-ops).
|
|
111
158
|
// PR2 v3.73.1 — previously a stale broken-symlink venv could pass the
|
|
112
159
|
// existence check, and the dashboard would silently fall back to ambient
|
|
113
160
|
// python3 without sqlite-vec/fastembed.
|
|
114
|
-
const venvHealth = ensureVenvHealthy({ log: (msg) =>
|
|
161
|
+
const venvHealth = ensureVenvHealthy({ log: (msg) => detail(msg) });
|
|
115
162
|
if (!venvHealth.healthy) {
|
|
116
|
-
|
|
163
|
+
warn(`Venv unhealthy (${venvHealth.reason}) - falling back to system Python with PEP 668 handling`);
|
|
117
164
|
} else if (venvHealth.repaired) {
|
|
118
|
-
|
|
165
|
+
ok(`Venv repaired (${venvHealth.reason})`);
|
|
119
166
|
}
|
|
120
167
|
|
|
121
168
|
const pythonCmd = getArkaosPython();
|
|
122
|
-
const log = (msg) =>
|
|
169
|
+
const log = (msg) => detail(msg);
|
|
123
170
|
|
|
124
171
|
// Core deps (always upgrade)
|
|
125
172
|
if (pipInstall("pyyaml pydantic rich click jinja2", { upgrade: true, log })) {
|
|
126
|
-
|
|
173
|
+
ok("Core deps updated");
|
|
127
174
|
} else {
|
|
128
|
-
|
|
175
|
+
warn("Core deps update failed");
|
|
129
176
|
}
|
|
130
177
|
|
|
131
178
|
// Only update optional deps if they were installed before
|
|
@@ -139,42 +186,42 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
139
186
|
const fastembedOk = pipInstall("fastembed", { upgrade: true, log, timeout: 180000 });
|
|
140
187
|
const sqliteVssOk = pipInstall("sqlite-vec", { upgrade: true, log, timeout: 180000 });
|
|
141
188
|
if (fastembedOk && sqliteVssOk) {
|
|
142
|
-
|
|
189
|
+
ok("Knowledge deps updated (fastembed, sqlite-vec)");
|
|
143
190
|
} else if (fastembedOk) {
|
|
144
|
-
|
|
191
|
+
warn("fastembed upgraded but sqlite-vec failed \u2014 semantic search degraded");
|
|
145
192
|
} else if (sqliteVssOk) {
|
|
146
|
-
|
|
193
|
+
warn("sqlite-vec upgraded but fastembed failed \u2014 embedding pipeline degraded");
|
|
147
194
|
} else {
|
|
148
|
-
|
|
195
|
+
warn("Knowledge deps upgrade failed \u2014 run: npx arkaos doctor");
|
|
149
196
|
}
|
|
150
197
|
}
|
|
151
198
|
|
|
152
199
|
if (pyCheck("fastapi")) {
|
|
153
200
|
if (pipInstall("fastapi uvicorn", { upgrade: true, log, timeout: 60000 })) {
|
|
154
|
-
|
|
201
|
+
ok("Dashboard deps updated");
|
|
155
202
|
}
|
|
156
203
|
}
|
|
157
204
|
|
|
158
205
|
// Always install ArkaOS core engine
|
|
159
206
|
if (pipInstall("", { editable: ARKAOS_ROOT, log, timeout: 60000 })) {
|
|
160
|
-
|
|
207
|
+
ok("ArkaOS core engine installed");
|
|
161
208
|
} else {
|
|
162
|
-
|
|
209
|
+
warn("Core engine install failed — run: npx arkaos doctor");
|
|
163
210
|
}
|
|
164
211
|
|
|
165
212
|
// ── 2. Update config files ──
|
|
166
|
-
|
|
213
|
+
section(2, 9, "Updating configuration...");
|
|
167
214
|
const constitutionSrc = join(ARKAOS_ROOT, "config", "constitution.yaml");
|
|
168
215
|
mkdirSync(join(installDir, "config"), { recursive: true });
|
|
169
216
|
if (existsSync(constitutionSrc)) {
|
|
170
217
|
copyFileSync(constitutionSrc, join(installDir, "config", "constitution.yaml"));
|
|
171
|
-
|
|
218
|
+
ok("Constitution updated");
|
|
172
219
|
}
|
|
173
220
|
const statuslineFile = IS_WINDOWS ? "statusline.ps1" : "statusline.sh";
|
|
174
221
|
const statuslineSrc = join(ARKAOS_ROOT, "config", statuslineFile);
|
|
175
222
|
if (existsSync(statuslineSrc)) {
|
|
176
223
|
copyFileSync(statuslineSrc, join(installDir, "config", statuslineFile));
|
|
177
|
-
|
|
224
|
+
ok("Statusline updated");
|
|
178
225
|
}
|
|
179
226
|
// Interaction Reform PR1 — refresh the ArkaOS output style file and
|
|
180
227
|
// seed the default (if-absent; explicit operator choice preserved).
|
|
@@ -184,20 +231,20 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
184
231
|
sourceDir: join(ARKAOS_ROOT, "config", "output-styles"),
|
|
185
232
|
});
|
|
186
233
|
if (styleResult.copied > 0) {
|
|
187
|
-
|
|
234
|
+
ok("Output style updated");
|
|
188
235
|
}
|
|
189
236
|
const seedResult = seedOutputStyleDefault({
|
|
190
237
|
runtime: manifest.runtime || "claude-code",
|
|
191
238
|
});
|
|
192
239
|
if (!seedResult.skipped && seedResult.action === "created") {
|
|
193
|
-
|
|
240
|
+
ok(`outputStyle default set to "${seedResult.value}"`);
|
|
194
241
|
}
|
|
195
242
|
} catch (err) {
|
|
196
|
-
|
|
243
|
+
warn(`Output style update failed (${err.message})`);
|
|
197
244
|
}
|
|
198
245
|
|
|
199
246
|
// ── 3. Update hooks ──
|
|
200
|
-
|
|
247
|
+
section(3, 9, "Updating hooks...");
|
|
201
248
|
// Keep this list in lockstep with installer/index.js::installHooks and
|
|
202
249
|
// installer/adapters/claude-code.js::hookCommand. Platform-aware: .ps1
|
|
203
250
|
// on Windows, .sh everywhere else.
|
|
@@ -240,21 +287,21 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
240
287
|
try { chmodSync(destPath, 0o755); } catch {}
|
|
241
288
|
}
|
|
242
289
|
}
|
|
243
|
-
|
|
290
|
+
ok("Hook scripts updated");
|
|
244
291
|
|
|
245
292
|
// Shared hook libraries (config/hooks/_lib/ — the Python interpreter
|
|
246
293
|
// resolver lives here). The hooks deployed above source
|
|
247
294
|
// _lib/arka_python.sh from the install dir, so skipping this copy
|
|
248
295
|
// leaves them falling back to a bare `python3` without ArkaOS deps.
|
|
249
296
|
if (copyHookLib(srcHooksDir, destHooksDir)) {
|
|
250
|
-
|
|
297
|
+
ok("Hook lib updated (_lib/)");
|
|
251
298
|
}
|
|
252
299
|
|
|
253
300
|
// F2-6 fast-path shims + gate manifest (same shared deploy as the
|
|
254
301
|
// fresh-install path — single asset list in hook-lib.js).
|
|
255
302
|
const assetCount = copyHookAssets(srcHooksDir, destHooksDir);
|
|
256
303
|
if (assetCount > 0) {
|
|
257
|
-
|
|
304
|
+
ok(`Hook fast-path assets updated (${assetCount})`);
|
|
258
305
|
}
|
|
259
306
|
|
|
260
307
|
// Re-register hooks in the runtime's settings file.
|
|
@@ -268,14 +315,14 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
268
315
|
if (runtimeConfig) {
|
|
269
316
|
const adapter = await loadAdapter(runtimeId);
|
|
270
317
|
adapter.configureHooks(runtimeConfig, installDir);
|
|
271
|
-
|
|
318
|
+
ok("Hooks re-registered in settings");
|
|
272
319
|
}
|
|
273
320
|
} catch (err) {
|
|
274
|
-
|
|
321
|
+
warn(`Could not re-register hooks: ${err.message}`);
|
|
275
322
|
}
|
|
276
323
|
|
|
277
324
|
// ── 4. Update CLI wrapper + user CLAUDE.md ──
|
|
278
|
-
|
|
325
|
+
section(4, 9, "Updating CLI wrapper and user instructions...");
|
|
279
326
|
const binDir = join(installDir, "bin");
|
|
280
327
|
mkdirSync(binDir, { recursive: true });
|
|
281
328
|
|
|
@@ -286,27 +333,27 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
286
333
|
if (existsSync(psSrc)) copyFileSync(psSrc, join(binDir, "arka-claude.ps1"));
|
|
287
334
|
if (existsSync(cmdSrc)) copyFileSync(cmdSrc, join(binDir, "arka-claude.cmd"));
|
|
288
335
|
if (existsSync(psSrc) || existsSync(cmdSrc)) {
|
|
289
|
-
|
|
336
|
+
ok("arka-claude wrapper updated (.cmd + .ps1)");
|
|
290
337
|
}
|
|
291
338
|
const pyPsSrc = join(ARKAOS_ROOT, "bin", "arka-py.ps1");
|
|
292
339
|
const pyCmdSrc = join(ARKAOS_ROOT, "bin", "arka-py.cmd");
|
|
293
340
|
if (existsSync(pyPsSrc)) copyFileSync(pyPsSrc, join(binDir, "arka-py.ps1"));
|
|
294
341
|
if (existsSync(pyCmdSrc)) copyFileSync(pyCmdSrc, join(binDir, "arka-py.cmd"));
|
|
295
342
|
if (existsSync(pyPsSrc) || existsSync(pyCmdSrc)) {
|
|
296
|
-
|
|
343
|
+
ok("arka-py interpreter shim updated (.cmd + .ps1)");
|
|
297
344
|
}
|
|
298
345
|
} else {
|
|
299
346
|
const wrapperSrc = join(ARKAOS_ROOT, "bin", "arka-claude");
|
|
300
347
|
if (existsSync(wrapperSrc)) {
|
|
301
348
|
copyFileSync(wrapperSrc, join(binDir, "arka-claude"));
|
|
302
349
|
try { chmodSync(join(binDir, "arka-claude"), 0o755); } catch {}
|
|
303
|
-
|
|
350
|
+
ok("arka-claude wrapper updated");
|
|
304
351
|
}
|
|
305
352
|
const arkaPySrc = join(ARKAOS_ROOT, "bin", "arka-py");
|
|
306
353
|
if (existsSync(arkaPySrc)) {
|
|
307
354
|
copyFileSync(arkaPySrc, join(binDir, "arka-py"));
|
|
308
355
|
try { chmodSync(join(binDir, "arka-py"), 0o755); } catch {}
|
|
309
|
-
|
|
356
|
+
ok("arka-py interpreter shim updated");
|
|
310
357
|
}
|
|
311
358
|
}
|
|
312
359
|
const userClaudeMd = join(homedir(), ".claude", "CLAUDE.md");
|
|
@@ -314,11 +361,11 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
314
361
|
if (existsSync(claudeMdSrc)) {
|
|
315
362
|
mkdirSync(join(homedir(), ".claude"), { recursive: true });
|
|
316
363
|
copyFileSync(claudeMdSrc, userClaudeMd);
|
|
317
|
-
|
|
364
|
+
ok("~/.claude/CLAUDE.md updated");
|
|
318
365
|
}
|
|
319
366
|
|
|
320
367
|
// ── 5. Update Cognitive Scheduler ──
|
|
321
|
-
|
|
368
|
+
section(5, 9, "Updating cognitive scheduler...");
|
|
322
369
|
updateCognitiveScheduler(installDir, ARKAOS_ROOT);
|
|
323
370
|
|
|
324
371
|
// ── 6. Update /arka skill + department skills + sub-skills + agents ──
|
|
@@ -332,7 +379,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
332
379
|
// skills on his WSL (deployed long ago by install.sh) vs 1 skill on
|
|
333
380
|
// his Windows install (only the main /arka). The Node installer
|
|
334
381
|
// never deployed anything else.
|
|
335
|
-
|
|
382
|
+
section(6, 9, "Updating /arka skill...");
|
|
336
383
|
const skillsBase = join(homedir(), ".claude", "skills");
|
|
337
384
|
const skillDest = join(skillsBase, "arka");
|
|
338
385
|
// Single shared deployment (installer/skill-deploy.js) — identical
|
|
@@ -342,7 +389,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
342
389
|
// before F2-7c-pre) + agent personas.
|
|
343
390
|
const skillsMode = resolveSkillsMode({ flag: skillsFlag, fresh: false });
|
|
344
391
|
if (skillsMode.deprecated) {
|
|
345
|
-
|
|
392
|
+
detail(" " + deprecationNotice());
|
|
346
393
|
}
|
|
347
394
|
const skillCounts = deploySkills({
|
|
348
395
|
repoRoot: ARKAOS_ROOT,
|
|
@@ -351,19 +398,19 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
351
398
|
version: VERSION,
|
|
352
399
|
mode: skillsMode.mode,
|
|
353
400
|
});
|
|
354
|
-
|
|
355
|
-
if (skillCounts.main)
|
|
401
|
+
ok(`skill set mode: ${skillsMode.mode}`);
|
|
402
|
+
if (skillCounts.main) ok("/arka skill updated");
|
|
356
403
|
if (skillCounts.depts > 0) {
|
|
357
|
-
|
|
404
|
+
ok(`${skillCounts.depts} department skills updated`);
|
|
358
405
|
}
|
|
359
406
|
if (skillCounts.subs > 0) {
|
|
360
|
-
|
|
407
|
+
ok(`${skillCounts.subs} sub-skills updated`);
|
|
361
408
|
}
|
|
362
409
|
if (skillCounts.meta > 0) {
|
|
363
|
-
|
|
410
|
+
ok(`${skillCounts.meta} meta skills updated`);
|
|
364
411
|
}
|
|
365
412
|
if (skillCounts.agents > 0) {
|
|
366
|
-
|
|
413
|
+
ok(`${skillCounts.agents} agent personas updated`);
|
|
367
414
|
}
|
|
368
415
|
|
|
369
416
|
// MCP infrastructure: deploy mcps/ subdirectories, registry, and
|
|
@@ -412,11 +459,11 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
412
459
|
}
|
|
413
460
|
}
|
|
414
461
|
|
|
415
|
-
|
|
462
|
+
ok("MCP infrastructure updated (profiles, stacks, scripts, arka-prompts + arka-tools servers)");
|
|
416
463
|
|
|
417
464
|
// Higgsfield MCP is registered but requires an account + API key to connect.
|
|
418
465
|
// Non-blocking warning: the update succeeds even without a Higgsfield account.
|
|
419
|
-
|
|
466
|
+
warn("Higgsfield MCP in registry — requires a Higgsfield account + HIGGSFIELD_API_KEY to connect (https://higgsfield.ai). Add per-project: bash apply-mcps.sh --add higgsfield");
|
|
420
467
|
}
|
|
421
468
|
|
|
422
469
|
// ── 6b. Copy feature registry for sync engine ──
|
|
@@ -429,7 +476,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
429
476
|
copyFileSync(join(featuresSource, file), join(featuresDest, file));
|
|
430
477
|
}
|
|
431
478
|
if (featureFiles.length > 0) {
|
|
432
|
-
|
|
479
|
+
ok(`Feature registry: ${featureFiles.length} features copied`);
|
|
433
480
|
}
|
|
434
481
|
}
|
|
435
482
|
|
|
@@ -449,7 +496,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
449
496
|
// flow; update.js previously only wrote the first, which is a
|
|
450
497
|
// latent bug that surfaces any time a user runs update from a
|
|
451
498
|
// different clone than the original install.
|
|
452
|
-
|
|
499
|
+
section(7, 9, "Updating references...");
|
|
453
500
|
writeFileSync(join(installDir, ".repo-path"), ARKAOS_ROOT);
|
|
454
501
|
// .repo-path points at the npx cache, which `npm cache clean` can purge;
|
|
455
502
|
// refresh the ~/.arkaos/lib snapshot so arka-py and the Python hooks
|
|
@@ -458,19 +505,19 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
458
505
|
// .repo-path (and any previous snapshot is preserved by the safe swap).
|
|
459
506
|
try {
|
|
460
507
|
if (deployCoreSnapshot(ARKAOS_ROOT, installDir)) {
|
|
461
|
-
|
|
508
|
+
ok("Core snapshot refreshed in ~/.arkaos/lib");
|
|
462
509
|
}
|
|
463
510
|
} catch (err) {
|
|
464
|
-
|
|
511
|
+
warn(`Core snapshot skipped (${err.message}) — arka-py falls back to .repo-path`);
|
|
465
512
|
}
|
|
466
513
|
const skillsArkaosDir = join(homedir(), ".claude", "skills", "arkaos");
|
|
467
514
|
if (existsSync(skillsArkaosDir)) {
|
|
468
515
|
writeFileSync(join(skillsArkaosDir, ".arkaos-root"), ARKAOS_ROOT);
|
|
469
|
-
|
|
516
|
+
ok("Repo path + skills alias updated");
|
|
470
517
|
} else {
|
|
471
518
|
// Fresh install never ran (or user deleted the skills alias);
|
|
472
519
|
// don't recreate it here — that's the install flow's job.
|
|
473
|
-
|
|
520
|
+
ok("Repo path updated (skills alias not present)");
|
|
474
521
|
}
|
|
475
522
|
|
|
476
523
|
// ── 7b. Frontend UI/UX tooling + Claude plugins ──
|
|
@@ -485,27 +532,27 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
485
532
|
const pluginResult = installDefaultClaudePlugins({ runtime: toolingRuntime });
|
|
486
533
|
if (!pluginResult.skipped) {
|
|
487
534
|
for (const m of pluginResult.marketplaces || []) {
|
|
488
|
-
if (m.action === "added")
|
|
489
|
-
else if (m.action === "failed")
|
|
535
|
+
if (m.action === "added") ok(`marketplace ${m.marketplace} added`);
|
|
536
|
+
else if (m.action === "failed") warn(`marketplace ${m.marketplace} failed (${m.reason})`);
|
|
490
537
|
}
|
|
491
538
|
for (const r of pluginResult.results) {
|
|
492
|
-
if (r.action === "installed")
|
|
493
|
-
else if (r.action === "failed")
|
|
539
|
+
if (r.action === "installed") ok(`${r.plugin} installed`);
|
|
540
|
+
else if (r.action === "failed") warn(`${r.plugin} failed (${r.reason})`);
|
|
494
541
|
}
|
|
495
542
|
}
|
|
496
543
|
} catch (err) {
|
|
497
|
-
|
|
544
|
+
warn(`Could not update Claude plugins (${err.message})`);
|
|
498
545
|
}
|
|
499
546
|
try {
|
|
500
547
|
const { setupFrontendTooling } = await import("./frontend-tooling.js");
|
|
501
548
|
const ft = await setupFrontendTooling({ runtime: toolingRuntime });
|
|
502
|
-
if (ft.magicMcp?.action === "registered")
|
|
503
|
-
else if (ft.magicMcp?.action === "already-present")
|
|
504
|
-
else if (ft.magicMcp?.action === "failed")
|
|
505
|
-
if (ft.motionKit?.action === "installed")
|
|
506
|
-
else if (ft.motionKit?.action === "failed")
|
|
549
|
+
if (ft.magicMcp?.action === "registered") ok("Magic MCP registered (user scope)");
|
|
550
|
+
else if (ft.magicMcp?.action === "already-present") ok("Magic MCP already registered");
|
|
551
|
+
else if (ft.magicMcp?.action === "failed") warn(`Magic MCP failed (${ft.magicMcp.reason})`);
|
|
552
|
+
if (ft.motionKit?.action === "installed") ok("Motion AI Kit installed");
|
|
553
|
+
else if (ft.motionKit?.action === "failed") warn(`Motion AI Kit failed (${ft.motionKit.reason})`);
|
|
507
554
|
} catch (err) {
|
|
508
|
-
|
|
555
|
+
warn(`Could not set up frontend tooling (${err.message})`);
|
|
509
556
|
}
|
|
510
557
|
|
|
511
558
|
// Graphify grounding layer — same wiring as installer/index.js. Best
|
|
@@ -514,45 +561,69 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
514
561
|
const { ensureGraphify, configureGraphifyHttp } = await import("./graphify.js");
|
|
515
562
|
const gf = ensureGraphify();
|
|
516
563
|
if (gf.binary?.installed) {
|
|
517
|
-
|
|
564
|
+
ok(`Graphify ready${gf.binary.version ? ` (v${gf.binary.version})` : ""}`);
|
|
518
565
|
if (gf.skillInstall?.action === "installed") {
|
|
519
|
-
|
|
566
|
+
ok("Graphify skill registered (graphify install)");
|
|
520
567
|
} else if (gf.skillInstall?.action === "failed") {
|
|
521
|
-
|
|
568
|
+
warn(`Graphify skill registration failed (${gf.skillInstall.reason})`);
|
|
522
569
|
}
|
|
523
570
|
} else if (gf.binary?.hint) {
|
|
524
|
-
|
|
571
|
+
warn(`${gf.binary.hint}`);
|
|
525
572
|
}
|
|
526
573
|
// Graphify HTTP knowledge-graph MCP (user-scope, config-driven endpoint).
|
|
527
574
|
const gh = await configureGraphifyHttp({ runtime: toolingRuntime });
|
|
528
575
|
if (gh.action === "registered" || gh.action === "re-registered") {
|
|
529
|
-
|
|
576
|
+
ok(`Graphify knowledge-graph MCP ${gh.action} (user scope)`);
|
|
530
577
|
} else if (gh.action === "failed") {
|
|
531
|
-
|
|
578
|
+
warn(`Graphify knowledge-graph MCP not registered (${gh.reason})`);
|
|
532
579
|
}
|
|
533
580
|
} catch (err) {
|
|
534
|
-
|
|
581
|
+
warn(`Could not set up Graphify (${err.message})`);
|
|
535
582
|
}
|
|
536
583
|
|
|
537
584
|
// ── 7b. Auto-update daemon (Foundation PR-1) — default-on, opt-out kept ──
|
|
538
585
|
try {
|
|
539
586
|
const { ensureDefaultEnabled } = await import("./autoupdate.js");
|
|
540
587
|
const au = ensureDefaultEnabled({ repoRoot: ARKAOS_ROOT });
|
|
541
|
-
if (au.action === "enabled")
|
|
542
|
-
else if (au.action === "already-enabled")
|
|
543
|
-
else if (au.action === "optout")
|
|
588
|
+
if (au.action === "enabled") ok("Auto-update daemon enabled (daily npm check + notification)");
|
|
589
|
+
else if (au.action === "already-enabled") ok("Auto-update daemon active");
|
|
590
|
+
else if (au.action === "optout") detail(" · Auto-update daemon: user opt-out respected");
|
|
544
591
|
} catch (err) {
|
|
545
|
-
|
|
592
|
+
warn(`Auto-update daemon not enabled (${err.message})`);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// ── 7c. Menu bar launcher (Foundation PR-5) — macOS, default-on ──
|
|
596
|
+
// Opt-out consulted BEFORE pip (QG M3): a disabled menu bar must not
|
|
597
|
+
// cost its dependency on every daemon update. CI runners never get
|
|
598
|
+
// LaunchAgents (QG M4).
|
|
599
|
+
if (process.platform === "darwin" && !process.env.CI) {
|
|
600
|
+
try {
|
|
601
|
+
const { ensureDefaultEnabled: ensureMenubar, status: menubarStatus } =
|
|
602
|
+
await import("./menubar.js");
|
|
603
|
+
if (menubarStatus().optout) {
|
|
604
|
+
detail(" · Menu bar launcher: user opt-out respected");
|
|
605
|
+
} else {
|
|
606
|
+
if (!pipInstall("rumps", { log, timeout: 120000 })) {
|
|
607
|
+
warn("rumps install failed — menu bar app will hint on first run");
|
|
608
|
+
}
|
|
609
|
+
const mb = ensureMenubar({ repoRoot: ARKAOS_ROOT });
|
|
610
|
+
if (mb.action === "enabled") ok("Menu bar launcher enabled (▲ in the macOS menu bar)");
|
|
611
|
+
else if (mb.action === "already-enabled") ok("Menu bar launcher active");
|
|
612
|
+
else if (mb.action === "partial") warn(`Menu bar launcher: ${mb.message}`);
|
|
613
|
+
}
|
|
614
|
+
} catch (err) {
|
|
615
|
+
warn(`Menu bar launcher not enabled (${err.message})`);
|
|
616
|
+
}
|
|
546
617
|
}
|
|
547
618
|
|
|
548
619
|
// ── 8. Update manifest ──
|
|
549
|
-
|
|
620
|
+
section(8, 9, "Finalizing...");
|
|
550
621
|
manifest.version = VERSION;
|
|
551
622
|
manifest.repoRoot = ARKAOS_ROOT;
|
|
552
623
|
manifest.pythonCmd = pythonCmd;
|
|
553
624
|
manifest.updatedAt = new Date().toISOString();
|
|
554
625
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
555
|
-
|
|
626
|
+
ok("Manifest updated");
|
|
556
627
|
|
|
557
628
|
// Reset sync state to trigger /arka update on next session
|
|
558
629
|
const syncStatePath = join(installDir, "sync-state.json");
|
|
@@ -566,9 +637,54 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
566
637
|
core_updated_at: new Date().toISOString()
|
|
567
638
|
};
|
|
568
639
|
writeFileSync(syncStatePath, JSON.stringify(syncState, null, 2));
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
640
|
+
ok("Sync state reset (auto-detected on next Claude session)");
|
|
641
|
+
|
|
642
|
+
// ── 9. Reconcile profile services (Foundation PR-4) ──
|
|
643
|
+
// Headless by design (the auto-update daemon runs this): only
|
|
644
|
+
// consent-free services install; consent-gated ones (ffmpeg, ollama)
|
|
645
|
+
// report a copy-paste hint. A service failure warns and continues —
|
|
646
|
+
// reconciliation can NEVER block the update.
|
|
647
|
+
section(9, 9, "Reconciling profile services...");
|
|
648
|
+
try {
|
|
649
|
+
const { normalizeProfileFlag } = await import("./profile.js");
|
|
650
|
+
const { reconcileServices } = await import("./services.js");
|
|
651
|
+
const installProfile = normalizeProfileFlag(profile.installProfile) || "essential";
|
|
652
|
+
const results = await reconcileServices({
|
|
653
|
+
profile: installProfile,
|
|
654
|
+
repoRoot: ARKAOS_ROOT,
|
|
655
|
+
interactive: false,
|
|
656
|
+
log: (msg) => detail(msg),
|
|
657
|
+
});
|
|
658
|
+
ok(`profile: ${installProfile}`);
|
|
659
|
+
for (const r of results) {
|
|
660
|
+
if (r.status === "present") ok(`${r.label} present`);
|
|
661
|
+
else if (r.status === "installed") ok(`${r.label} installed`);
|
|
662
|
+
else if (r.status === "skipped") detail(` · ${r.label} skipped${r.hint ? ` — ${r.hint}` : ""}`);
|
|
663
|
+
else warn(`${r.label} failed${r.hint ? ` — ${r.hint}` : ""}`);
|
|
664
|
+
}
|
|
665
|
+
} catch (err) {
|
|
666
|
+
warn(`Profile service reconciliation skipped (${err.message})`);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (ui.isFancy()) {
|
|
670
|
+
ui.stopSpinner();
|
|
671
|
+
const warnCount = ui.warnings().length;
|
|
672
|
+
ui.note(
|
|
673
|
+
[
|
|
674
|
+
`Language: ${profile.language || "not set"}`,
|
|
675
|
+
`Market: ${profile.market || "not set"}`,
|
|
676
|
+
`Projects: ${profile.projectsDir || "not set"}`,
|
|
677
|
+
`Vault: ${profile.vaultPath || "not set"}`,
|
|
678
|
+
`Profile: ${profile.installProfile || "essential"}`,
|
|
679
|
+
warnCount > 0 ? `Warnings: ${warnCount} (see above)` : null,
|
|
680
|
+
]
|
|
681
|
+
.filter((l) => l !== null)
|
|
682
|
+
.join("\n"),
|
|
683
|
+
`ArkaOS updated to v${VERSION} — configuration preserved`,
|
|
684
|
+
);
|
|
685
|
+
ui.outro("Next Claude Code session auto-detects the update and syncs your projects.");
|
|
686
|
+
} else {
|
|
687
|
+
console.log(`
|
|
572
688
|
╔══════════════════════════════════════════╗
|
|
573
689
|
║ ArkaOS updated to v${VERSION} ║
|
|
574
690
|
╚══════════════════════════════════════════╝
|
|
@@ -582,6 +698,7 @@ export async function update({ skillsFlag = "" } = {}) {
|
|
|
582
698
|
Next time you open Claude Code, ArkaOS will automatically
|
|
583
699
|
detect the update and sync all your projects.
|
|
584
700
|
`);
|
|
701
|
+
}
|
|
585
702
|
}
|
|
586
703
|
|
|
587
704
|
function ensureDir(dir) {
|
|
@@ -670,8 +787,8 @@ function migrateLegacyHookState(homeDir, installDir) {
|
|
|
670
787
|
}
|
|
671
788
|
|
|
672
789
|
if (migrated > 0) {
|
|
673
|
-
|
|
674
|
-
|
|
790
|
+
ok(`Migrated ${migrated} legacy hook state file(s) from ~/.arka-os/`);
|
|
791
|
+
detail(` (original files left in place for v1 coexistence)`);
|
|
675
792
|
}
|
|
676
793
|
}
|
|
677
794
|
|
|
@@ -682,7 +799,7 @@ function updateCognitiveScheduler(installDir, arkaosRoot) {
|
|
|
682
799
|
const schedSrc = join(arkaosRoot, "config", "cognition", "schedules.yaml");
|
|
683
800
|
if (existsSync(schedSrc)) {
|
|
684
801
|
copyFileSync(schedSrc, join(installDir, "schedules.yaml"));
|
|
685
|
-
|
|
802
|
+
ok("Schedule config updated");
|
|
686
803
|
}
|
|
687
804
|
|
|
688
805
|
// 2. Update prompt files
|
|
@@ -699,7 +816,7 @@ function updateCognitiveScheduler(installDir, arkaosRoot) {
|
|
|
699
816
|
copyFileSync(src, dst);
|
|
700
817
|
}
|
|
701
818
|
}
|
|
702
|
-
|
|
819
|
+
ok("Cognitive prompts updated");
|
|
703
820
|
}
|
|
704
821
|
|
|
705
822
|
// 3. Update daemon script and core modules
|
|
@@ -709,7 +826,7 @@ function updateCognitiveScheduler(installDir, arkaosRoot) {
|
|
|
709
826
|
if (existsSync(daemonSrc)) {
|
|
710
827
|
copyFileSync(daemonSrc, join(binDir, "scheduler-daemon.py"));
|
|
711
828
|
try { chmodSync(join(binDir, "scheduler-daemon.py"), 0o755); } catch {}
|
|
712
|
-
|
|
829
|
+
ok("Scheduler daemon updated");
|
|
713
830
|
}
|
|
714
831
|
|
|
715
832
|
// 3b. Update scheduler core modules (daemon imports these at runtime)
|
|
@@ -734,7 +851,7 @@ function updateCognitiveScheduler(installDir, arkaosRoot) {
|
|
|
734
851
|
ensureDir(dirname(dest));
|
|
735
852
|
writeFileSync(dest, '"""ArkaOS — deployed subset for scheduler."""\n');
|
|
736
853
|
}
|
|
737
|
-
|
|
854
|
+
ok("Scheduler core modules updated");
|
|
738
855
|
|
|
739
856
|
// 4. Ensure log directories
|
|
740
857
|
ensureDir(join(installDir, "logs", "dreaming"));
|
|
@@ -749,9 +866,9 @@ function updateCognitiveScheduler(installDir, arkaosRoot) {
|
|
|
749
866
|
try {
|
|
750
867
|
execSync(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "pipe" });
|
|
751
868
|
execSync(`launchctl load "${plistPath}"`, { stdio: "pipe" });
|
|
752
|
-
|
|
869
|
+
ok("Scheduler service restarted (launchd)");
|
|
753
870
|
} catch {
|
|
754
|
-
|
|
871
|
+
warn("Scheduler reload failed — restart manually");
|
|
755
872
|
}
|
|
756
873
|
} else {
|
|
757
874
|
// First time — install the service
|
|
@@ -800,17 +917,17 @@ function updateCognitiveScheduler(installDir, arkaosRoot) {
|
|
|
800
917
|
writeFileSync(plistPath, plist);
|
|
801
918
|
try {
|
|
802
919
|
execSync(`launchctl load "${plistPath}"`, { stdio: "pipe" });
|
|
803
|
-
|
|
920
|
+
ok("Scheduler service installed and started (launchd)");
|
|
804
921
|
} catch {
|
|
805
|
-
|
|
922
|
+
warn("Scheduler plist written but load failed");
|
|
806
923
|
}
|
|
807
924
|
}
|
|
808
925
|
} else if (platform === "linux") {
|
|
809
926
|
try {
|
|
810
927
|
execSync("systemctl --user restart arkaos-scheduler.service 2>/dev/null", { stdio: "pipe" });
|
|
811
|
-
|
|
928
|
+
ok("Scheduler service restarted (systemd)");
|
|
812
929
|
} catch {
|
|
813
|
-
|
|
930
|
+
warn("Scheduler not running — install with: npx arkaos install");
|
|
814
931
|
}
|
|
815
932
|
}
|
|
816
933
|
}
|