arkaos 4.34.0 → 4.36.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 +460 -0
- package/config/install-profiles.json +75 -0
- package/core/runtime/opencode.py +252 -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/index.js
CHANGED
|
@@ -10,18 +10,33 @@ import { copyHookLib, copyHookAssets } from "./hook-lib.js";
|
|
|
10
10
|
import { deploySkills } from "./skill-deploy.js";
|
|
11
11
|
import { resolveSkillsMode } from "./skills-mode.js";
|
|
12
12
|
import { deployCoreSnapshot } from "./core-snapshot.js";
|
|
13
|
+
import { getUi } from "./ui.js";
|
|
14
|
+
import { buildProfileRecord } from "./profile.js";
|
|
15
|
+
import { readProductStats, productStatsLines } from "./product-stats.js";
|
|
13
16
|
|
|
14
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
18
|
const __dirname = dirname(__filename);
|
|
16
19
|
const ARKAOS_ROOT = resolve(__dirname, "..");
|
|
17
20
|
const VERSION = JSON.parse(readFileSync(join(ARKAOS_ROOT, "package.json"), "utf-8")).version;
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
// UI facade — set at the top of install(). step/ok/warn/detail below
|
|
23
|
+
// delegate to it; the plain facade prints the historical byte-identical
|
|
24
|
+
// output, so headless logs and tests remain stable.
|
|
25
|
+
let ui = null;
|
|
26
|
+
|
|
27
|
+
export async function install({ runtime, path, force, skipSystem, withOllama, profileFlag }) {
|
|
20
28
|
const startTime = Date.now();
|
|
21
29
|
const config = getRuntimeConfig(runtime);
|
|
22
30
|
const isUpgrade = existsSync(join(path || join(homedir(), ".arkaos"), "install-manifest.json"));
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
ui = await getUi();
|
|
33
|
+
if (ui.isFancy()) {
|
|
34
|
+
ui.intro(`▲ ARKA OS v${VERSION}`);
|
|
35
|
+
ui.clack.log.message(
|
|
36
|
+
`Runtime: ${config.name}\nMode: ${isUpgrade ? "Upgrade" : "Fresh install"}`,
|
|
37
|
+
);
|
|
38
|
+
} else {
|
|
39
|
+
console.log(`
|
|
25
40
|
╔══════════════════════════════════════════════════════════╗
|
|
26
41
|
║ ArkaOS v${VERSION} — The Operating System for AI Agent Teams ║
|
|
27
42
|
╚══════════════════════════════════════════════════════════╝
|
|
@@ -29,10 +44,11 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
29
44
|
Runtime: ${config.name}
|
|
30
45
|
Mode: ${isUpgrade ? "Upgrade" : "Fresh install"}
|
|
31
46
|
`);
|
|
47
|
+
}
|
|
32
48
|
|
|
33
49
|
// ═══ Interactive Setup ═══
|
|
34
50
|
const { runSetupPrompts } = await import("./prompts.js");
|
|
35
|
-
const userConfig = await runSetupPrompts(isUpgrade);
|
|
51
|
+
const userConfig = await runSetupPrompts(isUpgrade, { profileFlag });
|
|
36
52
|
const installDir = userConfig.installDir;
|
|
37
53
|
|
|
38
54
|
// ═══ Step 1: Create directories ═══
|
|
@@ -71,7 +87,7 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
71
87
|
const v1Found = v1Paths.find(p => existsSync(p));
|
|
72
88
|
if (v1Found && !existsSync(join(installDir, "migrated-from-v1"))) {
|
|
73
89
|
warn(`v1 detected at ${v1Found}`);
|
|
74
|
-
|
|
90
|
+
detail(" Run 'npx arkaos migrate' after install to migrate your data.");
|
|
75
91
|
} else {
|
|
76
92
|
ok("No v1 installation found");
|
|
77
93
|
}
|
|
@@ -80,13 +96,16 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
80
96
|
// Wrapped in try/catch so a regression in system-tools.js cannot break a
|
|
81
97
|
// fresh `npx arkaos install` for the ~20K user base. We degrade to a warn
|
|
82
98
|
// and proceed to venv creation rather than exiting non-zero.
|
|
99
|
+
// Foundation PR-3: the "local-ai" profile implies Ollama for the
|
|
100
|
+
// existing system-tools check. Full profile provisioning is PR-4.
|
|
101
|
+
const wantsOllama = withOllama || userConfig.installProfile === "local-ai";
|
|
83
102
|
if (!skipSystem) {
|
|
84
103
|
try {
|
|
85
104
|
const { ensureSystemTools } = await import("./system-tools.js");
|
|
86
105
|
const { formatSudoInstructions } = await import("./package-manager.js");
|
|
87
|
-
const sys = ensureSystemTools({ skipSystem: false, withOllama });
|
|
106
|
+
const sys = ensureSystemTools({ skipSystem: false, withOllama: wantsOllama });
|
|
88
107
|
if (sys.sudoCommands && sys.sudoCommands.length > 0) {
|
|
89
|
-
|
|
108
|
+
detail(formatSudoInstructions(sys.sudoCommands));
|
|
90
109
|
}
|
|
91
110
|
for (const tool of [sys.obsidian, sys.node, sys.ollama]) {
|
|
92
111
|
if (!tool) continue;
|
|
@@ -94,7 +113,7 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
94
113
|
else if (tool.needsAction === "none") ok(`${tool.name} ready`);
|
|
95
114
|
else warn(`${tool.name} ${tool.needsAction} — see commands above`);
|
|
96
115
|
}
|
|
97
|
-
if (
|
|
116
|
+
if (wantsOllama && sys.ollama?.needsAction === "none") {
|
|
98
117
|
ok("Ollama backend ready — cognitive layer can use local LLM inference");
|
|
99
118
|
}
|
|
100
119
|
} catch (err) {
|
|
@@ -119,7 +138,7 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
119
138
|
process.exit(1);
|
|
120
139
|
}
|
|
121
140
|
ok(`System Python found: ${systemPython}`);
|
|
122
|
-
const venvCreated = ensureVenv((msg) =>
|
|
141
|
+
const venvCreated = ensureVenv((msg) => detail(msg));
|
|
123
142
|
if (!venvCreated) {
|
|
124
143
|
warn("Venv creation failed — falling back to system Python (PEP 668 may apply)");
|
|
125
144
|
}
|
|
@@ -177,8 +196,8 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
177
196
|
if (existsSync(pyPsSrc) || existsSync(pyCmdSrc)) ok("arka-py interpreter shim installed (.cmd + .ps1)");
|
|
178
197
|
if (installed) {
|
|
179
198
|
ok("arka-claude wrapper installed (.cmd + .ps1)");
|
|
180
|
-
|
|
181
|
-
|
|
199
|
+
detail(` Add to PATH: setx PATH "%PATH%;%USERPROFILE%\\.arkaos\\bin"`);
|
|
200
|
+
detail(` Then reopen any shell and run: arka-claude`);
|
|
182
201
|
}
|
|
183
202
|
} else {
|
|
184
203
|
const wrapperSrc = join(ARKAOS_ROOT, "bin", "arka-claude");
|
|
@@ -186,8 +205,8 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
186
205
|
copyFileSync(wrapperSrc, join(binDir, "arka-claude"));
|
|
187
206
|
try { chmodSync(join(binDir, "arka-claude"), 0o755); } catch {}
|
|
188
207
|
ok("arka-claude wrapper installed");
|
|
189
|
-
|
|
190
|
-
|
|
208
|
+
detail(` Add to PATH: export PATH="$HOME/.arkaos/bin:$PATH"`);
|
|
209
|
+
detail(` Optional alias: alias claude="arka-claude"`);
|
|
191
210
|
}
|
|
192
211
|
// arka-py — the ArkaOS Python entrypoint SKILL.md commands invoke so the
|
|
193
212
|
// agent never runs a bare `python` that lacks ArkaOS deps (pyyaml, ...).
|
|
@@ -223,28 +242,24 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
223
242
|
ok("Core snapshot deployed to ~/.arkaos/lib (survives npx cache purges)");
|
|
224
243
|
}
|
|
225
244
|
} catch (err) {
|
|
226
|
-
|
|
245
|
+
detail(` ⚠ Core snapshot skipped (${err.message}) — arka-py falls back to .repo-path`);
|
|
227
246
|
}
|
|
228
247
|
const skillsDir = join(config.skillsDir || join(homedir(), ".claude", "skills"), "arkaos");
|
|
229
248
|
ensureDir(skillsDir);
|
|
230
249
|
writeFileSync(join(skillsDir, ".arkaos-root"), ARKAOS_ROOT);
|
|
231
250
|
|
|
232
251
|
const profilePath = join(installDir, "profile.json");
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
? JSON.parse(readFileSync(profilePath, "utf-8")).created
|
|
243
|
-
: new Date().toISOString(),
|
|
244
|
-
updated: new Date().toISOString(),
|
|
245
|
-
};
|
|
252
|
+
// Previous record (upgrade) feeds `created` preservation and the
|
|
253
|
+
// installProfile fallback chain — see installer/profile.js.
|
|
254
|
+
let previousProfile = null;
|
|
255
|
+
if (existsSync(profilePath)) {
|
|
256
|
+
try {
|
|
257
|
+
previousProfile = JSON.parse(readFileSync(profilePath, "utf-8"));
|
|
258
|
+
} catch { /* corrupt previous profile — treated as fresh */ }
|
|
259
|
+
}
|
|
260
|
+
const profile = buildProfileRecord(userConfig, previousProfile);
|
|
246
261
|
writeFileSync(profilePath, JSON.stringify(profile, null, 2));
|
|
247
|
-
ok(
|
|
262
|
+
ok(`Profile saved (${profile.installProfile})`);
|
|
248
263
|
|
|
249
264
|
// Save API keys if provided
|
|
250
265
|
if (userConfig.openaiKey || userConfig.googleKey || userConfig.falKey) {
|
|
@@ -312,16 +327,16 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
312
327
|
const { seedArkaosConfig } = await import("./config-seed.js");
|
|
313
328
|
const seedResult = seedArkaosConfig({ home: homedir() });
|
|
314
329
|
if (seedResult.action === "created") {
|
|
315
|
-
|
|
330
|
+
detail(` hardEnforcement enabled (default).`);
|
|
316
331
|
} else if (seedResult.action === "added-key") {
|
|
317
|
-
|
|
332
|
+
detail(` hardEnforcement enabled (key was unset).`);
|
|
318
333
|
} else if (seedResult.action === "preserved-user-false") {
|
|
319
|
-
|
|
334
|
+
detail(` hardEnforcement is OFF (user-set, preserved).`);
|
|
320
335
|
} else if (seedResult.action === "rewrote-corrupt") {
|
|
321
|
-
|
|
336
|
+
detail(` config.json was corrupt — rewrote, backup at ${seedResult.backup}`);
|
|
322
337
|
}
|
|
323
338
|
} catch (err) {
|
|
324
|
-
|
|
339
|
+
detail(` Warning: could not seed config.json (${err.message})`);
|
|
325
340
|
}
|
|
326
341
|
|
|
327
342
|
// Foundation PR-1 — auto-update daemon, default-on (opt-out persists
|
|
@@ -329,10 +344,41 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
329
344
|
try {
|
|
330
345
|
const { ensureDefaultEnabled } = await import("./autoupdate.js");
|
|
331
346
|
const au = ensureDefaultEnabled({ repoRoot: ARKAOS_ROOT });
|
|
332
|
-
if (au.action === "enabled")
|
|
333
|
-
else if (au.action === "optout")
|
|
347
|
+
if (au.action === "enabled") detail(` Auto-update daemon enabled (npx arkaos autoupdate status).`);
|
|
348
|
+
else if (au.action === "optout") detail(` Auto-update daemon: user opt-out respected.`);
|
|
334
349
|
} catch (err) {
|
|
335
|
-
|
|
350
|
+
detail(` Warning: auto-update daemon not enabled (${err.message})`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Foundation PR-5 — menu bar launcher (macOS only), default-on with
|
|
354
|
+
// persisted opt-out (npx arkaos menubar disable). rumps install and
|
|
355
|
+
// launchd wiring are best-effort: a failure can never break install.
|
|
356
|
+
// Guards (QG M3/M4): a LaunchAgent is system integration, so it
|
|
357
|
+
// honors --no-system and never touches CI runners; the opt-out is
|
|
358
|
+
// consulted BEFORE pip — a user who disabled the menu bar must not
|
|
359
|
+
// receive its dependency on every install.
|
|
360
|
+
if (process.platform === "darwin" && !skipSystem && !process.env.CI) {
|
|
361
|
+
try {
|
|
362
|
+
const { ensureDefaultEnabled: ensureMenubar, status: menubarStatus } =
|
|
363
|
+
await import("./menubar.js");
|
|
364
|
+
if (menubarStatus().optout) {
|
|
365
|
+
detail(" Menu bar launcher: user opt-out respected.");
|
|
366
|
+
} else {
|
|
367
|
+
if (pipInstall("rumps", { log: (m) => detail(m), timeout: 120000 })) {
|
|
368
|
+
ok("rumps installed (menu bar framework)");
|
|
369
|
+
} else {
|
|
370
|
+
warn("rumps install failed — menu bar app will hint on first run");
|
|
371
|
+
}
|
|
372
|
+
const mb = ensureMenubar({ repoRoot: ARKAOS_ROOT });
|
|
373
|
+
if (mb.action === "enabled") {
|
|
374
|
+
detail(" Menu bar launcher enabled (▲ in the macOS menu bar).");
|
|
375
|
+
} else if (mb.action === "partial") {
|
|
376
|
+
detail(` Menu bar launcher: ${mb.message}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} catch (err) {
|
|
380
|
+
detail(` Warning: could not enable menu bar launcher (${err.message})`);
|
|
381
|
+
}
|
|
336
382
|
}
|
|
337
383
|
|
|
338
384
|
// PR28 v2.47.0 — scaffold the user-mutable files the discipline-arc
|
|
@@ -342,13 +388,13 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
342
388
|
const { scaffoldArkaosUserData } = await import("./user-data-scaffold.js");
|
|
343
389
|
const scaffoldResult = scaffoldArkaosUserData({ home: homedir() });
|
|
344
390
|
if (scaffoldResult.redaction.action === "created") {
|
|
345
|
-
|
|
391
|
+
detail(` redaction-clients.json scaffolded (empty list — populate to enable leak scanner).`);
|
|
346
392
|
}
|
|
347
393
|
if (scaffoldResult.proposals.action === "created") {
|
|
348
|
-
|
|
394
|
+
detail(` reorganize-proposals/ directory created.`);
|
|
349
395
|
}
|
|
350
396
|
} catch (err) {
|
|
351
|
-
|
|
397
|
+
detail(` Warning: could not scaffold user-data (${err.message})`);
|
|
352
398
|
}
|
|
353
399
|
|
|
354
400
|
// PR45 v2.64.0 — seed autoMode.hard_deny defaults into
|
|
@@ -361,13 +407,13 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
361
407
|
const denyResult = seedAutoModeHardDeny({ runtime });
|
|
362
408
|
if (!denyResult.skipped) {
|
|
363
409
|
if (denyResult.action === "created") {
|
|
364
|
-
|
|
410
|
+
detail(` autoMode.hard_deny created (${denyResult.count} rules).`);
|
|
365
411
|
} else if (denyResult.action === "merged") {
|
|
366
|
-
|
|
412
|
+
detail(` autoMode.hard_deny merged (${denyResult.count} rules, operator entries preserved).`);
|
|
367
413
|
}
|
|
368
414
|
}
|
|
369
415
|
} catch (err) {
|
|
370
|
-
|
|
416
|
+
detail(` Warning: could not seed autoMode.hard_deny (${err.message})`);
|
|
371
417
|
}
|
|
372
418
|
|
|
373
419
|
// PR48 v2.67.0 — seed worktree.baseRef = "head" so new Claude Code
|
|
@@ -377,12 +423,12 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
377
423
|
const { seedWorktreeBaseRef } = await import("./worktree-baseref.js");
|
|
378
424
|
const wtResult = seedWorktreeBaseRef({ runtime });
|
|
379
425
|
if (!wtResult.skipped && wtResult.action === "created") {
|
|
380
|
-
|
|
426
|
+
detail(` worktree.baseRef set to "${wtResult.value}".`);
|
|
381
427
|
} else if (!wtResult.skipped && wtResult.action === "merged") {
|
|
382
|
-
|
|
428
|
+
detail(` worktree.baseRef merged ("${wtResult.value}").`);
|
|
383
429
|
}
|
|
384
430
|
} catch (err) {
|
|
385
|
-
|
|
431
|
+
detail(` Warning: could not seed worktree.baseRef (${err.message})`);
|
|
386
432
|
}
|
|
387
433
|
|
|
388
434
|
// Interaction Reform PR1 — install the ArkaOS output style and seed
|
|
@@ -395,14 +441,14 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
395
441
|
sourceDir: join(ARKAOS_ROOT, "config", "output-styles"),
|
|
396
442
|
});
|
|
397
443
|
if (styleResult.copied > 0) {
|
|
398
|
-
|
|
444
|
+
detail(` ${styleResult.copied} output style(s) installed (~/.claude/output-styles/).`);
|
|
399
445
|
}
|
|
400
446
|
const seedResult = seedOutputStyleDefault({ runtime });
|
|
401
447
|
if (!seedResult.skipped && seedResult.action === "created") {
|
|
402
|
-
|
|
448
|
+
detail(` outputStyle default set to "${seedResult.value}".`);
|
|
403
449
|
}
|
|
404
450
|
} catch (err) {
|
|
405
|
-
|
|
451
|
+
detail(` Warning: could not install output style (${err.message})`);
|
|
406
452
|
}
|
|
407
453
|
|
|
408
454
|
// PR43 v2.62.0 — auto-install default Claude Code plugins. Only runs
|
|
@@ -414,23 +460,23 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
414
460
|
if (!pluginResult.skipped) {
|
|
415
461
|
for (const m of pluginResult.marketplaces || []) {
|
|
416
462
|
if (m.action === "added") {
|
|
417
|
-
|
|
463
|
+
detail(` marketplace ${m.marketplace} added.`);
|
|
418
464
|
} else if (m.action === "failed") {
|
|
419
|
-
|
|
465
|
+
detail(` marketplace ${m.marketplace} failed (${m.reason}).`);
|
|
420
466
|
}
|
|
421
467
|
}
|
|
422
468
|
for (const r of pluginResult.results) {
|
|
423
469
|
if (r.action === "installed") {
|
|
424
|
-
|
|
470
|
+
detail(` ${r.plugin} installed.`);
|
|
425
471
|
} else if (r.action === "already-present") {
|
|
426
|
-
|
|
472
|
+
detail(` ${r.plugin} already installed (skipped).`);
|
|
427
473
|
} else if (r.action === "failed") {
|
|
428
|
-
|
|
474
|
+
detail(` ${r.plugin} install failed (${r.reason}).`);
|
|
429
475
|
}
|
|
430
476
|
}
|
|
431
477
|
}
|
|
432
478
|
} catch (err) {
|
|
433
|
-
|
|
479
|
+
detail(` Warning: could not install default Claude plugins (${err.message})`);
|
|
434
480
|
}
|
|
435
481
|
|
|
436
482
|
// Frontend UI/UX tooling — Magic MCP (user scope, API-key gated) + Motion
|
|
@@ -439,19 +485,19 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
439
485
|
const { setupFrontendTooling } = await import("./frontend-tooling.js");
|
|
440
486
|
const ft = await setupFrontendTooling({ runtime });
|
|
441
487
|
if (ft.magicMcp?.action === "registered") {
|
|
442
|
-
|
|
488
|
+
detail(" Magic MCP registered (user scope).");
|
|
443
489
|
} else if (ft.magicMcp?.action === "already-present") {
|
|
444
|
-
|
|
490
|
+
detail(" Magic MCP already registered (skipped).");
|
|
445
491
|
} else if (ft.magicMcp?.action === "failed") {
|
|
446
|
-
|
|
492
|
+
detail(` Magic MCP registration failed (${ft.magicMcp.reason}).`);
|
|
447
493
|
}
|
|
448
494
|
if (ft.motionKit?.action === "installed") {
|
|
449
|
-
|
|
495
|
+
detail(" Motion AI Kit installed.");
|
|
450
496
|
} else if (ft.motionKit?.action === "failed") {
|
|
451
|
-
|
|
497
|
+
detail(` Motion AI Kit install failed (${ft.motionKit.reason}).`);
|
|
452
498
|
}
|
|
453
499
|
} catch (err) {
|
|
454
|
-
|
|
500
|
+
detail(` Warning: could not set up frontend tooling (${err.message})`);
|
|
455
501
|
}
|
|
456
502
|
|
|
457
503
|
// Graphify grounding layer — code knowledge graphs (PyPI `graphifyy`,
|
|
@@ -461,24 +507,24 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
461
507
|
const { ensureGraphify, configureGraphifyHttp } = await import("./graphify.js");
|
|
462
508
|
const gf = ensureGraphify();
|
|
463
509
|
if (gf.binary?.installed) {
|
|
464
|
-
|
|
510
|
+
detail(` Graphify ready${gf.binary.version ? ` (v${gf.binary.version})` : ""}.`);
|
|
465
511
|
if (gf.skillInstall?.action === "installed") {
|
|
466
|
-
|
|
512
|
+
detail(" Graphify skill registered (graphify install).");
|
|
467
513
|
} else if (gf.skillInstall?.action === "failed") {
|
|
468
|
-
|
|
514
|
+
detail(` Graphify skill registration failed (${gf.skillInstall.reason}).`);
|
|
469
515
|
}
|
|
470
516
|
} else if (gf.binary?.hint) {
|
|
471
|
-
|
|
517
|
+
detail(` ${gf.binary.hint}`);
|
|
472
518
|
}
|
|
473
519
|
// Graphify HTTP knowledge-graph MCP (user-scope, config-driven endpoint).
|
|
474
520
|
const gh = await configureGraphifyHttp({ runtime });
|
|
475
521
|
if (gh.action === "registered" || gh.action === "re-registered") {
|
|
476
|
-
|
|
522
|
+
detail(` Graphify knowledge-graph MCP ${gh.action} (user scope).`);
|
|
477
523
|
} else if (gh.action === "failed") {
|
|
478
|
-
|
|
524
|
+
detail(` Graphify knowledge-graph MCP not registered (${gh.reason}).`);
|
|
479
525
|
}
|
|
480
526
|
} catch (err) {
|
|
481
|
-
|
|
527
|
+
detail(` Warning: could not set up Graphify (${err.message})`);
|
|
482
528
|
}
|
|
483
529
|
|
|
484
530
|
const manifest = {
|
|
@@ -516,16 +562,41 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
516
562
|
|
|
517
563
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
518
564
|
|
|
519
|
-
|
|
565
|
+
// Counts derived from the shipped artifacts — never hand-typed
|
|
566
|
+
// (docs-as-code). Null fields are omitted from the summary.
|
|
567
|
+
const stats = readProductStats(ARKAOS_ROOT);
|
|
568
|
+
const statLines = productStatsLines(stats);
|
|
569
|
+
|
|
570
|
+
if (ui.isFancy()) {
|
|
571
|
+
ui.stopSpinner();
|
|
572
|
+
const warnCount = ui.warnings().length;
|
|
573
|
+
ui.note(
|
|
574
|
+
[
|
|
575
|
+
`Runtime: ${config.name}`,
|
|
576
|
+
`Install dir: ${installDir}`,
|
|
577
|
+
`Profile: ${profile.installProfile}`,
|
|
578
|
+
...statLines,
|
|
579
|
+
`Dashboard: npx arkaos dashboard`,
|
|
580
|
+
warnCount > 0 ? `Warnings: ${warnCount} (see above)` : null,
|
|
581
|
+
``,
|
|
582
|
+
`Quick start: /arka · /do <description> · /dev feature`,
|
|
583
|
+
]
|
|
584
|
+
.filter((l) => l !== null)
|
|
585
|
+
.join("\n"),
|
|
586
|
+
`ArkaOS v${VERSION} installed (${elapsed}s)`,
|
|
587
|
+
);
|
|
588
|
+
ui.outro("Open Claude Code and run /arka to get started.");
|
|
589
|
+
} else {
|
|
590
|
+
const plainStatLines = statLines.map((l) => ` ${l}`).join("\n");
|
|
591
|
+
console.log(`
|
|
520
592
|
╔══════════════════════════════════════════════════════════╗
|
|
521
593
|
║ ArkaOS v${VERSION} installed successfully! (${elapsed}s) ║
|
|
522
594
|
╚══════════════════════════════════════════════════════════╝
|
|
523
595
|
|
|
524
596
|
Runtime: ${config.name}
|
|
525
597
|
Install dir: ${installDir}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
Knowledge: Vector DB with semantic search
|
|
598
|
+
Profile: ${profile.installProfile}
|
|
599
|
+
${plainStatLines ? plainStatLines + "\n" : ""} Knowledge: Vector DB with semantic search
|
|
529
600
|
Dashboard: Run 'npx arkaos dashboard' to start
|
|
530
601
|
|
|
531
602
|
Quick start:
|
|
@@ -541,22 +612,37 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
541
612
|
npx arkaos keys — Configure API keys
|
|
542
613
|
npx arkaos doctor — Run health checks
|
|
543
614
|
`);
|
|
615
|
+
}
|
|
544
616
|
}
|
|
545
617
|
|
|
546
618
|
// ═══ Helper Functions ═══
|
|
619
|
+
// All four delegate to the UI facade when install() has resolved it;
|
|
620
|
+
// the plain facade (and the pre-resolution fallback) prints the exact
|
|
621
|
+
// historical strings, so non-fancy output is byte-identical.
|
|
547
622
|
|
|
548
623
|
function step(n, total, msg) {
|
|
624
|
+
if (ui) return ui.step(n, total, msg);
|
|
549
625
|
console.log(` [${n}/${total}] ${msg}`);
|
|
550
626
|
}
|
|
551
627
|
|
|
552
628
|
function ok(msg) {
|
|
629
|
+
if (ui) return ui.ok(msg);
|
|
553
630
|
console.log(` ✓ ${msg}`);
|
|
554
631
|
}
|
|
555
632
|
|
|
556
633
|
function warn(msg) {
|
|
634
|
+
if (ui) return ui.warn(msg);
|
|
557
635
|
console.log(` ⚠ ${msg}`);
|
|
558
636
|
}
|
|
559
637
|
|
|
638
|
+
// Secondary info lines (pip progress, PATH hints, seed results). Fancy
|
|
639
|
+
// mode folds them into the active spinner; plain mode prints them
|
|
640
|
+
// unchanged.
|
|
641
|
+
function detail(msg) {
|
|
642
|
+
if (ui) return ui.detail(msg);
|
|
643
|
+
console.log(msg);
|
|
644
|
+
}
|
|
645
|
+
|
|
560
646
|
function ensureDir(dir) {
|
|
561
647
|
if (!existsSync(dir)) {
|
|
562
648
|
mkdirSync(dir, { recursive: true });
|
|
@@ -564,7 +650,7 @@ function ensureDir(dir) {
|
|
|
564
650
|
}
|
|
565
651
|
|
|
566
652
|
function installAllPythonDeps(userConfig = {}) {
|
|
567
|
-
const log = (msg) =>
|
|
653
|
+
const log = (msg) => detail(msg);
|
|
568
654
|
|
|
569
655
|
// Core dependencies
|
|
570
656
|
const coreDeps = "pyyaml pydantic rich click jinja2";
|
|
@@ -582,7 +668,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
582
668
|
const transcriptionDeps = "faster-whisper";
|
|
583
669
|
|
|
584
670
|
// Core deps (required)
|
|
585
|
-
|
|
671
|
+
detail(" Installing core dependencies...");
|
|
586
672
|
if (pipInstall(coreDeps, { log })) {
|
|
587
673
|
ok("Core deps installed (pyyaml, pydantic, rich, click, jinja2)");
|
|
588
674
|
} else {
|
|
@@ -594,7 +680,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
594
680
|
// is reported accurately and the user knows which capability they
|
|
595
681
|
// actually have.
|
|
596
682
|
if (userConfig.installKnowledge !== false) {
|
|
597
|
-
|
|
683
|
+
detail(" Installing knowledge base dependencies...");
|
|
598
684
|
const fastembedOk = pipInstall("fastembed", { log, timeout: 180000 });
|
|
599
685
|
const sqliteVssOk = pipInstall("sqlite-vec", { log, timeout: 180000 });
|
|
600
686
|
if (fastembedOk && sqliteVssOk) {
|
|
@@ -609,7 +695,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
609
695
|
}
|
|
610
696
|
|
|
611
697
|
// Ingest deps
|
|
612
|
-
|
|
698
|
+
detail(" Installing content ingest dependencies...");
|
|
613
699
|
if (pipInstall(ingestDeps, { log })) {
|
|
614
700
|
ok("Ingest deps installed (yt-dlp, pdfplumber, beautifulsoup4)");
|
|
615
701
|
} else {
|
|
@@ -618,7 +704,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
618
704
|
|
|
619
705
|
// Dashboard deps (optional)
|
|
620
706
|
if (userConfig.installDashboard !== false) {
|
|
621
|
-
|
|
707
|
+
detail(" Installing dashboard dependencies...");
|
|
622
708
|
if (pipInstall(dashboardDeps, { log, timeout: 120000 })) {
|
|
623
709
|
ok("Dashboard API installed (fastapi, uvicorn, python-multipart)");
|
|
624
710
|
} else {
|
|
@@ -627,7 +713,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
627
713
|
}
|
|
628
714
|
|
|
629
715
|
// Transcription (optional, heavy)
|
|
630
|
-
|
|
716
|
+
detail(" Installing transcription engine...");
|
|
631
717
|
if (pipInstall(transcriptionDeps, { log, timeout: 300000 })) {
|
|
632
718
|
ok("Whisper transcription installed");
|
|
633
719
|
} else {
|
|
@@ -635,7 +721,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
635
721
|
}
|
|
636
722
|
|
|
637
723
|
// Install ArkaOS core package as editable
|
|
638
|
-
|
|
724
|
+
detail(" Installing ArkaOS core engine...");
|
|
639
725
|
if (pipInstall("", { editable: ARKAOS_ROOT, log, timeout: 60000 })) {
|
|
640
726
|
ok("ArkaOS core engine installed");
|
|
641
727
|
} else {
|
|
@@ -1056,13 +1142,13 @@ function printSchtasksAccessDeniedHelp(pythonPath, daemonPath) {
|
|
|
1056
1142
|
// nice-to-have that keeps background tasks ticking. We print the
|
|
1057
1143
|
// manual registration command so power users can elevate once and
|
|
1058
1144
|
// run it, and move on.
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1145
|
+
detail(" Access denied. Options:");
|
|
1146
|
+
detail(" 1) Re-run the installer from an elevated PowerShell (Run as Administrator)");
|
|
1147
|
+
detail(" 2) Or register the task manually from an elevated prompt:");
|
|
1148
|
+
detail(` schtasks /Create /F /TN "ArkaOS-Scheduler" /SC ONLOGON /TR "\"${pythonPath}\" \"${daemonPath}\""`);
|
|
1149
|
+
detail(" 3) Or skip the scheduler and launch the daemon manually when needed:");
|
|
1150
|
+
detail(` "${pythonPath}" "${daemonPath}"`);
|
|
1151
|
+
detail(" The rest of ArkaOS is installed and functional — this only affects background task automation.");
|
|
1066
1152
|
}
|
|
1067
1153
|
|
|
1068
1154
|
function installSchtasksService(daemonPath) {
|
|
@@ -1119,7 +1205,7 @@ function installSchtasksService(daemonPath) {
|
|
|
1119
1205
|
if (kind === "access-denied") {
|
|
1120
1206
|
printSchtasksAccessDeniedHelp(pythonPath, daemonPath);
|
|
1121
1207
|
} else {
|
|
1122
|
-
|
|
1208
|
+
detail(" Try manually: schtasks /Create /F /TN \"ArkaOS-Scheduler\" /SC ONLOGON /TR \"" + pythonPath + " " + daemonPath + "\"");
|
|
1123
1209
|
}
|
|
1124
1210
|
return;
|
|
1125
1211
|
}
|
|
@@ -1129,9 +1215,9 @@ function installSchtasksService(daemonPath) {
|
|
|
1129
1215
|
const kind = classifySchtasksError(runResult.stderr);
|
|
1130
1216
|
warn(`Scheduler: task created but /Run failed (${kind}): ${runResult.stderr.slice(0, 220)}`);
|
|
1131
1217
|
if (kind === "access-denied") {
|
|
1132
|
-
|
|
1218
|
+
detail(" Task is registered but couldn't be started now. It will run automatically at next logon.");
|
|
1133
1219
|
} else {
|
|
1134
|
-
|
|
1220
|
+
detail(" Task will start at next logon");
|
|
1135
1221
|
}
|
|
1136
1222
|
return;
|
|
1137
1223
|
}
|
|
@@ -1146,7 +1232,7 @@ export async function loadAdapter(runtime) {
|
|
|
1146
1232
|
} catch {
|
|
1147
1233
|
return {
|
|
1148
1234
|
configureHooks(config, installDir) {
|
|
1149
|
-
|
|
1235
|
+
detail(` Using generic configuration for ${runtime}`);
|
|
1150
1236
|
},
|
|
1151
1237
|
};
|
|
1152
1238
|
}
|