@robbiesrobotics/alice-agents 1.2.8 → 1.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robbies Robotics (av3.ai)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -51,16 +51,23 @@ An orchestrator (Olivia) backed by specialist agents across every domain:
51
51
  | **Eva** | Executive Assistant | 📌 | Pro |
52
52
  | **Parker** | Project Management | 📅 | Pro |
53
53
 
54
- ## Model Presets
54
+ ## Model Flexibility
55
+
56
+ A.L.I.C.E. works with **whatever model you already have configured** in OpenClaw/NemoClaw. There's no required API key — just use what you've got.
57
+
58
+ When you install, the installer will **auto-detect your configured model** and use it by default. You can also choose from presets or specify a custom model.
55
59
 
56
60
  | Preset | Models | Best For |
57
61
  |--------|--------|----------|
58
- | **Sonnet** (default) | claude-sonnet-4-6 for all | Balanced speed + quality |
59
- | **Opus + Sonnet** | Opus for orchestrator, Sonnet for specialists | Maximum orchestration quality |
62
+ | **Auto-detect** (default) | Your current OpenClaw model | Zero friction works with what you have |
63
+ | **Sonnet** | claude-sonnet-4-6 for all | Balanced speed + quality (requires Anthropic key) |
64
+ | **Opus + Sonnet** | Opus for orchestrator, Sonnet for specialists | Maximum quality (requires Anthropic key) |
60
65
  | **OpenAI** | GPT-5.4 / GPT-5.4-mini | OpenAI users |
61
- | **Local (Ollama)** | Local models | Privacy, offline use |
66
+ | **Local (Ollama)** | Local models | Privacy, offline use, no API key needed |
62
67
  | **Custom** | Your choice | Full control |
63
68
 
69
+ > **Tip:** We prefer Claude Opus for orchestration when available — but A.L.I.C.E. is model-agnostic. Whatever model OpenClaw has configured will work.
70
+
64
71
  ## Install Options
65
72
 
66
73
  ```bash
@@ -132,7 +139,7 @@ If you're already running NemoClaw, A.L.I.C.E. works out of the box — no extra
132
139
 
133
140
  - [OpenClaw](https://openclaw.ai) or [NemoClaw](https://nemoclaw.com) installed and configured
134
141
  - Node.js 18+
135
- - At least one AI provider configured (Anthropic, OpenAI, or Ollama)
142
+ - At least one model configured in OpenClaw or NemoClaw — no specific API key required. A.L.I.C.E. uses whatever you already have set up.
136
143
 
137
144
  ## License
138
145
 
package/bin/.gitkeep ADDED
File without changes
@@ -1,10 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { readFileSync } from 'node:fs';
4
+ import { createRequire } from 'node:module';
3
5
  import { runInstall, runUninstall } from '../lib/installer.mjs';
6
+ import { runDoctor } from '../lib/doctor.mjs';
4
7
 
5
8
  const args = process.argv.slice(2);
6
9
  const flags = new Set(args);
7
10
 
11
+ if (flags.has('--version') || flags.has('-v')) {
12
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url)));
13
+ console.log(pkg.version);
14
+ process.exit(0);
15
+ }
16
+
8
17
  if (flags.has('--help') || flags.has('-h')) {
9
18
  console.log(`
10
19
  alice-agents — A.L.I.C.E. Agent Framework Installer
