@robbiesrobotics/alice-agents 1.1.1 → 1.2.1

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/lib/installer.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { readFileSync } from 'node:fs';
1
+ 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';
@@ -184,6 +184,22 @@ function printSummary(mode, tier, agents, preset, userInfo) {
184
184
  export async function runInstall(options = {}) {
185
185
  const auto = options.yes || false;
186
186
 
187
+ // Check health flag first (before banner)
188
+ if (process.argv.includes('--health')) {
189
+ const healthPath = join(process.env.HOME, '.openclaw', '.alice-health-alert.json');
190
+ if (existsSync(healthPath)) {
191
+ const alerts = JSON.parse(readFileSync(healthPath, 'utf8'));
192
+ console.log('\n⚠️ A.L.I.C.E. Health Report\n');
193
+ for (const alert of alerts.alerts) {
194
+ console.log(` [${alert.severity}] ${alert.category}: ${alert.field}`);
195
+ console.log(` ${alert.description}\n`);
196
+ }
197
+ process.exit(0);
198
+ }
199
+ console.log('✅ A.L.I.C.E. is healthy\n');
200
+ process.exit(0);
201
+ }
202
+
187
203
  printBanner();
188
204
 
189
205
  // 1. Detect OpenClaw — offer to install if missing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbiesrobotics/alice-agents",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
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"
@@ -20,7 +20,10 @@
20
20
  "files": [
21
21
  "bin/",
22
22
  "lib/",
23
+ "tools/",
24
+ "snapshots/",
23
25
  "templates/",
26
+ "SELF-HEALING-SPEC.md",
24
27
  "README.md"
25
28
  ],
26
29
  "publishConfig": {
@@ -0,0 +1,221 @@
1
+ {
2
+ "meta": {
3
+ "capturedAt": "2026-03-16T00:00:00Z",
4
+ "openclawVersion": "2026.3.13",
5
+ "aliceVersion": "1.1.1",
6
+ "description": "Config fields A.L.I.C.E. depends on",
7
+ "checksum": "458186002246ca46"
8
+ },
9
+ "agents": {
10
+ "defaults": {
11
+ "model": {
12
+ "path": "agents.defaults.model",
13
+ "required": true,
14
+ "fields": {
15
+ "primary": {
16
+ "type": "string",
17
+ "example": "anthropic/claude-sonnet-4-6"
18
+ },
19
+ "fallbacks": {
20
+ "type": "array"
21
+ }
22
+ }
23
+ },
24
+ "workspace": {
25
+ "path": "agents.defaults.workspace",
26
+ "type": "string",
27
+ "required": true
28
+ },
29
+ "heartbeat": {
30
+ "path": "agents.defaults.heartbeat",
31
+ "required": false,
32
+ "fields": {
33
+ "every": {
34
+ "type": "string",
35
+ "example": "15m"
36
+ },
37
+ "target": {
38
+ "type": "string",
39
+ "allowedValues": [
40
+ "last",
41
+ "new"
42
+ ]
43
+ },
44
+ "directPolicy": {
45
+ "type": "string",
46
+ "allowedValues": [
47
+ "allow",
48
+ "deny"
49
+ ]
50
+ },
51
+ "prompt": {
52
+ "type": "string"
53
+ }
54
+ }
55
+ },
56
+ "maxConcurrent": {
57
+ "path": "agents.defaults.maxConcurrent",
58
+ "type": "number",
59
+ "required": false
60
+ },
61
+ "subagents": {
62
+ "path": "agents.defaults.subagents",
63
+ "fields": {
64
+ "maxConcurrent": {
65
+ "type": "number"
66
+ },
67
+ "archiveAfterMinutes": {
68
+ "type": "number"
69
+ },
70
+ "runTimeoutSeconds": {
71
+ "type": "number"
72
+ }
73
+ }
74
+ },
75
+ "compaction": {
76
+ "path": "agents.defaults.compaction",
77
+ "fields": {
78
+ "mode": {
79
+ "type": "string",
80
+ "allowedValues": [
81
+ "safeguard",
82
+ "auto",
83
+ "off"
84
+ ]
85
+ }
86
+ }
87
+ }
88
+ },
89
+ "list_entry": {
90
+ "description": "Schema for each entry in agents.list",
91
+ "fields": {
92
+ "id": {
93
+ "type": "string",
94
+ "required": true
95
+ },
96
+ "name": {
97
+ "type": "string",
98
+ "required": true
99
+ },
100
+ "workspace": {
101
+ "type": "string",
102
+ "required": true
103
+ },
104
+ "identity": {
105
+ "required": true,
106
+ "fields": {
107
+ "name": {
108
+ "type": "string"
109
+ },
110
+ "theme": {
111
+ "type": "string"
112
+ },
113
+ "emoji": {
114
+ "type": "string"
115
+ }
116
+ }
117
+ },
118
+ "sandbox": {
119
+ "required": true,
120
+ "fields": {
121
+ "mode": {
122
+ "type": "string",
123
+ "allowedValues": [
124
+ "off",
125
+ "all"
126
+ ]
127
+ },
128
+ "scope": {
129
+ "type": "string",
130
+ "allowedValues": [
131
+ "agent",
132
+ "workspace"
133
+ ]
134
+ }
135
+ }
136
+ },
137
+ "tools": {
138
+ "required": true,
139
+ "variants": {
140
+ "profile_based": {
141
+ "fields": {
142
+ "profile": {
143
+ "type": "string",
144
+ "allowedValues": [
145
+ "full",
146
+ "coding",
147
+ "basic"
148
+ ]
149
+ },
150
+ "alsoAllow": {
151
+ "type": "array"
152
+ },
153
+ "deny": {
154
+ "type": "array"
155
+ }
156
+ }
157
+ },
158
+ "explicit": {
159
+ "fields": {
160
+ "allow": {
161
+ "type": "array",
162
+ "required": true
163
+ },
164
+ "deny": {
165
+ "type": "array"
166
+ }
167
+ }
168
+ }
169
+ }
170
+ },
171
+ "model": {
172
+ "type": "string",
173
+ "required": false
174
+ },
175
+ "default": {
176
+ "type": "boolean",
177
+ "required": false
178
+ },
179
+ "subagents": {
180
+ "type": "object",
181
+ "required": false
182
+ },
183
+ "groupChat": {
184
+ "type": "object",
185
+ "required": false
186
+ }
187
+ }
188
+ }
189
+ },
190
+ "tools": {
191
+ "agentToAgent": {
192
+ "path": "tools.agentToAgent",
193
+ "fields": {
194
+ "allow": {
195
+ "type": "array",
196
+ "description": "Agent IDs that can receive spawned tasks"
197
+ }
198
+ }
199
+ }
200
+ },
201
+ "hooks": {
202
+ "knownHooks": [
203
+ "boot-md",
204
+ "bootstrap-extra-files",
205
+ "command-logger",
206
+ "session-memory"
207
+ ],
208
+ "path": "hooks.entries"
209
+ },
210
+ "sessions": {
211
+ "path": "sessions",
212
+ "fields": {
213
+ "plugins": {
214
+ "type": "object"
215
+ },
216
+ "capabilities": {
217
+ "type": "object"
218
+ }
219
+ }
220
+ }
221
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "meta": {
3
+ "capturedAt": "2026-03-16T00:00:00Z",
4
+ "openclawVersion": "2026.3.13",
5
+ "aliceVersion": "1.1.1",
6
+ "description": "Tools A.L.I.C.E. references in agent configs"
7
+ },
8
+ "tools": {
9
+ "read": { "criticality": "core", "usedBy": ["all"] },
10
+ "write": { "criticality": "core", "usedBy": ["all"] },
11
+ "edit": { "criticality": "core", "usedBy": ["dylan","darius","avery","isaac","felix","caleb","devon","quinn","alex","daphne"] },
12
+ "exec": { "criticality": "core", "usedBy": ["dylan","darius","avery","isaac","owen","selena","devon","quinn","alex","felix","caleb"] },
13
+ "process": { "criticality": "core", "usedBy": ["dylan","darius","avery","isaac","devon","quinn"] },
14
+ "apply_patch": { "criticality": "core", "usedBy": ["dylan","darius","avery","isaac","felix","caleb","devon","quinn","alex","daphne"] },
15
+ "web_search": { "criticality": "core", "usedBy": ["all"] },
16
+ "web_fetch": { "criticality": "core", "usedBy": ["all"] },
17
+ "browser": { "criticality": "optional", "usedBy": ["olivia","rowan","quinn","uma","alex","tommy","nadia","morgan","sloane"] },
18
+ "canvas": { "criticality": "optional", "usedBy": ["olivia","nadia"] },
19
+ "message": { "criticality": "optional", "usedBy": ["olivia","clara","sophie","sloane","morgan","eva","parker"] },
20
+ "tts": { "criticality": "optional", "usedBy": ["olivia"] },
21
+ "sessions_spawn": { "criticality": "core", "usedBy": ["olivia"] },
22
+ "sessions_send": { "criticality": "core", "usedBy": ["olivia"] },
23
+ "sessions_list": { "criticality": "core", "usedBy": ["olivia","all"] },
24
+ "sessions_history":{ "criticality": "core", "usedBy": ["olivia","all"] },
25
+ "session_status": { "criticality": "core", "usedBy": ["olivia","all"] },
26
+ "agents_list": { "criticality": "core", "usedBy": ["olivia"] },
27
+ "cron": { "criticality": "optional", "usedBy": ["olivia","avery","tommy","sloane","morgan","eva","parker"] },
28
+ "memory_search": { "criticality": "core", "usedBy": ["olivia"] },
29
+ "memory_get": { "criticality": "core", "usedBy": ["olivia"] },
30
+ "image": { "criticality": "optional", "usedBy": ["olivia"] },
31
+ "pdf": { "criticality": "optional", "usedBy": ["olivia"] }
32
+ },
33
+ "profiles": {
34
+ "full": { "description": "All tools available", "usedBy": ["olivia"] },
35
+ "coding": { "description": "Code-focused toolset with exec/edit/apply_patch", "usedBy": ["dylan","darius","avery","isaac","devon","felix","quinn","alex","caleb"] }
36
+ }
37
+ }
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * A.L.I.C.E. Compatibility Checker
4
+ * Diffs current OpenClaw installation against stored snapshots.
5
+ * Exit 0 = compatible, 1 = breaking changes found.
6
+ */
7
+
8
+ import { readFileSync, existsSync, writeFileSync } from 'node:fs';
9
+ import { join, dirname } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { execSync } from 'node:child_process';
12
+ import { createHash } from 'node:crypto';
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const ROOT = join(__dirname, '..');
16
+
17
+ // --- CLI args ---
18
+ const args = process.argv.slice(2);
19
+ const verbose = args.includes('--verbose');
20
+ const outputFile = args.find(a => a.startsWith('--output='))?.split('=')[1];
21
+
22
+ function log(...a) { if (verbose) console.log(...a); }
23
+ function warn(msg) { console.warn(` ⚠️ ${msg}`); }
24
+
25
+ // --- Helpers ---
26
+ function loadJSON(path) {
27
+ if (!existsSync(path)) return null;
28
+ return JSON.parse(readFileSync(path, 'utf8'));
29
+ }
30
+
31
+ function getOpenClawVersion() {
32
+ try {
33
+ const out = execSync('openclaw --version 2>/dev/null', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] });
34
+ const m = out.match(/(\d{4}\.\d+\.\d+)/);
35
+ return m ? m[1] : 'unknown';
36
+ } catch { return 'unknown'; }
37
+ }
38
+
39
+ function getOpenClawConfig() {
40
+ const configPath = join(process.env.HOME, '.openclaw', 'openclaw.json');
41
+ return loadJSON(configPath);
42
+ }
43
+
44
+ // --- Diff functions ---
45
+
46
+ function diffConfigSchema(snapshot, liveConfig) {
47
+ const changes = [];
48
+
49
+ // Check agents.defaults fields
50
+ const defaults = liveConfig?.agents?.defaults || {};
51
+ const snap = snapshot?.agents?.defaults || {};
52
+
53
+ if (!defaults.model?.primary) {
54
+ changes.push({
55
+ category: 'config',
56
+ severity: 'high',
57
+ field: 'agents.defaults.model.primary',
58
+ change: 'Field missing or undefined',
59
+ autoFixable: false
60
+ });
61
+ }
62
+
63
+ // Check sandbox allowedValues
64
+ const agents = liveConfig?.agents?.list || [];
65
+ for (const agent of agents) {
66
+ const mode = agent?.sandbox?.mode;
67
+ const allowed = ['off', 'all'];
68
+ if (mode && !allowed.includes(mode)) {
69
+ changes.push({
70
+ category: 'config',
71
+ severity: 'high',
72
+ field: `agents.list[${agent.id}].sandbox.mode`,
73
+ change: `Unexpected value '${mode}', expected one of: ${allowed.join(', ')}`,
74
+ autoFixable: false
75
+ });
76
+ }
77
+ }
78
+
79
+ // Check compaction mode
80
+ const compactionMode = defaults?.compaction?.mode;
81
+ const validModes = ['safeguard', 'auto', 'off'];
82
+ if (compactionMode && !validModes.includes(compactionMode)) {
83
+ changes.push({
84
+ category: 'behavioral',
85
+ severity: 'medium',
86
+ field: 'agents.defaults.compaction.mode',
87
+ change: `Value '${compactionMode}' may not be valid. Expected: ${validModes.join(', ')}`,
88
+ autoFixable: false
89
+ });
90
+ }
91
+
92
+ return changes;
93
+ }
94
+
95
+ function diffToolAPI(snapshot, liveConfig) {
96
+ const changes = [];
97
+ const snapTools = snapshot?.tools || {};
98
+
99
+ // Get all tools referenced in agent configs
100
+ const referencedTools = new Set();
101
+ const referencedProfiles = new Set();
102
+
103
+ for (const agent of liveConfig?.agents?.list || []) {
104
+ const t = agent?.tools || {};
105
+ if (t.profile) referencedProfiles.add(t.profile);
106
+ for (const tool of [...(t.allow || []), ...(t.alsoAllow || []), ...(t.deny || [])]) {
107
+ referencedTools.add(tool);
108
+ }
109
+ }
110
+
111
+ const knownTools = new Set(Object.keys(snapTools));
112
+
113
+ // Check for tools in use that aren't in our snapshot (may be new — not breaking)
114
+ for (const tool of referencedTools) {
115
+ if (!knownTools.has(tool)) {
116
+ log(` Note: Tool '${tool}' not in snapshot — may be new`);
117
+ }
118
+ }
119
+
120
+ // Check snapshot profiles still exist
121
+ const snapProfiles = snapshot?.profiles || {};
122
+ for (const profile of referencedProfiles) {
123
+ if (!snapProfiles[profile]) {
124
+ // Can't verify, just note
125
+ log(` Note: Profile '${profile}' used but not in snapshot`);
126
+ }
127
+ }
128
+
129
+ return changes;
130
+ }
131
+
132
+ function diffBehavioral(snapshot, liveConfig) {
133
+ const changes = [];
134
+ const defaults = liveConfig?.agents?.defaults || {};
135
+ const snapDefaults = snapshot?.agents?.defaults || {};
136
+
137
+ // Check heartbeat still works
138
+ if (defaults.heartbeat && !defaults.heartbeat.every) {
139
+ changes.push({
140
+ category: 'behavioral',
141
+ severity: 'medium',
142
+ field: 'agents.defaults.heartbeat.every',
143
+ change: 'Heartbeat interval missing',
144
+ autoFixable: true,
145
+ fix: { type: 'field-add', path: 'agents.defaults.heartbeat.every', value: '15m' }
146
+ });
147
+ }
148
+
149
+ // Check subagents runTimeoutSeconds still present
150
+ if (defaults.subagents && !defaults.subagents.runTimeoutSeconds) {
151
+ changes.push({
152
+ category: 'behavioral',
153
+ severity: 'low',
154
+ field: 'agents.defaults.subagents.runTimeoutSeconds',
155
+ change: 'runTimeoutSeconds missing from subagents defaults',
156
+ autoFixable: true,
157
+ fix: { type: 'field-add', path: 'agents.defaults.subagents.runTimeoutSeconds', value: 900 }
158
+ });
159
+ }
160
+
161
+ return changes;
162
+ }
163
+
164
+ function diffSkills() {
165
+ const changes = [];
166
+ // Check if skills directory structure is intact
167
+ const skillsPath = join(
168
+ process.env.HOME,
169
+ '.local/share/fnm/node-versions',
170
+ );
171
+ // Skills live in node_modules/openclaw/skills — check a known skill exists
172
+ try {
173
+ execSync('ls ~/.local/share/fnm/node-versions/*/installation/lib/node_modules/openclaw/skills/coding-agent/SKILL.md 2>/dev/null | head -1', {
174
+ encoding: 'utf8', shell: '/bin/sh', stdio: ['pipe','pipe','pipe']
175
+ });
176
+ } catch {
177
+ changes.push({
178
+ category: 'skills',
179
+ severity: 'medium',
180
+ field: 'skills.coding-agent',
181
+ change: 'coding-agent skill not found in expected location',
182
+ autoFixable: false
183
+ });
184
+ }
185
+ return changes;
186
+ }
187
+
188
+ // --- Main ---
189
+ async function main() {
190
+ const openclawVersion = getOpenClawVersion();
191
+ const aliceVersion = loadJSON(join(ROOT, 'package.json'))?.version || 'unknown';
192
+
193
+ console.log(`\n 🔍 A.L.I.C.E. Compatibility Checker`);
194
+ console.log(` OpenClaw: ${openclawVersion} | A.L.I.C.E.: ${aliceVersion}\n`);
195
+
196
+ const schemaSnapshot = loadJSON(join(ROOT, 'snapshots', 'schema-snapshot.json'));
197
+ const toolSnapshot = loadJSON(join(ROOT, 'snapshots', 'tool-snapshot.json'));
198
+ const liveConfig = getOpenClawConfig();
199
+
200
+ if (!schemaSnapshot || !toolSnapshot) {
201
+ warn('Snapshots missing — cannot check compatibility');
202
+ process.exit(0);
203
+ }
204
+
205
+ if (!liveConfig) {
206
+ warn('OpenClaw config not found — is OpenClaw installed and configured?');
207
+ process.exit(1);
208
+ }
209
+
210
+ const breakingChanges = [
211
+ ...diffConfigSchema(schemaSnapshot, liveConfig),
212
+ ...diffToolAPI(toolSnapshot, liveConfig),
213
+ ...diffBehavioral(schemaSnapshot, liveConfig),
214
+ ...diffSkills()
215
+ ];
216
+
217
+ const criticals = breakingChanges.filter(c => c.severity === 'critical' || c.severity === 'high');
218
+ const mediums = breakingChanges.filter(c => c.severity === 'medium');
219
+ const lows = breakingChanges.filter(c => c.severity === 'low');
220
+ const autoFixable = breakingChanges.filter(c => c.autoFixable);
221
+
222
+ const report = {
223
+ generatedAt: new Date().toISOString(),
224
+ openclawVersion,
225
+ aliceVersion,
226
+ snapshotVersion: schemaSnapshot.meta?.openclawVersion,
227
+ compatible: breakingChanges.length === 0,
228
+ summary: {
229
+ total: breakingChanges.length,
230
+ critical: criticals.length,
231
+ medium: mediums.length,
232
+ low: lows.length,
233
+ autoFixable: autoFixable.length
234
+ },
235
+ breakingChanges
236
+ };
237
+
238
+ if (outputFile) {
239
+ writeFileSync(outputFile, JSON.stringify(report, null, 2));
240
+ console.log(` Report written to: ${outputFile}`);
241
+ }
242
+
243
+ if (breakingChanges.length === 0) {
244
+ console.log(' ✅ Compatible — no breaking changes detected\n');
245
+ process.exit(0);
246
+ }
247
+
248
+ console.log(` Found ${breakingChanges.length} issue(s):\n`);
249
+ for (const c of breakingChanges) {
250
+ const icon = c.severity === 'high' || c.severity === 'critical' ? '🔴' :
251
+ c.severity === 'medium' ? '🟡' : '🟢';
252
+ const fix = c.autoFixable ? ' [auto-fixable]' : ' [manual review]';
253
+ console.log(` ${icon} [${c.category}] ${c.field}`);
254
+ console.log(` ${c.change}${fix}\n`);
255
+ }
256
+
257
+ if (autoFixable.length > 0) {
258
+ console.log(` 💡 ${autoFixable.length} issue(s) can be auto-fixed.`);
259
+ console.log(` Run: npx @robbiesrobotics/alice-agents --health\n`);
260
+ }
261
+
262
+ process.exit(criticals.length > 0 ? 1 : 0);
263
+ }
264
+
265
+ main().catch(err => {
266
+ console.error('Checker error:', err.message);
267
+ process.exit(1);
268
+ });