arkaos 4.33.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/hooks/session-start.sh +1 -1
- package/config/install-profiles.json +75 -0
- package/config/statusline.sh +6 -1
- package/core/hooks/session_start.py +69 -28
- 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/autoupdate.js +249 -0
- package/installer/cli.js +38 -1
- package/installer/core-snapshot.js +5 -1
- package/installer/detect-runtime.js +18 -0
- package/installer/doctor.js +213 -2
- package/installer/index.js +182 -85
- 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 +219 -91
- package/knowledge/skills-manifest.json +1 -1
- package/package.json +6 -1
- package/pyproject.toml +1 -1
- package/scripts/auto-update.sh +188 -0
- 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,58 @@ 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})`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Foundation PR-1 — auto-update daemon, default-on (opt-out persists
|
|
343
|
+
// across installs via ~/.arkaos/autoupdate.optout).
|
|
344
|
+
try {
|
|
345
|
+
const { ensureDefaultEnabled } = await import("./autoupdate.js");
|
|
346
|
+
const au = ensureDefaultEnabled({ repoRoot: ARKAOS_ROOT });
|
|
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.`);
|
|
349
|
+
} catch (err) {
|
|
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
|
+
}
|
|
325
382
|
}
|
|
326
383
|
|
|
327
384
|
// PR28 v2.47.0 — scaffold the user-mutable files the discipline-arc
|
|
@@ -331,13 +388,13 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
331
388
|
const { scaffoldArkaosUserData } = await import("./user-data-scaffold.js");
|
|
332
389
|
const scaffoldResult = scaffoldArkaosUserData({ home: homedir() });
|
|
333
390
|
if (scaffoldResult.redaction.action === "created") {
|
|
334
|
-
|
|
391
|
+
detail(` redaction-clients.json scaffolded (empty list — populate to enable leak scanner).`);
|
|
335
392
|
}
|
|
336
393
|
if (scaffoldResult.proposals.action === "created") {
|
|
337
|
-
|
|
394
|
+
detail(` reorganize-proposals/ directory created.`);
|
|
338
395
|
}
|
|
339
396
|
} catch (err) {
|
|
340
|
-
|
|
397
|
+
detail(` Warning: could not scaffold user-data (${err.message})`);
|
|
341
398
|
}
|
|
342
399
|
|
|
343
400
|
// PR45 v2.64.0 — seed autoMode.hard_deny defaults into
|
|
@@ -350,13 +407,13 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
350
407
|
const denyResult = seedAutoModeHardDeny({ runtime });
|
|
351
408
|
if (!denyResult.skipped) {
|
|
352
409
|
if (denyResult.action === "created") {
|
|
353
|
-
|
|
410
|
+
detail(` autoMode.hard_deny created (${denyResult.count} rules).`);
|
|
354
411
|
} else if (denyResult.action === "merged") {
|
|
355
|
-
|
|
412
|
+
detail(` autoMode.hard_deny merged (${denyResult.count} rules, operator entries preserved).`);
|
|
356
413
|
}
|
|
357
414
|
}
|
|
358
415
|
} catch (err) {
|
|
359
|
-
|
|
416
|
+
detail(` Warning: could not seed autoMode.hard_deny (${err.message})`);
|
|
360
417
|
}
|
|
361
418
|
|
|
362
419
|
// PR48 v2.67.0 — seed worktree.baseRef = "head" so new Claude Code
|
|
@@ -366,12 +423,12 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
366
423
|
const { seedWorktreeBaseRef } = await import("./worktree-baseref.js");
|
|
367
424
|
const wtResult = seedWorktreeBaseRef({ runtime });
|
|
368
425
|
if (!wtResult.skipped && wtResult.action === "created") {
|
|
369
|
-
|
|
426
|
+
detail(` worktree.baseRef set to "${wtResult.value}".`);
|
|
370
427
|
} else if (!wtResult.skipped && wtResult.action === "merged") {
|
|
371
|
-
|
|
428
|
+
detail(` worktree.baseRef merged ("${wtResult.value}").`);
|
|
372
429
|
}
|
|
373
430
|
} catch (err) {
|
|
374
|
-
|
|
431
|
+
detail(` Warning: could not seed worktree.baseRef (${err.message})`);
|
|
375
432
|
}
|
|
376
433
|
|
|
377
434
|
// Interaction Reform PR1 — install the ArkaOS output style and seed
|
|
@@ -384,14 +441,14 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
384
441
|
sourceDir: join(ARKAOS_ROOT, "config", "output-styles"),
|
|
385
442
|
});
|
|
386
443
|
if (styleResult.copied > 0) {
|
|
387
|
-
|
|
444
|
+
detail(` ${styleResult.copied} output style(s) installed (~/.claude/output-styles/).`);
|
|
388
445
|
}
|
|
389
446
|
const seedResult = seedOutputStyleDefault({ runtime });
|
|
390
447
|
if (!seedResult.skipped && seedResult.action === "created") {
|
|
391
|
-
|
|
448
|
+
detail(` outputStyle default set to "${seedResult.value}".`);
|
|
392
449
|
}
|
|
393
450
|
} catch (err) {
|
|
394
|
-
|
|
451
|
+
detail(` Warning: could not install output style (${err.message})`);
|
|
395
452
|
}
|
|
396
453
|
|
|
397
454
|
// PR43 v2.62.0 — auto-install default Claude Code plugins. Only runs
|
|
@@ -403,23 +460,23 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
403
460
|
if (!pluginResult.skipped) {
|
|
404
461
|
for (const m of pluginResult.marketplaces || []) {
|
|
405
462
|
if (m.action === "added") {
|
|
406
|
-
|
|
463
|
+
detail(` marketplace ${m.marketplace} added.`);
|
|
407
464
|
} else if (m.action === "failed") {
|
|
408
|
-
|
|
465
|
+
detail(` marketplace ${m.marketplace} failed (${m.reason}).`);
|
|
409
466
|
}
|
|
410
467
|
}
|
|
411
468
|
for (const r of pluginResult.results) {
|
|
412
469
|
if (r.action === "installed") {
|
|
413
|
-
|
|
470
|
+
detail(` ${r.plugin} installed.`);
|
|
414
471
|
} else if (r.action === "already-present") {
|
|
415
|
-
|
|
472
|
+
detail(` ${r.plugin} already installed (skipped).`);
|
|
416
473
|
} else if (r.action === "failed") {
|
|
417
|
-
|
|
474
|
+
detail(` ${r.plugin} install failed (${r.reason}).`);
|
|
418
475
|
}
|
|
419
476
|
}
|
|
420
477
|
}
|
|
421
478
|
} catch (err) {
|
|
422
|
-
|
|
479
|
+
detail(` Warning: could not install default Claude plugins (${err.message})`);
|
|
423
480
|
}
|
|
424
481
|
|
|
425
482
|
// Frontend UI/UX tooling — Magic MCP (user scope, API-key gated) + Motion
|
|
@@ -428,19 +485,19 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
428
485
|
const { setupFrontendTooling } = await import("./frontend-tooling.js");
|
|
429
486
|
const ft = await setupFrontendTooling({ runtime });
|
|
430
487
|
if (ft.magicMcp?.action === "registered") {
|
|
431
|
-
|
|
488
|
+
detail(" Magic MCP registered (user scope).");
|
|
432
489
|
} else if (ft.magicMcp?.action === "already-present") {
|
|
433
|
-
|
|
490
|
+
detail(" Magic MCP already registered (skipped).");
|
|
434
491
|
} else if (ft.magicMcp?.action === "failed") {
|
|
435
|
-
|
|
492
|
+
detail(` Magic MCP registration failed (${ft.magicMcp.reason}).`);
|
|
436
493
|
}
|
|
437
494
|
if (ft.motionKit?.action === "installed") {
|
|
438
|
-
|
|
495
|
+
detail(" Motion AI Kit installed.");
|
|
439
496
|
} else if (ft.motionKit?.action === "failed") {
|
|
440
|
-
|
|
497
|
+
detail(` Motion AI Kit install failed (${ft.motionKit.reason}).`);
|
|
441
498
|
}
|
|
442
499
|
} catch (err) {
|
|
443
|
-
|
|
500
|
+
detail(` Warning: could not set up frontend tooling (${err.message})`);
|
|
444
501
|
}
|
|
445
502
|
|
|
446
503
|
// Graphify grounding layer — code knowledge graphs (PyPI `graphifyy`,
|
|
@@ -450,24 +507,24 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
450
507
|
const { ensureGraphify, configureGraphifyHttp } = await import("./graphify.js");
|
|
451
508
|
const gf = ensureGraphify();
|
|
452
509
|
if (gf.binary?.installed) {
|
|
453
|
-
|
|
510
|
+
detail(` Graphify ready${gf.binary.version ? ` (v${gf.binary.version})` : ""}.`);
|
|
454
511
|
if (gf.skillInstall?.action === "installed") {
|
|
455
|
-
|
|
512
|
+
detail(" Graphify skill registered (graphify install).");
|
|
456
513
|
} else if (gf.skillInstall?.action === "failed") {
|
|
457
|
-
|
|
514
|
+
detail(` Graphify skill registration failed (${gf.skillInstall.reason}).`);
|
|
458
515
|
}
|
|
459
516
|
} else if (gf.binary?.hint) {
|
|
460
|
-
|
|
517
|
+
detail(` ${gf.binary.hint}`);
|
|
461
518
|
}
|
|
462
519
|
// Graphify HTTP knowledge-graph MCP (user-scope, config-driven endpoint).
|
|
463
520
|
const gh = await configureGraphifyHttp({ runtime });
|
|
464
521
|
if (gh.action === "registered" || gh.action === "re-registered") {
|
|
465
|
-
|
|
522
|
+
detail(` Graphify knowledge-graph MCP ${gh.action} (user scope).`);
|
|
466
523
|
} else if (gh.action === "failed") {
|
|
467
|
-
|
|
524
|
+
detail(` Graphify knowledge-graph MCP not registered (${gh.reason}).`);
|
|
468
525
|
}
|
|
469
526
|
} catch (err) {
|
|
470
|
-
|
|
527
|
+
detail(` Warning: could not set up Graphify (${err.message})`);
|
|
471
528
|
}
|
|
472
529
|
|
|
473
530
|
const manifest = {
|
|
@@ -505,16 +562,41 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
505
562
|
|
|
506
563
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
507
564
|
|
|
508
|
-
|
|
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(`
|
|
509
592
|
╔══════════════════════════════════════════════════════════╗
|
|
510
593
|
║ ArkaOS v${VERSION} installed successfully! (${elapsed}s) ║
|
|
511
594
|
╚══════════════════════════════════════════════════════════╝
|
|
512
595
|
|
|
513
596
|
Runtime: ${config.name}
|
|
514
597
|
Install dir: ${installDir}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
Knowledge: Vector DB with semantic search
|
|
598
|
+
Profile: ${profile.installProfile}
|
|
599
|
+
${plainStatLines ? plainStatLines + "\n" : ""} Knowledge: Vector DB with semantic search
|
|
518
600
|
Dashboard: Run 'npx arkaos dashboard' to start
|
|
519
601
|
|
|
520
602
|
Quick start:
|
|
@@ -530,22 +612,37 @@ export async function install({ runtime, path, force, skipSystem, withOllama })
|
|
|
530
612
|
npx arkaos keys — Configure API keys
|
|
531
613
|
npx arkaos doctor — Run health checks
|
|
532
614
|
`);
|
|
615
|
+
}
|
|
533
616
|
}
|
|
534
617
|
|
|
535
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.
|
|
536
622
|
|
|
537
623
|
function step(n, total, msg) {
|
|
624
|
+
if (ui) return ui.step(n, total, msg);
|
|
538
625
|
console.log(` [${n}/${total}] ${msg}`);
|
|
539
626
|
}
|
|
540
627
|
|
|
541
628
|
function ok(msg) {
|
|
629
|
+
if (ui) return ui.ok(msg);
|
|
542
630
|
console.log(` ✓ ${msg}`);
|
|
543
631
|
}
|
|
544
632
|
|
|
545
633
|
function warn(msg) {
|
|
634
|
+
if (ui) return ui.warn(msg);
|
|
546
635
|
console.log(` ⚠ ${msg}`);
|
|
547
636
|
}
|
|
548
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
|
+
|
|
549
646
|
function ensureDir(dir) {
|
|
550
647
|
if (!existsSync(dir)) {
|
|
551
648
|
mkdirSync(dir, { recursive: true });
|
|
@@ -553,7 +650,7 @@ function ensureDir(dir) {
|
|
|
553
650
|
}
|
|
554
651
|
|
|
555
652
|
function installAllPythonDeps(userConfig = {}) {
|
|
556
|
-
const log = (msg) =>
|
|
653
|
+
const log = (msg) => detail(msg);
|
|
557
654
|
|
|
558
655
|
// Core dependencies
|
|
559
656
|
const coreDeps = "pyyaml pydantic rich click jinja2";
|
|
@@ -571,7 +668,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
571
668
|
const transcriptionDeps = "faster-whisper";
|
|
572
669
|
|
|
573
670
|
// Core deps (required)
|
|
574
|
-
|
|
671
|
+
detail(" Installing core dependencies...");
|
|
575
672
|
if (pipInstall(coreDeps, { log })) {
|
|
576
673
|
ok("Core deps installed (pyyaml, pydantic, rich, click, jinja2)");
|
|
577
674
|
} else {
|
|
@@ -583,7 +680,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
583
680
|
// is reported accurately and the user knows which capability they
|
|
584
681
|
// actually have.
|
|
585
682
|
if (userConfig.installKnowledge !== false) {
|
|
586
|
-
|
|
683
|
+
detail(" Installing knowledge base dependencies...");
|
|
587
684
|
const fastembedOk = pipInstall("fastembed", { log, timeout: 180000 });
|
|
588
685
|
const sqliteVssOk = pipInstall("sqlite-vec", { log, timeout: 180000 });
|
|
589
686
|
if (fastembedOk && sqliteVssOk) {
|
|
@@ -598,7 +695,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
598
695
|
}
|
|
599
696
|
|
|
600
697
|
// Ingest deps
|
|
601
|
-
|
|
698
|
+
detail(" Installing content ingest dependencies...");
|
|
602
699
|
if (pipInstall(ingestDeps, { log })) {
|
|
603
700
|
ok("Ingest deps installed (yt-dlp, pdfplumber, beautifulsoup4)");
|
|
604
701
|
} else {
|
|
@@ -607,7 +704,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
607
704
|
|
|
608
705
|
// Dashboard deps (optional)
|
|
609
706
|
if (userConfig.installDashboard !== false) {
|
|
610
|
-
|
|
707
|
+
detail(" Installing dashboard dependencies...");
|
|
611
708
|
if (pipInstall(dashboardDeps, { log, timeout: 120000 })) {
|
|
612
709
|
ok("Dashboard API installed (fastapi, uvicorn, python-multipart)");
|
|
613
710
|
} else {
|
|
@@ -616,7 +713,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
616
713
|
}
|
|
617
714
|
|
|
618
715
|
// Transcription (optional, heavy)
|
|
619
|
-
|
|
716
|
+
detail(" Installing transcription engine...");
|
|
620
717
|
if (pipInstall(transcriptionDeps, { log, timeout: 300000 })) {
|
|
621
718
|
ok("Whisper transcription installed");
|
|
622
719
|
} else {
|
|
@@ -624,7 +721,7 @@ function installAllPythonDeps(userConfig = {}) {
|
|
|
624
721
|
}
|
|
625
722
|
|
|
626
723
|
// Install ArkaOS core package as editable
|
|
627
|
-
|
|
724
|
+
detail(" Installing ArkaOS core engine...");
|
|
628
725
|
if (pipInstall("", { editable: ARKAOS_ROOT, log, timeout: 60000 })) {
|
|
629
726
|
ok("ArkaOS core engine installed");
|
|
630
727
|
} else {
|
|
@@ -1045,13 +1142,13 @@ function printSchtasksAccessDeniedHelp(pythonPath, daemonPath) {
|
|
|
1045
1142
|
// nice-to-have that keeps background tasks ticking. We print the
|
|
1046
1143
|
// manual registration command so power users can elevate once and
|
|
1047
1144
|
// run it, and move on.
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
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.");
|
|
1055
1152
|
}
|
|
1056
1153
|
|
|
1057
1154
|
function installSchtasksService(daemonPath) {
|
|
@@ -1108,7 +1205,7 @@ function installSchtasksService(daemonPath) {
|
|
|
1108
1205
|
if (kind === "access-denied") {
|
|
1109
1206
|
printSchtasksAccessDeniedHelp(pythonPath, daemonPath);
|
|
1110
1207
|
} else {
|
|
1111
|
-
|
|
1208
|
+
detail(" Try manually: schtasks /Create /F /TN \"ArkaOS-Scheduler\" /SC ONLOGON /TR \"" + pythonPath + " " + daemonPath + "\"");
|
|
1112
1209
|
}
|
|
1113
1210
|
return;
|
|
1114
1211
|
}
|
|
@@ -1118,9 +1215,9 @@ function installSchtasksService(daemonPath) {
|
|
|
1118
1215
|
const kind = classifySchtasksError(runResult.stderr);
|
|
1119
1216
|
warn(`Scheduler: task created but /Run failed (${kind}): ${runResult.stderr.slice(0, 220)}`);
|
|
1120
1217
|
if (kind === "access-denied") {
|
|
1121
|
-
|
|
1218
|
+
detail(" Task is registered but couldn't be started now. It will run automatically at next logon.");
|
|
1122
1219
|
} else {
|
|
1123
|
-
|
|
1220
|
+
detail(" Task will start at next logon");
|
|
1124
1221
|
}
|
|
1125
1222
|
return;
|
|
1126
1223
|
}
|
|
@@ -1135,7 +1232,7 @@ export async function loadAdapter(runtime) {
|
|
|
1135
1232
|
} catch {
|
|
1136
1233
|
return {
|
|
1137
1234
|
configureHooks(config, installDir) {
|
|
1138
|
-
|
|
1235
|
+
detail(` Using generic configuration for ${runtime}`);
|
|
1139
1236
|
},
|
|
1140
1237
|
};
|
|
1141
1238
|
}
|