@@ -12,17 +21,33 @@ if (flags.has('--help') || flags.has('-h')) {
12
21
  Usage:
13
22
  npx @robbiesrobotics/alice-agents Interactive install
14
23
  npx @robbiesrobotics/alice-agents --yes Non-interactive install with defaults
24
+ npx @robbiesrobotics/alice-agents --update Non-interactive upgrade to latest agents
15
25
  npx @robbiesrobotics/alice-agents --uninstall Remove A.L.I.C.E. agents from config
26
+ npx @robbiesrobotics/alice-agents --doctor Run diagnostics on your A.L.I.C.E. install
27
+ npx @robbiesrobotics/alice-agents --version Show version
16
28
  npx @robbiesrobotics/alice-agents --help Show this help
17
29
 
18
30
  Options:
19
31
  --yes Skip prompts, use defaults (Sonnet, Starter tier)
32
+ --update Non-interactive upgrade (alias for --yes with upgrade mode)
20
33
  --uninstall Remove A.L.I.C.E. agents (preserves non-ALICE agents)
34
+ --doctor Run diagnostics and check install health
35
+ --version Print package version
21
36
  `);
22
37
  process.exit(0);
23
38
  }
24
39
 
25
- if (flags.has('--uninstall')) {
40
+ if (flags.has('--doctor')) {
41
+ runDoctor().then((ok) => process.exit(ok ? 0 : 1)).catch((err) => {
42
+ console.error(' ❌ Doctor failed:', err.message);
43
+ process.exit(1);
44
+ });
45
+ } else if (flags.has('--update')) {
46
+ runInstall({ yes: true, modeOverride: 'upgrade' }).catch((err) => {
47
+ console.error(' ❌ Update failed:', err.message);
48
+ process.exit(1);
49
+ });
50
+ } else if (flags.has('--uninstall')) {
26
51
  runUninstall({ yes: flags.has('--yes') }).catch((err) => {
27
52
  console.error(' ❌ Uninstall failed:', err.message);
28
53
  process.exit(1);
package/lib/.gitkeep ADDED
File without changes
@@ -15,6 +15,43 @@ export function readConfig() {
15
15
  return JSON.parse(raw);
16
16
  }
17
17
 
18
+ /**
19
+ * Inspect the existing OpenClaw/NemoClaw config and return what models
20
+ * and providers the user already has set up. This is used to avoid
21
+ * forcing Anthropic/Claude on users who haven't configured those keys.
22
+ *
23
+ * Returns null if config can't be read.
24
+ */
25
+ export function detectAvailableModels() {
26
+ if (!configExists()) return null;
27
+ try {
28
+ const config = readConfig();
29
+
30
+ // Current agents.defaults.model (set by a prior install or manually)
31
+ const agentDefaults = config?.agents?.defaults?.model || {};
32
+
33
+ // Top-level model override (some users set this)
34
+ const globalModel = config?.model;
35
+
36
+ // Configured provider keys (e.g. ['anthropic', 'openai', 'ollama'])
37
+ const providers = Object.keys(config?.models?.providers || {});
38
+
39
+ const primary = agentDefaults.primary || globalModel || null;
40
+ const orchestrator = agentDefaults.orchestrator || primary;
41
+ const fallbacks = agentDefaults.fallbacks || [];
42
+
43
+ return {
44
+ primary,
45
+ orchestrator,
46
+ fallbacks,
47
+ providers,
48
+ hasModel: !!primary,
49
+ };
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
18
55
  function backupConfig() {
19
56
  const ts = Date.now();
20
57
  const backupPath = join(OPENCLAW_DIR, `openclaw.json.bak.alice-${ts}`);
@@ -29,8 +66,17 @@ function writeConfigAtomic(config) {
29
66
  renameSync(tmpPath, CONFIG_PATH);
30
67
  }
31
68
 
32
- function getModelConfig(preset, customModels) {
69
+ function getModelConfig(preset, customModels, detectedModels) {
33
70
  switch (preset) {
71
+ case 'detected':
72
+ // Use whatever the user already has configured — don't touch model settings at all
73
+ return {
74
+ primary: detectedModels?.primary || null,
75
+ orchestrator: detectedModels?.orchestrator || detectedModels?.primary || null,
76
+ fallbacks: detectedModels?.fallbacks || [],
77
+ models: {},
78
+ preserve: true, // signal: don't overwrite model defaults
79
+ };
34
80
  case 'sonnet':
35
81
  return {
36
82
  primary: 'anthropic/claude-sonnet-4-6',
@@ -71,8 +117,8 @@ function getModelConfig(preset, customModels) {
71
117
  };
72
118
  case 'custom':
73
119
  return {
74
- primary: customModels?.primary || 'anthropic/claude-sonnet-4-6',
75
- orchestrator: customModels?.orchestrator || customModels?.primary || 'anthropic/claude-sonnet-4-6',
120
+ primary: customModels?.primary || null,
121
+ orchestrator: customModels?.orchestrator || customModels?.primary || null,
76
122
  fallbacks: [],
77
123
  models: {},
78
124
  };
@@ -110,7 +156,8 @@ function buildAgentEntry(agent, modelCfg) {
110
156
  export function mergeConfig({ agents, mode, preset, customModels }) {
111
157
  const backupPath = backupConfig();
112
158
  const config = readConfig();
113
- const modelCfg = getModelConfig(preset, customModels);
159
+ const detectedModels = detectAvailableModels();
160
+ const modelCfg = getModelConfig(preset, customModels, detectedModels);
114
161
 
115
162
  // Build agent entries
116
163
  const aliceEntries = agents.map((a) => buildAgentEntry(a, modelCfg));
@@ -140,13 +187,24 @@ export function mergeConfig({ agents, mode, preset, customModels }) {
140
187
 
141
188
  // Set defaults
142
189
  config.agents.defaults = config.agents.defaults || {};
143
- config.agents.defaults.model = {
144
- primary: modelCfg.primary,
145
- fallbacks: modelCfg.fallbacks,
146
- };
147
- if (Object.keys(modelCfg.models).length > 0) {
148
- config.agents.defaults.models = modelCfg.models;
190
+
191
+ if (modelCfg.preserve) {
192
+ // User's existing model config is intact — don't overwrite it.
193
+ // Only initialize the key if it doesn't exist at all (safety net).
194
+ config.agents.defaults.model = config.agents.defaults.model || {};
195
+ } else if (modelCfg.primary) {
196
+ config.agents.defaults.model = {
197
+ primary: modelCfg.primary,
198
+ fallbacks: modelCfg.fallbacks,
199
+ };
200
+ if (modelCfg.orchestrator && modelCfg.orchestrator !== modelCfg.primary) {
201
+ config.agents.defaults.model.orchestrator = modelCfg.orchestrator;
202
+ }
203
+ if (Object.keys(modelCfg.models).length > 0) {
204
+ config.agents.defaults.models = modelCfg.models;
205
+ }
149
206
  }
207
+ // If modelCfg.primary is null (custom/detected with nothing set), leave existing model config alone
150
208
  config.agents.defaults.workspace = join(OPENCLAW_DIR, 'workspace-olivia');
151
209
  config.agents.defaults.compaction = config.agents.defaults.compaction || { mode: 'safeguard' };
152
210
  config.agents.defaults.maxConcurrent = config.agents.defaults.maxConcurrent || 4;
package/lib/doctor.mjs ADDED
@@ -0,0 +1,169 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { execSync } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const HOME = homedir();
9
+ const OPENCLAW_DIR = join(HOME, '.openclaw');
10
+
11
+ const STARTER_AGENTS = [
12
+ 'olivia', 'dylan', 'selena', 'devon', 'quinn',
13
+ 'felix', 'daphne', 'rowan', 'darius', 'sophie',
14
+ ];
15
+
16
+ function check(label, ok, hint) {
17
+ const icon = ok ? '✓' : '✗';
18
+ console.log(` ${icon} ${label}`);
19
+ if (!ok && hint) console.log(` → ${hint}`);
20
+ return ok;
21
+ }
22
+
23
+ function getRuntime() {
24
+ try {
25
+ const v = execSync('nemoclaw --version', { stdio: 'pipe', encoding: 'utf8' }).trim();
26
+ return { name: 'NemoClaw', ok: true, version: v };
27
+ } catch {}
28
+ try {
29
+ const v = execSync('openclaw --version', { stdio: 'pipe', encoding: 'utf8' }).trim();
30
+ return { name: 'OpenClaw', ok: true, version: v };
31
+ } catch {}
32
+ return { name: 'openclaw/nemoclaw', ok: false, version: null };
33
+ }
34
+
35
+ function loadConfig() {
36
+ const configPath = join(OPENCLAW_DIR, 'openclaw.json');
37
+ if (!existsSync(configPath)) return null;
38
+ try {
39
+ return JSON.parse(readFileSync(configPath, 'utf8'));
40
+ } catch {
41
+ return 'invalid';
42
+ }
43
+ }
44
+
45
+ export async function runDoctor() {
46
+ console.log('\n 🩺 A.L.I.C.E. Doctor — Diagnostic Report\n');
47
+ let allOk = true;
48
+
49
+ // 1. Runtime check
50
+ const runtime = getRuntime();
51
+ const runtimeOk = check(
52
+ runtime.ok
53
+ ? `${runtime.name} installed (${runtime.version})`
54
+ : `${runtime.name} not found`,
55
+ runtime.ok,
56
+ 'Install OpenClaw: npm install -g openclaw'
57
+ );
58
+ allOk = allOk && runtimeOk;
59
+
60
+ // 2. Config exists and valid JSON
61
+ const configPath = join(OPENCLAW_DIR, 'openclaw.json');
62
+ const configExists = existsSync(configPath);
63
+ check('openclaw.json exists', configExists, 'Run: openclaw configure');
64
+
65
+ if (!configExists) {
66
+ allOk = false;
67
+ console.log('\n ⚠️ Cannot continue checks — openclaw.json missing.\n');
68
+ return false;
69
+ }
70
+
71
+ const config = loadConfig();
72
+ const configValid = config !== null && config !== 'invalid';
73
+ check(
74
+ 'openclaw.json is valid JSON',
75
+ configValid,
76
+ `Fix JSON syntax in ${configPath}`
77
+ );
78
+ if (!configValid) {
79
+ allOk = false;
80
+ console.log('\n ⚠️ Cannot continue checks — config is invalid JSON.\n');
81
+ return false;
82
+ }
83
+
84
+ // 3. A.L.I.C.E. agents in config
85
+ const configAgents = Array.isArray(config.agents) ? config.agents : [];
86
+ const agentsInConfig = configAgents
87
+ .filter((a) => a && STARTER_AGENTS.includes(a.id))
88
+ .map((a) => a.id);
89
+
90
+ const agentsOk = agentsInConfig.length > 0;
91
+ check(
92
+ agentsOk
93
+ ? `A.L.I.C.E. agents in config: ${agentsInConfig.join(', ')}`
94
+ : 'No A.L.I.C.E. agents found in config',
95
+ agentsOk,
96
+ 'Run: npx @robbiesrobotics/alice-agents to install'
97
+ );
98
+ allOk = allOk && agentsOk;
99
+
100
+ // Check for missing agents from full starter set
101
+ if (agentsInConfig.length > 0 && agentsInConfig.length < STARTER_AGENTS.length) {
102
+ const missing = STARTER_AGENTS.filter((id) => !agentsInConfig.includes(id));
103
+ check(
104
+ `All starter agents present (missing: ${missing.join(', ')})`,
105
+ false,
106
+ 'Run: npx @robbiesrobotics/alice-agents --update'
107
+ );
108
+ allOk = false;
109
+ } else if (agentsInConfig.length === STARTER_AGENTS.length) {
110
+ check('All starter agents present', true);
111
+ }
112
+
113
+ // 4. Agent workspaces exist on disk
114
+ if (agentsInConfig.length > 0) {
115
+ let missingWorkspaces = [];
116
+ for (const id of agentsInConfig) {
117
+ const wsDir = join(OPENCLAW_DIR, `workspace-${id}`);
118
+ if (!existsSync(wsDir)) {
119
+ missingWorkspaces.push(id);
120
+ }
121
+ }
122
+ const workspacesOk = missingWorkspaces.length === 0;
123
+ check(
124
+ workspacesOk
125
+ ? `Agent workspaces exist (${agentsInConfig.length})`
126
+ : `Agent workspaces missing: ${missingWorkspaces.join(', ')}`,
127
+ workspacesOk,
128
+ 'Run: npx @robbiesrobotics/alice-agents --update to scaffold missing workspaces'
129
+ );
130
+ allOk = allOk && workspacesOk;
131
+ }
132
+
133
+ // 5. At least one model/provider configured
134
+ let modelOk = false;
135
+ let modelLabel = null;
136
+
137
+ if (config.default_model) {
138
+ modelOk = true;
139
+ modelLabel = config.default_model;
140
+ } else if (config.models && Object.keys(config.models).length > 0) {
141
+ modelOk = true;
142
+ modelLabel = Object.keys(config.models)[0];
143
+ } else if (config.providers && Object.keys(config.providers).length > 0) {
144
+ modelOk = true;
145
+ modelLabel = Object.keys(config.providers)[0];
146
+ } else if (config.llm && Object.keys(config.llm).length > 0) {
147
+ modelOk = true;
148
+ modelLabel = Object.keys(config.llm)[0];
149
+ }
150
+
151
+ check(
152
+ modelOk
153
+ ? `Model/provider configured: ${modelLabel}`
154
+ : 'No model/provider configured',
155
+ modelOk,
156
+ 'Run: openclaw configure to set up a model provider'
157
+ );
158
+ allOk = allOk && modelOk;
159
+
160
+ // Summary
161
+ console.log();
162
+ if (allOk) {
163
+ console.log(' ✅ A.L.I.C.E. is healthy!\n');
164
+ } else {
165
+ console.log(' ⚠️ Issues found — follow the hints above to fix them.\n');
166
+ }
167
+
168
+ return allOk;
169
+ }
package/lib/installer.mjs CHANGED
@@ -2,7 +2,7 @@ import { readFileSync, existsSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { execSync } from 'node:child_process';
5
- import { configExists, mergeConfig, removeAliceAgents } from './config-merger.mjs';
5
+ import { configExists, mergeConfig, removeAliceAgents, detectAvailableModels } from './config-merger.mjs';
6
6
  import { scaffoldAll } from './workspace-scaffolder.mjs';
7
7
  import { readManifest, writeManifest } from './manifest.mjs';
8
8
  import {
@@ -170,11 +170,18 @@ function printBanner() {
170
170
  console.log();
171
171
  }
172
172
 
173
- function printSummary(mode, tier, agents, preset, userInfo) {
173
+ function printSummary(mode, tier, agents, preset, userInfo, detectedModels) {
174
+ const modelLabel =
175
+ preset === 'detected'
176
+ ? `${detectedModels?.primary || 'your configured model'} (detected)`
177
+ : preset === 'custom'
178
+ ? `custom`
179
+ : preset;
180
+
174
181
  console.log('\n ── Install Summary ──────────────────────────────');
175
182
  console.log(` Mode: ${mode}`);
176
183
  console.log(` Tier: ${tier} (${agents.length} agents)`);
177
- console.log(` Model: ${preset}`);
184
+ console.log(` Model: ${modelLabel}`);
178
185
  console.log(` User: ${userInfo.name}`);
179
186
  console.log(` Timezone: ${userInfo.timezone}`);
180
187
  console.log(' ─────────────────────────────────────────────────');
@@ -229,11 +236,26 @@ export async function runInstall(options = {}) {
229
236
  console.log(' 💡 Tip: Upgrade to NemoClaw for enterprise security: https://nvidia.com/nemoclaw\n');
230
237
  }
231
238
 
239
+ // Detect what models the user already has configured
240
+ const detectedModels = detectAvailableModels();
241
+ if (detectedModels?.hasModel) {
242
+ console.log(` ✔ Detected configured model: ${detectedModels.primary}`);
243
+ if (detectedModels.providers.length > 0) {
244
+ console.log(` Providers: ${detectedModels.providers.join(', ')}\n`);
245
+ } else {
246
+ console.log();
247
+ }
248
+ } else {
249
+ console.log(' ℹ No model configured yet — you\'ll be prompted to choose one.\n');
250
+ }
251
+
232
252
  const allAgents = loadAgentRegistry();
233
253
 
234
254
  // 2. Install mode
235
255
  let mode;
236
- if (auto) {
256
+ if (options.modeOverride) {
257
+ mode = options.modeOverride;
258
+ } else if (auto) {
237
259
  const manifest = readManifest();
238
260
  mode = manifest ? 'upgrade' : 'fresh';
239
261
  } else {
@@ -269,9 +291,12 @@ export async function runInstall(options = {}) {
269
291
  // 4. Model preset
270
292
  let preset, customModels;
271
293
  if (auto) {
272
- preset = 'sonnet';
294
+ // Non-interactive: use whatever the user already has configured.
295
+ // Only fall back to sonnet if nothing is detected (e.g. fresh OpenClaw install
296
+ // where the user explicitly set up Claude credentials).
297
+ preset = detectedModels?.hasModel ? 'detected' : 'sonnet';
273
298
  } else {
274
- preset = await promptModelPreset();
299
+ preset = await promptModelPreset(detectedModels);
275
300
  if (preset === 'custom') {
276
301
  customModels = await promptCustomModel();
277
302
  }
@@ -307,7 +332,7 @@ export async function runInstall(options = {}) {
307
332
  const agents = allAgents;
308
333
 
309
334
  // 6. Confirmation
310
- printSummary(mode, tier, agents, preset, userInfo);
335
+ printSummary(mode, tier, agents, preset, userInfo, detectedModels);
311
336
 
312
337
  if (!auto) {
313
338
  const ok = await confirm(' Proceed with installation?');
package/lib/prompter.mjs CHANGED
@@ -78,19 +78,29 @@ export async function promptUserInfo() {
78
78
  return { name, timezone: tz, notes };
79
79
  }
80
80
 
81
- export async function promptModelPreset() {
82
- return choose('Model preset:', [
83
- { label: 'Sonnet (recommended) — claude-sonnet-4-6 for all agents', value: 'sonnet' },
81
+ export async function promptModelPreset(detectedModels) {
82
+ const options = [];
83
+
84
+ // If the user already has a model configured, put it first
85
+ if (detectedModels?.hasModel) {
86
+ const label = `Use your current model (${detectedModels.primary}) — recommended`;
87
+ options.push({ label, value: 'detected' });
88
+ }
89
+
90
+ options.push(
91
+ { label: 'Sonnet — claude-sonnet-4-6 for all agents', value: 'sonnet' },
84
92
  { label: 'Opus + Sonnet — Opus for orchestrator, Sonnet for specialists', value: 'opus-sonnet' },
85
93
  { label: 'OpenAI — GPT-5.4 / GPT-5.4-mini', value: 'openai' },
86
94
  { label: 'Local (Ollama) — requires local models', value: 'local' },
87
95
  { label: 'Custom — specify your own model strings', value: 'custom' },
88
- ]);
96
+ );
97
+
98
+ return choose('\n Model selection:', options);
89
99
  }
90
100
 
91
101
  export async function promptCustomModel() {
92
- const primary = await input('Primary model (e.g., anthropic/claude-sonnet-4-6)');
93
- const orchestrator = await input('Orchestrator model (or same as primary)', primary);
102
+ const primary = await input(' Primary model (e.g., anthropic/claude-sonnet-4-6, openai/gpt-4o, ollama/llama3)');
103
+ const orchestrator = await input(' Orchestrator model (or same as primary)', primary);
94
104
  return { primary, orchestrator };
95
105
  }
96
106
 
@@ -12,7 +12,7 @@ const SKILLS_DIR = join(OPENCLAW_DIR, 'skills');
12
12
  const PRODUCT_FILES = ['SOUL.md', 'AGENTS.md', 'IDENTITY.md', 'TOOLS.md'];
13
13
 
14
14
  // User files — only created if missing
15
- const USER_FILES = ['PLAYBOOK.md', 'LEARNINGS.md', 'FEEDBACK.md', 'USER.md'];
15
+ const USER_FILES = ['PLAYBOOK.md', 'LEARNINGS.md', 'FEEDBACK.md', 'USER.md', 'MEMORY.md'];
16
16
 
17
17
  function renderTemplate(template, vars) {
18
18
  let result = template;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbiesrobotics/alice-agents",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "description": "A.L.I.C.E. — 28 AI agents for OpenClaw. One conversation, one team.",
5
5
  "bin": {
6
6
  "alice-agents": "bin/alice-install.mjs"
@@ -28,6 +28,10 @@
28
28
  "SELF-HEALING-SPEC.md",
29
29
  "README.md"
30
30
  ],
31
+ "scripts": {
32
+ "test": "node --test test/*.test.mjs",
33
+ "test:check": "node --check lib/*.mjs bin/*.mjs"
34
+ },
31
35
  "publishConfig": {
32
36
  "access": "public"
33
37
  }
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,22 @@
1
+ # MEMORY.md — {{agentName}}
2
+
3
+ > Persistent memory for {{agentName}}, {{agentDomain}} specialist.
4
+ > This file is yours — add notes, context, and learnings that should persist across sessions.
5
+
6
+ ## Identity
7
+
8
+ - **Name:** {{agentName}}
9
+ - **Domain:** {{agentDomain}}
10
+ - **Team:** A.L.I.C.E.
11
+
12
+ ## Active Projects
13
+
14
+ <!-- Add ongoing projects and their current status here -->
15
+
16
+ ## Key Notes
17
+
18
+ <!-- Jot down anything important to remember across sessions -->
19
+
20
+ ## Decisions Made
21
+
22
+ <!-- Record significant decisions and their rationale -->
package/tools/.gitkeep ADDED
File without changes