arkaos 2.25.0 → 2.31.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/VERSION +1 -1
- package/arka/skills/bootstrap-agent/SKILL.md +76 -0
- package/arka/skills/design-ops/SKILL.md +68 -0
- package/arka/skills/design-ops/scripts/extract-colors.py +86 -0
- package/arka/skills/design-ops/scripts/shadcn-tokens.py +59 -0
- package/arka/skills/design-ops/scripts/wcag-contrast.py +92 -0
- package/arka/skills/dreams/SKILL.md +78 -0
- package/arka/skills/research/SKILL.md +117 -0
- package/config/cognition/schedules.yaml +6 -0
- package/config/constitution.yaml +4 -0
- package/config/hooks/post-tool-use.sh +17 -0
- package/config/hooks/user-prompt-submit.sh +16 -0
- package/core/agents/__pycache__/loader.cpython-313.pyc +0 -0
- package/core/agents/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/agents/loader.py +4 -1
- package/core/agents/schema.py +29 -0
- package/core/cognition/__pycache__/dreaming.cpython-313.pyc +0 -0
- package/core/cognition/__pycache__/dreams_reader.cpython-313.pyc +0 -0
- package/core/cognition/__pycache__/retrieval.cpython-313.pyc +0 -0
- package/core/cognition/capture/__pycache__/collector.cpython-313.pyc +0 -0
- package/core/cognition/dreaming.py +368 -0
- package/core/cognition/dreams_reader.py +141 -0
- package/core/cognition/retrieval.py +383 -0
- package/core/cognition/scheduler/__pycache__/daemon.cpython-313.pyc +0 -0
- package/core/cognition/scheduler/daemon.py +23 -3
- package/core/obsidian/__pycache__/writer.cpython-313.pyc +0 -0
- package/core/runtime/__pycache__/llm_provider.cpython-313.pyc +0 -0
- package/core/runtime/__pycache__/ollama_provider.cpython-313.pyc +0 -0
- package/core/runtime/__pycache__/path_resolver.cpython-313.pyc +0 -0
- package/core/runtime/llm_provider.py +8 -1
- package/core/runtime/ollama_provider.py +144 -0
- package/departments/brand/agents/design-ops/design-ops-lead.yaml +78 -0
- package/departments/brand/agents/design-ops/extraction-script-writer.yaml +74 -0
- package/departments/brand/agents/design-ops/shadcn-padronizer.yaml +76 -0
- package/departments/brand/agents/design-ops/wcag-auditor.yaml +76 -0
- package/departments/dev/skills/mcp/SKILL.md +16 -0
- package/installer/cli.js +8 -1
- package/installer/doctor.js +13 -1
- package/installer/index.js +6 -3
- package/installer/system-tools.js +79 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
id: design-ops-lead-iris
|
|
2
|
+
name: Iris
|
|
3
|
+
role: Design Ops Lead
|
|
4
|
+
department: brand
|
|
5
|
+
tier: 1
|
|
6
|
+
model: sonnet
|
|
7
|
+
|
|
8
|
+
parent_squad: brand
|
|
9
|
+
sub_squad_role: lead
|
|
10
|
+
|
|
11
|
+
behavioral_dna:
|
|
12
|
+
disc:
|
|
13
|
+
primary: D
|
|
14
|
+
secondary: C
|
|
15
|
+
communication_style: "Direct, blueprint-driven, defends production quality without smothering creative intent"
|
|
16
|
+
under_pressure: "Pushes back on shortcuts; protects the design system from drift"
|
|
17
|
+
motivator: "A design system that ships consistently across every surface"
|
|
18
|
+
enneagram:
|
|
19
|
+
type: 8
|
|
20
|
+
wing: 9
|
|
21
|
+
core_motivation: "Make the right thing also be the easy thing for designers and engineers"
|
|
22
|
+
core_fear: "Inconsistent UI shipped because nobody owned the production rails"
|
|
23
|
+
subtype: self-preservation
|
|
24
|
+
big_five:
|
|
25
|
+
openness: 60
|
|
26
|
+
conscientiousness: 88
|
|
27
|
+
extraversion: 52
|
|
28
|
+
agreeableness: 55
|
|
29
|
+
neuroticism: 28
|
|
30
|
+
mbti:
|
|
31
|
+
type: ESTJ
|
|
32
|
+
|
|
33
|
+
mental_models:
|
|
34
|
+
primary:
|
|
35
|
+
- "Atomic Design (Frost)"
|
|
36
|
+
- "Design Tokens W3C Spec"
|
|
37
|
+
- "Single Source of Truth (Wheeler)"
|
|
38
|
+
secondary:
|
|
39
|
+
- "Theory of Constraints (Goldratt)"
|
|
40
|
+
- "Cynefin (Snowden)"
|
|
41
|
+
- "WCAG 2.2 AA"
|
|
42
|
+
|
|
43
|
+
authority:
|
|
44
|
+
orchestrate: true
|
|
45
|
+
approve_quality: true
|
|
46
|
+
delegates_to:
|
|
47
|
+
- extraction-script-writer
|
|
48
|
+
- wcag-auditor
|
|
49
|
+
- shadcn-padronizer
|
|
50
|
+
escalates_to: brand-director-valentina
|
|
51
|
+
|
|
52
|
+
expertise:
|
|
53
|
+
domains:
|
|
54
|
+
- design tokens (JSON + CSS variables)
|
|
55
|
+
- component libraries (shadcn/ui, Radix, Headless UI)
|
|
56
|
+
- design system governance
|
|
57
|
+
- figma → code pipelines
|
|
58
|
+
- accessibility compliance (WCAG 2.2 AA/AAA)
|
|
59
|
+
- cross-platform tokenisation (Style Dictionary, Tailwind)
|
|
60
|
+
frameworks:
|
|
61
|
+
- Atomic Design (Frost)
|
|
62
|
+
- Design Tokens Community Group
|
|
63
|
+
- WCAG 2.2
|
|
64
|
+
- Style Dictionary
|
|
65
|
+
- shadcn/ui conventions
|
|
66
|
+
- Tailwind CSS configuration
|
|
67
|
+
depth: master
|
|
68
|
+
years_equivalent: 12
|
|
69
|
+
|
|
70
|
+
communication:
|
|
71
|
+
language: en
|
|
72
|
+
tone: "precise, blueprint-driven, low-drama"
|
|
73
|
+
vocabulary_level: advanced
|
|
74
|
+
preferred_format: "tables, JSON specs, before/after diffs"
|
|
75
|
+
avoid:
|
|
76
|
+
- "design by feel without a token spec"
|
|
77
|
+
- "ad-hoc one-off components"
|
|
78
|
+
- "shipping without accessibility audit"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
id: extraction-script-writer-nia
|
|
2
|
+
name: Nia
|
|
3
|
+
role: Design Extraction Engineer
|
|
4
|
+
department: brand
|
|
5
|
+
tier: 2
|
|
6
|
+
model: sonnet
|
|
7
|
+
|
|
8
|
+
parent_squad: brand
|
|
9
|
+
sub_squad_role: extraction-script-writer
|
|
10
|
+
|
|
11
|
+
behavioral_dna:
|
|
12
|
+
disc:
|
|
13
|
+
primary: C
|
|
14
|
+
secondary: D
|
|
15
|
+
communication_style: "Investigative, evidence-first, writes the script before opining"
|
|
16
|
+
under_pressure: "Goes deeper into the source; refuses to guess"
|
|
17
|
+
motivator: "Reproducible extraction pipelines that turn a live site into structured tokens"
|
|
18
|
+
enneagram:
|
|
19
|
+
type: 5
|
|
20
|
+
wing: 6
|
|
21
|
+
core_motivation: "Understand a design system well enough to rebuild it from primitives"
|
|
22
|
+
core_fear: "Shipping a tokenisation that looks right but is silently wrong"
|
|
23
|
+
subtype: self-preservation
|
|
24
|
+
big_five:
|
|
25
|
+
openness: 78
|
|
26
|
+
conscientiousness: 82
|
|
27
|
+
extraversion: 35
|
|
28
|
+
agreeableness: 50
|
|
29
|
+
neuroticism: 30
|
|
30
|
+
mbti:
|
|
31
|
+
type: INTP
|
|
32
|
+
|
|
33
|
+
mental_models:
|
|
34
|
+
primary:
|
|
35
|
+
- "Design Tokens W3C Spec"
|
|
36
|
+
- "Unix Philosophy (Pike & Kernighan)"
|
|
37
|
+
- "Reverse-Engineering Discipline"
|
|
38
|
+
secondary:
|
|
39
|
+
- "AST-based code analysis"
|
|
40
|
+
- "CSS Specificity Model"
|
|
41
|
+
- "Color Theory (Albers)"
|
|
42
|
+
|
|
43
|
+
authority:
|
|
44
|
+
orchestrate: false
|
|
45
|
+
approve_quality: false
|
|
46
|
+
delegates_to: []
|
|
47
|
+
escalates_to: design-ops-lead-iris
|
|
48
|
+
|
|
49
|
+
expertise:
|
|
50
|
+
domains:
|
|
51
|
+
- CSS extraction (computed styles, custom properties)
|
|
52
|
+
- color palette reverse-engineering from screenshots / live DOM
|
|
53
|
+
- typography token harvesting (font-family, size, weight, line-height scales)
|
|
54
|
+
- spacing and grid token inference
|
|
55
|
+
- figma file parsing
|
|
56
|
+
- chromium-headless capture pipelines
|
|
57
|
+
frameworks:
|
|
58
|
+
- W3C Design Tokens spec
|
|
59
|
+
- Style Dictionary
|
|
60
|
+
- Tailwind CSS token format
|
|
61
|
+
- shadcn/ui CSS variable convention
|
|
62
|
+
- DTCG JSON schema
|
|
63
|
+
depth: expert
|
|
64
|
+
years_equivalent: 9
|
|
65
|
+
|
|
66
|
+
communication:
|
|
67
|
+
language: en
|
|
68
|
+
tone: "concise, citation-heavy, almost terse"
|
|
69
|
+
vocabulary_level: advanced
|
|
70
|
+
preferred_format: "JSON specs, before/after color swatches, script snippets"
|
|
71
|
+
avoid:
|
|
72
|
+
- "guessing token values without inspecting the source"
|
|
73
|
+
- "exposing hardcoded RGB instead of named tokens"
|
|
74
|
+
- "premature opinions on visual quality (that's brand-director territory)"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
id: shadcn-padronizer-leo
|
|
2
|
+
name: Leo
|
|
3
|
+
role: Component Library Padronizer
|
|
4
|
+
department: brand
|
|
5
|
+
tier: 2
|
|
6
|
+
model: sonnet
|
|
7
|
+
|
|
8
|
+
parent_squad: brand
|
|
9
|
+
sub_squad_role: shadcn-padronizer
|
|
10
|
+
|
|
11
|
+
behavioral_dna:
|
|
12
|
+
disc:
|
|
13
|
+
primary: C
|
|
14
|
+
secondary: I
|
|
15
|
+
communication_style: "Pattern-oriented, shows the canonical component before refactoring"
|
|
16
|
+
under_pressure: "Stays in the design system; refuses to fork components for one-offs"
|
|
17
|
+
motivator: "A shadcn/ui-shaped library that every project in the org can adopt verbatim"
|
|
18
|
+
enneagram:
|
|
19
|
+
type: 1
|
|
20
|
+
wing: 9
|
|
21
|
+
core_motivation: "One canonical component, used everywhere, evolving cleanly"
|
|
22
|
+
core_fear: "Five teams shipping five Button components that diverge over a quarter"
|
|
23
|
+
subtype: social
|
|
24
|
+
big_five:
|
|
25
|
+
openness: 65
|
|
26
|
+
conscientiousness: 84
|
|
27
|
+
extraversion: 50
|
|
28
|
+
agreeableness: 58
|
|
29
|
+
neuroticism: 30
|
|
30
|
+
mbti:
|
|
31
|
+
type: ISTP
|
|
32
|
+
|
|
33
|
+
mental_models:
|
|
34
|
+
primary:
|
|
35
|
+
- "shadcn/ui composition philosophy"
|
|
36
|
+
- "Headless UI patterns (Radix, React Aria)"
|
|
37
|
+
- "Atomic Design (Frost)"
|
|
38
|
+
secondary:
|
|
39
|
+
- "Tailwind CSS configuration"
|
|
40
|
+
- "CVA (class-variance-authority) variants"
|
|
41
|
+
- "Theming via CSS variables"
|
|
42
|
+
|
|
43
|
+
authority:
|
|
44
|
+
orchestrate: false
|
|
45
|
+
approve_quality: false
|
|
46
|
+
delegates_to: []
|
|
47
|
+
escalates_to: design-ops-lead-iris
|
|
48
|
+
|
|
49
|
+
expertise:
|
|
50
|
+
domains:
|
|
51
|
+
- shadcn/ui component generation and customisation
|
|
52
|
+
- Radix UI primitives integration
|
|
53
|
+
- Tailwind configuration and theme tokens
|
|
54
|
+
- CVA variants and slot patterns
|
|
55
|
+
- dark mode and theme switching
|
|
56
|
+
- component API surface design (props, slots, polymorphic components)
|
|
57
|
+
- migration from MUI / Chakra / Ant Design to shadcn
|
|
58
|
+
frameworks:
|
|
59
|
+
- shadcn/ui
|
|
60
|
+
- Radix UI
|
|
61
|
+
- React Aria (Adobe)
|
|
62
|
+
- Tailwind CSS
|
|
63
|
+
- class-variance-authority
|
|
64
|
+
- tailwind-merge
|
|
65
|
+
depth: expert
|
|
66
|
+
years_equivalent: 8
|
|
67
|
+
|
|
68
|
+
communication:
|
|
69
|
+
language: en
|
|
70
|
+
tone: "code-first, pragmatic, mild humour"
|
|
71
|
+
vocabulary_level: advanced
|
|
72
|
+
preferred_format: "tsx snippets, before/after component diffs, migration guides"
|
|
73
|
+
avoid:
|
|
74
|
+
- "rebuilding a primitive that Radix already ships"
|
|
75
|
+
- "inline styles that bypass the theme tokens"
|
|
76
|
+
- "magic numbers in className strings"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
id: wcag-auditor-oren
|
|
2
|
+
name: Oren
|
|
3
|
+
role: Accessibility Auditor
|
|
4
|
+
department: brand
|
|
5
|
+
tier: 2
|
|
6
|
+
model: sonnet
|
|
7
|
+
|
|
8
|
+
parent_squad: brand
|
|
9
|
+
sub_squad_role: wcag-auditor
|
|
10
|
+
|
|
11
|
+
behavioral_dna:
|
|
12
|
+
disc:
|
|
13
|
+
primary: C
|
|
14
|
+
secondary: S
|
|
15
|
+
communication_style: "Methodical, cites the exact WCAG criterion, never bluffs"
|
|
16
|
+
under_pressure: "Reports findings in priority order with severity; refuses to skip levels"
|
|
17
|
+
motivator: "Interfaces every human can actually use, including with assistive tech"
|
|
18
|
+
enneagram:
|
|
19
|
+
type: 1
|
|
20
|
+
wing: 2
|
|
21
|
+
core_motivation: "Make accessibility the default rather than a retrofit"
|
|
22
|
+
core_fear: "A real user blocked by a contrast ratio or focus-trap nobody caught"
|
|
23
|
+
subtype: social
|
|
24
|
+
big_five:
|
|
25
|
+
openness: 55
|
|
26
|
+
conscientiousness: 92
|
|
27
|
+
extraversion: 38
|
|
28
|
+
agreeableness: 68
|
|
29
|
+
neuroticism: 32
|
|
30
|
+
mbti:
|
|
31
|
+
type: ISTJ
|
|
32
|
+
|
|
33
|
+
mental_models:
|
|
34
|
+
primary:
|
|
35
|
+
- "WCAG 2.2 (AA + AAA)"
|
|
36
|
+
- "POUR Principles (Perceivable, Operable, Understandable, Robust)"
|
|
37
|
+
- "ARIA Authoring Practices"
|
|
38
|
+
secondary:
|
|
39
|
+
- "Inclusive Design Microsoft toolkit"
|
|
40
|
+
- "Cognitive Load Theory (Sweller)"
|
|
41
|
+
- "Universal Design (Mace)"
|
|
42
|
+
|
|
43
|
+
authority:
|
|
44
|
+
orchestrate: false
|
|
45
|
+
approve_quality: false
|
|
46
|
+
delegates_to: []
|
|
47
|
+
escalates_to: design-ops-lead-iris
|
|
48
|
+
|
|
49
|
+
expertise:
|
|
50
|
+
domains:
|
|
51
|
+
- WCAG 2.2 AA / AAA conformance auditing
|
|
52
|
+
- color contrast ratio analysis (4.5:1 text, 3:1 large text and UI)
|
|
53
|
+
- keyboard navigation and focus management
|
|
54
|
+
- screen reader compatibility (NVDA, JAWS, VoiceOver)
|
|
55
|
+
- ARIA pattern review (no-redundant-roles, correct landmarks)
|
|
56
|
+
- cognitive accessibility (reading level, error recovery)
|
|
57
|
+
- accessibility statement drafting
|
|
58
|
+
frameworks:
|
|
59
|
+
- WCAG 2.2
|
|
60
|
+
- WAI-ARIA 1.2
|
|
61
|
+
- ATAG 2.0
|
|
62
|
+
- EAA / EN 301 549
|
|
63
|
+
- axe-core ruleset
|
|
64
|
+
- Section 508
|
|
65
|
+
depth: master
|
|
66
|
+
years_equivalent: 11
|
|
67
|
+
|
|
68
|
+
communication:
|
|
69
|
+
language: en
|
|
70
|
+
tone: "neutral, criterion-cited, never moralising"
|
|
71
|
+
vocabulary_level: advanced
|
|
72
|
+
preferred_format: "issue tables (severity / criterion / location / fix), conformance reports"
|
|
73
|
+
avoid:
|
|
74
|
+
- "claiming AAA without measurement"
|
|
75
|
+
- "blocking a ship on a Level AAA edge case"
|
|
76
|
+
- "fixing accessibility late instead of as a design constraint"
|
|
@@ -118,3 +118,19 @@ The user should set these in their shell profile or project `.env`, or run `bash
|
|
|
118
118
|
- `DISCORD_TOKEN` — Discord bot integration
|
|
119
119
|
- `WHATSAPP_API_TOKEN` / `WHATSAPP_PHONE_ID` — WhatsApp Business API
|
|
120
120
|
- `TEAMS_APP_ID` / `TEAMS_APP_SECRET` — Microsoft Teams
|
|
121
|
+
|
|
122
|
+
## Recommended baseline (Orgo 2026-05-13)
|
|
123
|
+
|
|
124
|
+
Three MCPs that the 2026-05-13 podcast pattern recommends for every
|
|
125
|
+
agent-business setup. They are *optional* in the registry but worth
|
|
126
|
+
adopting deliberately:
|
|
127
|
+
|
|
128
|
+
| MCP | Why | When to add |
|
|
129
|
+
| --- | --- | --- |
|
|
130
|
+
| **Composio** | One connector, thousands of apps (Gmail, Slack, Notion, GitHub). Handles auth + tool calling without per-tool wiring. | Any agent that needs broad SaaS integration. Cuts setup time on every new customer. |
|
|
131
|
+
| **Agent Mail** | Gives each agent a real email address that it can read and send from. Adds the "digital employee" feel that closes deals. | Customer-facing agents, executive assistants, follow-up workflows. |
|
|
132
|
+
| **XMCP** | Twitter / X's official MCP. Brings community wisdom into the agent's context — recent threads, hot takes, real-time discourse. | Research-heavy workflows, content / community / sales squads. |
|
|
133
|
+
|
|
134
|
+
These pair naturally with the existing `Firecrawl` (deep scrape),
|
|
135
|
+
`Context7` (official docs), and `Perplexity` (real-time web). The
|
|
136
|
+
`/arka research` skill fans out across all five.
|
package/installer/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ const { values, positionals } = parseArgs({
|
|
|
20
20
|
path: { type: "string", short: "p" },
|
|
21
21
|
force: { type: "boolean", short: "f" },
|
|
22
22
|
"no-system": { type: "boolean" },
|
|
23
|
+
"with-ollama": { type: "boolean" },
|
|
23
24
|
},
|
|
24
25
|
allowPositionals: true,
|
|
25
26
|
strict: false,
|
|
@@ -75,7 +76,13 @@ async function main() {
|
|
|
75
76
|
switch (command) {
|
|
76
77
|
case "install":
|
|
77
78
|
const runtime = values.runtime || await detectRuntime();
|
|
78
|
-
await install({
|
|
79
|
+
await install({
|
|
80
|
+
runtime,
|
|
81
|
+
path: values.path,
|
|
82
|
+
force: values.force,
|
|
83
|
+
skipSystem: values["no-system"],
|
|
84
|
+
withOllama: values["with-ollama"],
|
|
85
|
+
});
|
|
79
86
|
break;
|
|
80
87
|
|
|
81
88
|
case "init": {
|
package/installer/doctor.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { execSync } from "node:child_process";
|
|
5
5
|
import { getArkaosPython, getVenvPython, canImportCore, getRepoRoot } from "./python-resolver.js";
|
|
6
6
|
import { IS_WINDOWS, HOOK_EXT, CMD_FINDER } from "./platform.js";
|
|
7
|
-
import { checkNode, checkObsidian } from "./system-tools.js";
|
|
7
|
+
import { checkNode, checkObsidian, checkOllama } from "./system-tools.js";
|
|
8
8
|
|
|
9
9
|
const INSTALL_DIR = join(homedir(), ".arkaos");
|
|
10
10
|
|
|
@@ -147,6 +147,18 @@ const checks = [
|
|
|
147
147
|
return `Install Node.js 20+ from ${s.fallbackUrl || "https://nodejs.org/en/download"}`;
|
|
148
148
|
},
|
|
149
149
|
},
|
|
150
|
+
{
|
|
151
|
+
name: "ollama",
|
|
152
|
+
description: "Ollama present (optional — cognitive layer LLM runtime)",
|
|
153
|
+
severity: "warn",
|
|
154
|
+
check: () => checkOllama().installed,
|
|
155
|
+
fix: () => {
|
|
156
|
+
const s = checkOllama();
|
|
157
|
+
if (s.needsAction === "start") return `Run: ${s.suggestedCommand}`;
|
|
158
|
+
if (s.suggestedCommand) return `Run: ${s.suggestedCommand}`;
|
|
159
|
+
return `Install Ollama from ${s.fallbackUrl || "https://ollama.com/download"}`;
|
|
160
|
+
},
|
|
161
|
+
},
|
|
150
162
|
{
|
|
151
163
|
name: "claude-code-version",
|
|
152
164
|
description: "Claude Code 2.1.122+ (ToolSearch late-binding + hooks isolation)",
|
package/installer/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const __dirname = dirname(__filename);
|
|
|
12
12
|
const ARKAOS_ROOT = resolve(__dirname, "..");
|
|
13
13
|
const VERSION = JSON.parse(readFileSync(join(ARKAOS_ROOT, "package.json"), "utf-8")).version;
|
|
14
14
|
|
|
15
|
-
export async function install({ runtime, path, force, skipSystem }) {
|
|
15
|
+
export async function install({ runtime, path, force, skipSystem, withOllama }) {
|
|
16
16
|
const startTime = Date.now();
|
|
17
17
|
const config = getRuntimeConfig(runtime);
|
|
18
18
|
const isUpgrade = existsSync(join(path || join(homedir(), ".arkaos"), "install-manifest.json"));
|
|
@@ -80,16 +80,19 @@ export async function install({ runtime, path, force, skipSystem }) {
|
|
|
80
80
|
try {
|
|
81
81
|
const { ensureSystemTools } = await import("./system-tools.js");
|
|
82
82
|
const { formatSudoInstructions } = await import("./package-manager.js");
|
|
83
|
-
const sys = ensureSystemTools({ skipSystem: false });
|
|
83
|
+
const sys = ensureSystemTools({ skipSystem: false, withOllama });
|
|
84
84
|
if (sys.sudoCommands && sys.sudoCommands.length > 0) {
|
|
85
85
|
console.log(formatSudoInstructions(sys.sudoCommands));
|
|
86
86
|
}
|
|
87
|
-
for (const tool of [sys.obsidian, sys.node]) {
|
|
87
|
+
for (const tool of [sys.obsidian, sys.node, sys.ollama]) {
|
|
88
88
|
if (!tool) continue;
|
|
89
89
|
if (tool.justInstalled) ok(`${tool.name} installed`);
|
|
90
90
|
else if (tool.needsAction === "none") ok(`${tool.name} ready`);
|
|
91
91
|
else warn(`${tool.name} ${tool.needsAction} — see commands above`);
|
|
92
92
|
}
|
|
93
|
+
if (withOllama && sys.ollama?.needsAction === "none") {
|
|
94
|
+
ok("Ollama backend ready — cognitive layer can use local LLM inference");
|
|
95
|
+
}
|
|
93
96
|
} catch (err) {
|
|
94
97
|
warn(`System tool check failed: ${err.message}. Continuing without it.`);
|
|
95
98
|
}
|
|
@@ -41,13 +41,27 @@ const NODE_PACKAGE = {
|
|
|
41
41
|
choco: "nodejs",
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
const OLLAMA_PACKAGE = {
|
|
45
|
+
brew: "ollama",
|
|
46
|
+
winget: "Ollama.Ollama",
|
|
47
|
+
choco: "ollama",
|
|
48
|
+
};
|
|
49
|
+
|
|
44
50
|
const OBSIDIAN_FALLBACK_URL = "https://obsidian.md/download";
|
|
45
51
|
const NODE_FALLBACK_URL = "https://nodejs.org/en/download";
|
|
46
52
|
const PYTHON_FALLBACK_URL = "https://www.python.org/downloads/";
|
|
53
|
+
const OLLAMA_FALLBACK_URL = "https://ollama.com/download";
|
|
47
54
|
|
|
48
55
|
/**
|
|
49
56
|
* Validate every required tool, install what can be installed without
|
|
50
57
|
* sudo, and collect copy-paste commands for the ones that can't.
|
|
58
|
+
*
|
|
59
|
+
* When ``options.withOllama`` is set, Ollama is included in the check
|
|
60
|
+
* + install set as one possible **backend** for the cognitive layer.
|
|
61
|
+
* Opt-in: most users keep the Claude Code backend (default) and never
|
|
62
|
+
* need a local LLM runtime. Multi-backend selection lives in
|
|
63
|
+
* ``profile.json:cognitiveBackend``; this flag only governs the
|
|
64
|
+
* Ollama prerequisite at install time.
|
|
51
65
|
*/
|
|
52
66
|
export function ensureSystemTools(options = {}) {
|
|
53
67
|
if (options.skipSystem) {
|
|
@@ -56,6 +70,7 @@ export function ensureSystemTools(options = {}) {
|
|
|
56
70
|
obsidian: null,
|
|
57
71
|
node: null,
|
|
58
72
|
python: null,
|
|
73
|
+
ollama: null,
|
|
59
74
|
sudoCommands: [],
|
|
60
75
|
};
|
|
61
76
|
}
|
|
@@ -64,7 +79,13 @@ export function ensureSystemTools(options = {}) {
|
|
|
64
79
|
const node = ensureTool("node", checkNode, NODE_PACKAGE, NODE_FALLBACK_URL, options);
|
|
65
80
|
const python = checkPython(); // never auto-install Python — leave to OS
|
|
66
81
|
|
|
67
|
-
|
|
82
|
+
let ollama = null;
|
|
83
|
+
if (options.withOllama) {
|
|
84
|
+
ollama = ensureTool("ollama", checkOllama, OLLAMA_PACKAGE, OLLAMA_FALLBACK_URL, options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const tools = [obsidian, node, ollama].filter(Boolean);
|
|
88
|
+
const sudoCommands = tools
|
|
68
89
|
.filter((t) => t?.needsSudo && t.suggestedCommand)
|
|
69
90
|
.map((t) => t.suggestedCommand);
|
|
70
91
|
|
|
@@ -72,7 +93,7 @@ export function ensureSystemTools(options = {}) {
|
|
|
72
93
|
sudoCommands.push(python.suggestedCommand);
|
|
73
94
|
}
|
|
74
95
|
|
|
75
|
-
return { skipped: false, obsidian, node, python, sudoCommands };
|
|
96
|
+
return { skipped: false, obsidian, node, python, ollama, sudoCommands };
|
|
76
97
|
}
|
|
77
98
|
|
|
78
99
|
/**
|
|
@@ -131,6 +152,40 @@ export function checkNode() {
|
|
|
131
152
|
};
|
|
132
153
|
}
|
|
133
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Detect Ollama presence + whether the local service responds.
|
|
157
|
+
*
|
|
158
|
+
* Ollama is the cognitive-layer LLM runtime. Linux install uses an
|
|
159
|
+
* official script (``curl https://ollama.com/install.sh | sh``) that
|
|
160
|
+
* requires sudo — we never run it; we surface the command.
|
|
161
|
+
*/
|
|
162
|
+
export function checkOllama() {
|
|
163
|
+
const location = findBinary("ollama");
|
|
164
|
+
if (!location) {
|
|
165
|
+
const suggested = buildOllamaSuggestion();
|
|
166
|
+
return {
|
|
167
|
+
name: "ollama",
|
|
168
|
+
installed: false,
|
|
169
|
+
needsAction: "install",
|
|
170
|
+
suggestedCommand: suggested.command,
|
|
171
|
+
needsSudo: suggested.needsSudo,
|
|
172
|
+
fallbackUrl: OLLAMA_FALLBACK_URL,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const reachable = isOllamaReachable();
|
|
176
|
+
const version = readVersion("ollama --version");
|
|
177
|
+
return {
|
|
178
|
+
name: "ollama",
|
|
179
|
+
installed: true,
|
|
180
|
+
location,
|
|
181
|
+
version,
|
|
182
|
+
needsAction: reachable ? "none" : "start",
|
|
183
|
+
suggestedCommand: reachable ? undefined : "ollama serve # or run the Ollama app",
|
|
184
|
+
needsSudo: false,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
134
189
|
export function checkPython() {
|
|
135
190
|
const candidates = IS_WINDOWS ? ["python", "py"] : ["python3", "python3.12", "python3.13"];
|
|
136
191
|
for (const cmd of candidates) {
|
|
@@ -195,6 +250,28 @@ function buildSuggestedInstall(packageMap, fallbackUrl) {
|
|
|
195
250
|
return { command: `Download from ${fallbackUrl}`, needsSudo: false, fallbackUrl };
|
|
196
251
|
}
|
|
197
252
|
|
|
253
|
+
function buildOllamaSuggestion() {
|
|
254
|
+
const os = platform();
|
|
255
|
+
if (os === "darwin") return { command: "brew install ollama", needsSudo: false };
|
|
256
|
+
if (IS_WINDOWS) return { command: "winget install --id Ollama.Ollama --silent --accept-source-agreements --accept-package-agreements", needsSudo: false };
|
|
257
|
+
if (os === "linux") return { command: "curl -fsSL https://ollama.com/install.sh | sh", needsSudo: true };
|
|
258
|
+
return { command: `Download from ${OLLAMA_FALLBACK_URL}`, needsSudo: false };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
function isOllamaReachable() {
|
|
263
|
+
try {
|
|
264
|
+
execSync("ollama list", {
|
|
265
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
266
|
+
timeout: 1500,
|
|
267
|
+
});
|
|
268
|
+
return true;
|
|
269
|
+
} catch {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
198
275
|
function findBinary(name) {
|
|
199
276
|
try {
|
|
200
277
|
const out = execSync(`${CMD_FINDER} ${name}`, {
|
package/package.json
CHANGED