@soederpop/luca 0.0.23 → 0.0.25

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.
Files changed (58) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +6 -1
  3. package/assistants/codingAssistant/hooks.ts +0 -1
  4. package/assistants/lucaExpert/CORE.md +37 -0
  5. package/assistants/lucaExpert/hooks.ts +9 -0
  6. package/assistants/lucaExpert/tools.ts +177 -0
  7. package/commands/build-bootstrap.ts +41 -1
  8. package/docs/TABLE-OF-CONTENTS.md +0 -1
  9. package/docs/apis/clients/rest.md +5 -5
  10. package/docs/apis/features/agi/assistant.md +1 -1
  11. package/docs/apis/features/agi/conversation-history.md +6 -7
  12. package/docs/apis/features/agi/conversation.md +1 -1
  13. package/docs/apis/features/agi/semantic-search.md +1 -1
  14. package/docs/bootstrap/CLAUDE.md +1 -1
  15. package/docs/bootstrap/SKILL.md +7 -3
  16. package/docs/bootstrap/templates/luca-cli.ts +5 -0
  17. package/docs/mcp/readme.md +1 -1
  18. package/docs/tutorials/00-bootstrap.md +18 -0
  19. package/package.json +2 -2
  20. package/scripts/stamp-build.sh +12 -0
  21. package/scripts/test-docs-reader.ts +10 -0
  22. package/src/agi/container.server.ts +8 -5
  23. package/src/agi/features/assistant.ts +208 -55
  24. package/src/agi/features/assistants-manager.ts +138 -66
  25. package/src/agi/features/conversation.ts +46 -14
  26. package/src/agi/features/docs-reader.ts +142 -0
  27. package/src/agi/features/openapi.ts +1 -1
  28. package/src/agi/features/skills-library.ts +257 -313
  29. package/src/bootstrap/generated.ts +8163 -6
  30. package/src/cli/build-info.ts +4 -0
  31. package/src/cli/cli.ts +2 -1
  32. package/src/commands/bootstrap.ts +16 -1
  33. package/src/commands/eval.ts +6 -1
  34. package/src/commands/sandbox-mcp.ts +17 -7
  35. package/src/helper.ts +56 -2
  36. package/src/introspection/generated.agi.ts +2409 -1608
  37. package/src/introspection/generated.node.ts +902 -594
  38. package/src/introspection/generated.web.ts +1 -1
  39. package/src/node/container.ts +1 -1
  40. package/src/node/features/content-db.ts +251 -13
  41. package/src/node/features/git.ts +90 -0
  42. package/src/node/features/grep.ts +1 -1
  43. package/src/node/features/proc.ts +1 -0
  44. package/src/node/features/tts.ts +1 -1
  45. package/src/node/features/vm.ts +48 -0
  46. package/src/scaffolds/generated.ts +2 -2
  47. package/assistants/architect/CORE.md +0 -3
  48. package/assistants/architect/hooks.ts +0 -3
  49. package/assistants/architect/tools.ts +0 -10
  50. package/docs/apis/features/agi/skills-library.md +0 -234
  51. package/docs/reports/assistant-bugs.md +0 -38
  52. package/docs/reports/attach-pattern-usage.md +0 -18
  53. package/docs/reports/code-audit-results.md +0 -391
  54. package/docs/reports/console-hmr-design.md +0 -170
  55. package/docs/reports/helper-semantic-search.md +0 -72
  56. package/docs/reports/introspection-audit-tasks.md +0 -378
  57. package/docs/reports/luca-mcp-improvements.md +0 -128
  58. package/test-integration/skills-library.test.ts +0 -157
@@ -1,234 +0,0 @@
1
- # SkillsLibrary (features.skillsLibrary)
2
-
3
- Manages two contentbase collections of skills following the Claude Code SKILL.md format. Project-level skills live in .claude/skills/ and user-level skills live in ~/.luca/skills/. Skills can be discovered, searched, created, updated, and removed at runtime.
4
-
5
- ## Usage
6
-
7
- ```ts
8
- container.feature('skillsLibrary', {
9
- // Path to project-level skills directory
10
- projectSkillsPath,
11
- // Path to user-level global skills directory
12
- userSkillsPath,
13
- })
14
- ```
15
-
16
- ## Options (Zod v4 schema)
17
-
18
- | Property | Type | Description |
19
- |----------|------|-------------|
20
- | `projectSkillsPath` | `string` | Path to project-level skills directory |
21
- | `userSkillsPath` | `string` | Path to user-level global skills directory |
22
-
23
- ## Methods
24
-
25
- ### load
26
-
27
- Loads both project and user skill collections from disk. Gracefully handles missing directories.
28
-
29
- **Returns:** `Promise<SkillsLibrary>`
30
-
31
-
32
-
33
- ### list
34
-
35
- Lists all skills from both collections. Project skills come first.
36
-
37
- **Returns:** `SkillEntry[]`
38
-
39
-
40
-
41
- ### find
42
-
43
- Finds a skill by name. Project skills take precedence over user skills.
44
-
45
- **Parameters:**
46
-
47
- | Name | Type | Required | Description |
48
- |------|------|----------|-------------|
49
- | `name` | `string` | ✓ | The skill name to find (case-insensitive) |
50
-
51
- **Returns:** `SkillEntry | undefined`
52
-
53
-
54
-
55
- ### search
56
-
57
- Searches skills by substring match against name and description.
58
-
59
- **Parameters:**
60
-
61
- | Name | Type | Required | Description |
62
- |------|------|----------|-------------|
63
- | `query` | `string` | ✓ | The search query |
64
-
65
- **Returns:** `SkillEntry[]`
66
-
67
-
68
-
69
- ### getSkill
70
-
71
- Gets a skill by name. Alias for find().
72
-
73
- **Parameters:**
74
-
75
- | Name | Type | Required | Description |
76
- |------|------|----------|-------------|
77
- | `name` | `string` | ✓ | The skill name |
78
-
79
- **Returns:** `SkillEntry | undefined`
80
-
81
-
82
-
83
- ### create
84
-
85
- Creates a new SKILL.md file in the specified collection. Maintains the directory-per-skill structure (skill-name/SKILL.md).
86
-
87
- **Parameters:**
88
-
89
- | Name | Type | Required | Description |
90
- |------|------|----------|-------------|
91
- | `skill` | `{
92
- name: string
93
- description: string
94
- body: string
95
- meta?: Record<string, unknown>
96
- }` | ✓ | The skill to create |
97
- | `target` | `'project' | 'user'` | | Which collection to write to (default: 'project') |
98
-
99
- **Returns:** `Promise<SkillEntry>`
100
-
101
-
102
-
103
- ### update
104
-
105
- Updates an existing skill's content or metadata.
106
-
107
- **Parameters:**
108
-
109
- | Name | Type | Required | Description |
110
- |------|------|----------|-------------|
111
- | `name` | `string` | ✓ | The skill name to update |
112
- | `updates` | `{
113
- description?: string
114
- body?: string
115
- meta?: Record<string, unknown>
116
- }` | ✓ | Fields to update |
117
-
118
- **Returns:** `Promise<SkillEntry>`
119
-
120
-
121
-
122
- ### remove
123
-
124
- Removes a skill by name, deleting its SKILL.md and cleaning up the directory.
125
-
126
- **Parameters:**
127
-
128
- | Name | Type | Required | Description |
129
- |------|------|----------|-------------|
130
- | `name` | `string` | ✓ | The skill name to remove |
131
-
132
- **Returns:** `Promise<boolean>`
133
-
134
-
135
-
136
- ### toConversationTools
137
-
138
- Converts all skills into ConversationTool format for use with Conversation. Each skill becomes a tool that returns its instruction body when invoked.
139
-
140
- **Returns:** `Record<string, ConversationTool>`
141
-
142
-
143
-
144
- ### toSystemPromptBlock
145
-
146
- Generates a markdown block listing all available skills with names and descriptions. Suitable for injecting into a system prompt.
147
-
148
- **Returns:** `string`
149
-
150
-
151
-
152
- ## Getters
153
-
154
- | Property | Type | Description |
155
- |----------|------|-------------|
156
- | `projectCollection` | `Collection` | Returns the project-level contentbase Collection, lazily initialized. |
157
- | `userCollection` | `Collection` | Returns the user-level contentbase Collection, lazily initialized. |
158
- | `isLoaded` | `boolean` | Whether the skills library has been loaded. |
159
- | `skillNames` | `string[]` | Array of all skill names across both collections. |
160
-
161
- ## Events (Zod v4 schema)
162
-
163
- ### loaded
164
-
165
- Fired after both project and user skill collections are loaded
166
-
167
-
168
-
169
- ### skillCreated
170
-
171
- Fired after a new skill is written to disk
172
-
173
- **Event Arguments:**
174
-
175
- | Name | Type | Description |
176
- |------|------|-------------|
177
- | `arg0` | `any` | The created SkillEntry object |
178
-
179
-
180
-
181
- ### skillUpdated
182
-
183
- Fired after an existing skill is updated
184
-
185
- **Event Arguments:**
186
-
187
- | Name | Type | Description |
188
- |------|------|-------------|
189
- | `arg0` | `any` | The updated SkillEntry object |
190
-
191
-
192
-
193
- ### skillRemoved
194
-
195
- Fired after a skill is deleted
196
-
197
- **Event Arguments:**
198
-
199
- | Name | Type | Description |
200
- |------|------|-------------|
201
- | `arg0` | `string` | The name of the removed skill |
202
-
203
-
204
-
205
- ## State (Zod v4 schema)
206
-
207
- | Property | Type | Description |
208
- |----------|------|-------------|
209
- | `enabled` | `boolean` | Whether this feature is currently enabled |
210
- | `loaded` | `boolean` | Whether both collections have been loaded |
211
- | `projectSkillCount` | `number` | Number of skills in the project collection |
212
- | `userSkillCount` | `number` | Number of skills in the user-level collection |
213
- | `totalSkillCount` | `number` | Total number of skills across both collections |
214
-
215
- ## Examples
216
-
217
- **features.skillsLibrary**
218
-
219
- ```ts
220
- const skills = container.feature('skillsLibrary')
221
- await skills.load()
222
-
223
- // List and search
224
- const allSkills = skills.list()
225
- const matches = skills.search('code review')
226
-
227
- // Create a new skill
228
- await skills.create({
229
- name: 'summarize',
230
- description: 'Summarize a document',
231
- body: '## Instructions\nRead the document and produce a concise summary.'
232
- })
233
- ```
234
-
@@ -1,38 +0,0 @@
1
- # Assistant systemPrompt Bug Fix Verification
2
-
3
- The bug: class field initializers (`private _systemPrompt: string = ''`) on Feature subclasses
4
- overwrite values set during `afterInitialize()` because ES2022 field initializers run AFTER `super()` returns.
5
-
6
- Fix: use `declare private _systemPrompt: string` which emits no JavaScript, so afterInitialize values persist.
7
-
8
- ## Test
9
-
10
- ```ts
11
- const assistant = container.feature('assistant', {
12
- folder: '/Users/jon/@soederpop/commands/voice/assistant'
13
- })
14
- ```
15
-
16
- systemPrompt should contain the CORE.md content (not be empty):
17
-
18
- ```ts
19
- console.log("systemPrompt length:", assistant.systemPrompt.length)
20
- console.log("contains omar:", assistant.systemPrompt.toLowerCase().includes("omar"))
21
- console.log("first 80 chars:", assistant.systemPrompt.slice(0, 80))
22
- ```
23
-
24
- Tools should have been loaded from tools.ts:
25
-
26
- ```ts
27
- console.log("tools loaded:", Object.keys(assistant.tools))
28
- ```
29
-
30
- Starting the assistant should pass the systemPrompt into the conversation:
31
-
32
- ```ts
33
- await assistant.start()
34
- const systemMsg = assistant.conversation.messages[0]
35
- console.log("conversation has system message:", systemMsg.role === "system")
36
- console.log("system message has content:", systemMsg.content.length > 0)
37
- console.log("system message contains omar:", systemMsg.content.toLowerCase().includes("omar"))
38
- ```
@@ -1,18 +0,0 @@
1
- # Attach Pattern
2
-
3
- Here is some problematic code:
4
-
5
- ```ts skip
6
- const { container } = context
7
- const { VoiceRouter } = await import(resolve(import.meta.dir, 'voice/router.ts'))
8
- container.features.register('voiceRouter', VoiceRouter as any)
9
- const router = container.feature('voiceRouter' as any, { enable: true }) as InstanceType<typeof VoiceRouter>
10
- ```
11
-
12
- I'd rather see
13
-
14
- ```ts skip
15
- // we know since we're inside a command this has to be our path anyway, relative to the container's cwd is how we're discovered
16
- await import(container.paths.resolve('commands','voice','router.ts')).then(({ VoiceRouter }) => container.use(VoiceRouter))
17
- ```
18
-
@@ -1,391 +0,0 @@
1
- ---
2
- title: Code Audit - Container Abstraction Violations
3
- status: active
4
- type: report
5
- createdAt: 2026-02-26
6
- updatedAt: 2026-02-26
7
- ---
8
-
9
- # Code Audit: Container Abstraction Violations
10
-
11
- Audit of `src/**/features/**`, `src/**/clients/**`, `src/clients/**`, `src/servers/**`, and `src/commands/**` for violations of the container abstraction pattern.
12
-
13
- **Excluded from audit**: `fs.ts`, `proc.ts`, `git.ts`, `os.ts` — these are core wrappers that intentionally import Node builtins. `file-manager.ts` is allowed to use `path` directly.
14
-
15
- ## Severity Legend
16
-
17
- - **HIGH**: Breaks Node.js compatibility, or completely bypasses container when equivalent exists
18
- - **MEDIUM**: Uses builtins/process.env when container provides an alternative
19
- - **LOW**: Minor style issue, or acceptable edge case
20
-
21
- ---
22
-
23
- ## Summary
24
-
25
- | Category | Files Audited | Files with Violations | HIGH | MEDIUM | LOW |
26
- |----------|--------------|----------------------|------|--------|-----|
27
- | Node Features | 14 | 11 | 19 | 14 | 6 |
28
- | AGI Features | 10 | 3 | 12 | 4 | 0 |
29
- | Clients | 7 | 3 | 3 | 2 | 0 |
30
- | Servers | 3 | 2 | 1 | 1 | 0 |
31
- | Commands | 11 | 5 | 3 | 5 | 2 |
32
- | **Total** | **45** | **24** | **38** | **26** | **8** |
33
-
34
- ### Top Offenders (by violation count)
35
-
36
- 1. **`skills-library.ts`** — 7 HIGH (imports `path`, `os`, `fs/promises` and uses throughout)
37
- 2. **`claude-code.ts`** — 8 violations (3x `Bun.spawn`, 1x `Bun.write`, 2x dynamic `fs/promises`, 2x `process.env`)
38
- 3. **`launcher-app-command-listener.ts`** — 7 HIGH (fs, path, os at module top-level)
39
- 4. **`window-manager.ts`** — 7 HIGH (same pattern as launcher-app)
40
- 5. **`python.ts`** — 9+ uses of `existsSync`/`join` from builtins
41
- 6. **`package-finder.ts`** — 5 violations (partially migrated, inconsistent)
42
- 7. **`comfyui/index.ts`** — 5 violations in one method (dynamic imports + `Bun.write`)
43
- 8. **`openai-codex.ts`** — 4 violations (3x `Bun.spawn`, 2x `process.env`)
44
-
45
- ### Bug Found
46
-
47
- **`repl.ts` lines 92, 192** — Uses `fs.readFileSync` and `fs.appendFileSync` but **never imports `fs`**. This will throw `ReferenceError` at runtime when history persistence is used.
48
-
49
- ---
50
-
51
- ## Detailed Findings
52
-
53
- ### Node Features (`src/node/features/`)
54
-
55
- #### `package-finder.ts`
56
-
57
- | Line(s) | Violation | Should Use | Severity |
58
- |---------|-----------|-----------|----------|
59
- | 4 | `import { readdir, readFile } from 'fs/promises'` | `this.container.fs` | HIGH |
60
- | 5 | `import { resolve, join, basename } from 'path'` | `this.container.paths` | MEDIUM |
61
- | 242 | `readFile(path)` direct usage | `this.container.fs.readFileAsync()` | HIGH |
62
- | 471, 477 | `readdir(...)` direct usage | `this.container.fs.readdirAsync()` | HIGH |
63
- | 475, 477 | `join(...)` direct usage | `this.container.paths.join()` | MEDIUM |
64
-
65
- Note: Line 523 correctly uses `this.container.fs.findUpAsync` — file is partially migrated but inconsistent.
66
-
67
- #### `python.ts`
68
-
69
- | Line(s) | Violation | Should Use | Severity |
70
- |---------|-----------|-----------|----------|
71
- | 4 | `import { existsSync } from 'fs'` | `this.container.fs.exists()` | HIGH |
72
- | 5 | `import { join, resolve } from 'path'` | `this.container.paths` | MEDIUM |
73
- | 84 | `resolve(this.options.dir)` | `this.container.paths.resolve()` | MEDIUM |
74
- | 93, 145, 158, 171-172, 177, 245-246, 256, 259 | 9+ calls to `existsSync()` | `this.container.fs.exists()` | HIGH |
75
- | 145, 158, 171+ | `join(...)` throughout `detectEnvironment()` | `this.container.paths.join()` | MEDIUM |
76
-
77
- Note: `execute()` method (line 313+) correctly uses container features — only `detectEnvironment()` and `enable()` are violating.
78
-
79
- #### `launcher-app-command-listener.ts`
80
-
81
- | Line(s) | Violation | Should Use | Severity |
82
- |---------|-----------|-----------|----------|
83
- | 5 | `import { homedir } from 'os'` | `this.container.feature('os').homedir` | MEDIUM |
84
- | 6 | `import { join, dirname } from 'path'` | `this.container.paths` | MEDIUM |
85
- | 7 | `import { existsSync, unlinkSync, mkdirSync } from 'fs'` | `this.container.fs` | HIGH |
86
- | 9-15 | `homedir()`, `join(...)` at module top-level (before container exists) | Must defer to runtime (`enable()` or getter) | HIGH |
87
- | 250-253 | `dirname()`, `existsSync()`, `mkdirSync()` | `this.container.paths`/`this.container.fs` | HIGH |
88
- | 260-263 | `existsSync()`, `unlinkSync()` | `this.container.fs` | HIGH |
89
- | 307-308 | `existsSync()`, `unlinkSync()` | `this.container.fs` | HIGH |
90
-
91
- #### `window-manager.ts`
92
-
93
- | Line(s) | Violation | Should Use | Severity |
94
- |---------|-----------|-----------|----------|
95
- | 5 | `import { homedir } from 'os'` | `this.container.feature('os').homedir` | MEDIUM |
96
- | 6 | `import { join, dirname } from 'path'` | `this.container.paths` | MEDIUM |
97
- | 8 | `import { existsSync, unlinkSync, mkdirSync } from 'fs'` | `this.container.fs` | HIGH |
98
- | 10-16 | `homedir()`, `join(...)` at module top-level | Must defer to runtime | HIGH |
99
- | 354-372 | `dirname()`, `existsSync()`, `mkdirSync()`, `unlinkSync()` | Container equivalents | HIGH |
100
- | 420-421 | `existsSync()`, `unlinkSync()` | `this.container.fs` | HIGH |
101
-
102
- #### `helpers.ts`
103
-
104
- | Line(s) | Violation | Should Use | Severity |
105
- |---------|-----------|-----------|----------|
106
- | 11 | `import { resolve, parse } from 'path'` | `this.container.paths` | MEDIUM |
107
- | 134, 258 | `resolve(this.rootDir, ...)` | `this.container.paths.resolve()` | MEDIUM |
108
- | 324 | `const { Glob } = globalThis.Bun \|\| (await import('bun'))` — unguarded `Bun.Glob` | Guard with `this.container.isBun` or use container glob | HIGH |
109
-
110
- #### `tmux.ts`
111
-
112
- | Line(s) | Violation | Should Use | Severity |
113
- |---------|-----------|-----------|----------|
114
- | 479, 531 | `process.env.TMUX` | Container environment handling | MEDIUM |
115
- | 505-509 | `process.platform === 'darwin'` / `'linux'` | `this.container.feature('os').platform` | LOW |
116
- | 543-544 | `process.argv` direct access | Container equivalent | LOW |
117
- | 546 | `import('child_process')` then `execSync(...)` | `this.container.feature('proc')` | HIGH |
118
-
119
- #### `process-manager.ts`
120
-
121
- | Line(s) | Violation | Should Use | Severity |
122
- |---------|-----------|-----------|----------|
123
- | 104 | `ReturnType<typeof Bun.spawn>` — type depends on Bun | Runtime-agnostic type or guard | HIGH |
124
- | 164 | `Bun.spawn(...)` — unguarded | `this.container.feature('proc')` or guard with `isBun` | HIGH |
125
- | 166 | `{ ...process.env, ...spawnOptions.env }` | Container environment | MEDIUM |
126
- | 508-530 | `process.on('exit')`, `process.on('SIGINT')`, etc. | Container lifecycle hooks | MEDIUM |
127
-
128
- #### `google-auth.ts`
129
-
130
- | Line(s) | Violation | Should Use | Severity |
131
- |---------|-----------|-----------|----------|
132
- | 108, 115, 123, 147, 486 | `process.env.GOOGLE_*` (5 occurrences) | Container env handling (already declares `static envVars`) | MEDIUM |
133
- | 247 | `Bun.serve({...})` — unguarded | Guard with `isBun` or use container server | HIGH |
134
-
135
- #### `repl.ts`
136
-
137
- | Line(s) | Violation | Should Use | Severity |
138
- |---------|-----------|-----------|----------|
139
- | 92 | `fs.readFileSync(...)` — **`fs` is NOT imported** | `this.container.fs.readFileSync()` | **HIGH (BUG)** |
140
- | 172 | `Bun.inspect(result, ...)` — unguarded | Guard with `this.container.isBun` | MEDIUM |
141
- | 192 | `fs.appendFileSync(...)` — **`fs` is NOT imported** | `this.container.fs` | **HIGH (BUG)** |
142
-
143
- #### `tts.ts`
144
-
145
- | Line(s) | Violation | Should Use | Severity |
146
- |---------|-----------|-----------|----------|
147
- | 67 | `process.env.RUNPOD_API_KEY` | Container env handling | MEDIUM |
148
-
149
- Otherwise clean — correctly uses `this.container.paths`, `this.container.fs`, `this.container.feature('os')`.
150
-
151
- #### `downloader.ts`
152
-
153
- | Line(s) | Violation | Should Use | Severity |
154
- |---------|-----------|-----------|----------|
155
- | 3 | `import fetch from 'cross-fetch'` | Global `fetch` (available in Bun and Node 18+) or container REST client | HIGH |
156
-
157
- Otherwise clean — correctly uses `this.container.fs.writeFileAsync` and `this.container.paths.resolve`.
158
-
159
- #### `runpod.ts`
160
-
161
- | Line(s) | Violation | Should Use | Severity |
162
- |---------|-----------|-----------|----------|
163
- | 4 | `import axios from 'axios'` | `this.container.client('rest')` or global `fetch` | HIGH |
164
- | 46 | `process.env.RUNPOD_API_KEY` | Container env handling | MEDIUM |
165
-
166
- #### `telegram.ts`
167
-
168
- | Line(s) | Violation | Should Use | Severity |
169
- |---------|-----------|-----------|----------|
170
- | 97 | `process.env.TELEGRAM_BOT_TOKEN` | Container env handling | MEDIUM |
171
-
172
- Otherwise clean — properly uses `container.server('express')` and `container.feature('ui')`.
173
-
174
- ---
175
-
176
- ### AGI Features (`src/agi/features/`)
177
-
178
- #### `skills-library.ts`
179
-
180
- | Line(s) | Violation | Should Use | Severity |
181
- |---------|-----------|-----------|----------|
182
- | 2 | `import path from 'path'` | `this.container.paths` | HIGH |
183
- | 3 | `import os from 'os'` | `this.container.paths.homedir` or container os feature | HIGH |
184
- | 4 | `import fs from 'fs/promises'` | `this.container.fs` | HIGH |
185
- | 131 | `path.resolve(os.homedir(), '.luca', 'skills')` | `this.container.paths.resolve(...)` | HIGH |
186
- | 250 | `await fs.mkdir(..., { recursive: true })` | `this.container.fs.mkdirp()` or `ensureFolder()` | HIGH |
187
- | 330-331 | `path.resolve(...)` in `remove()` | `this.container.paths.resolve()` | HIGH |
188
- | 335 | `await fs.rm(skillDir, { recursive: true })` | `this.container.fs.rm()` | HIGH |
189
-
190
- Worst AGI offender — three Node builtin imports at top level used throughout.
191
-
192
- #### `claude-code.ts`
193
-
194
- | Line(s) | Violation | Should Use | Severity |
195
- |---------|-----------|-----------|----------|
196
- | 7 | `import type { Subprocess } from 'bun'` | Runtime-agnostic type | MEDIUM |
197
- | 275 | `Bun.spawn([this.claudePath, '--version'], ...)` | Container `proc` feature | HIGH |
198
- | 334 | `const { appendFile } = await import('node:fs/promises')` | `this.container.fs` | HIGH |
199
- | 382 | `process.env.TMPDIR` | Container temp dir handling | MEDIUM |
200
- | 384 | `await Bun.write(tmpPath, ...)` | Container fs write | HIGH |
201
- | 619-624 | `Bun.spawn(...)` + `{ ...process.env }` | Container `proc` + env | HIGH |
202
- | 750-755 | `Bun.spawn(...)` + `{ ...process.env }` | Same | HIGH |
203
- | 920 | `const { unlink } = await import('node:fs/promises')` | `this.container.fs` | HIGH |
204
-
205
- Completely Bun-locked. Three `Bun.spawn` call sites, one `Bun.write`, two dynamic `fs/promises` imports.
206
-
207
- #### `openai-codex.ts`
208
-
209
- | Line(s) | Violation | Should Use | Severity |
210
- |---------|-----------|-----------|----------|
211
- | 7 | `import type { Subprocess } from 'bun'` | Runtime-agnostic type | MEDIUM |
212
- | 174 | `Bun.spawn([this.codexPath, '--version'], ...)` | Container `proc` feature | HIGH |
213
- | 375-379 | `Bun.spawn(...)` + `{ ...process.env }` | Container `proc` + env | HIGH |
214
- | 502-507 | `Bun.spawn(...)` + `{ ...process.env }` | Same | HIGH |
215
-
216
- Same pattern as `claude-code.ts`.
217
-
218
- #### Clean AGI Files
219
-
220
- - `conversation.ts` — Clean
221
- - `conversation-history.ts` — Clean (uses `container.feature('diskCache')`)
222
- - `assistant.ts` — Exemplary (uses `container.fs`, `container.paths`, `container.feature('vm')`)
223
- - `assistants-manager.ts` — Clean (uses `container.paths`, `container.fs`)
224
- - `docs-reader.ts` — Clean
225
- - `openapi.ts` — Clean (uses global `fetch`)
226
- - `heartbeat.ts` — Clean (uses `container.feature('proc')`, `container.feature('vm')`, etc.)
227
-
228
- ---
229
-
230
- ### Clients (`src/clients/`, `src/web/clients/`)
231
-
232
- #### `comfyui/index.ts`
233
-
234
- | Line(s) | Violation | Should Use | Severity |
235
- |---------|-----------|-----------|----------|
236
- | 531 | `const { mkdir } = await import("fs/promises")` | `this.container.fs.ensureFolder()` | HIGH |
237
- | 532 | `const { join } = await import("path")` | `this.container.paths.join()` | MEDIUM |
238
- | 533 | `await mkdir(options.outputDir, { recursive: true })` | `this.container.fs.ensureFolder()` | HIGH |
239
- | 537 | `const localPath = join(...)` | `this.container.paths.join()` | MEDIUM |
240
- | 538 | `await Bun.write(localPath, buf)` — unguarded | `this.container.fs.writeFileAsync()` | HIGH |
241
-
242
- All 5 violations are in the `runWorkflow` method (lines 530-541).
243
-
244
- #### `openai/index.ts`
245
-
246
- | Line(s) | Violation | Should Use | Severity |
247
- |---------|-----------|-----------|----------|
248
- | 76 | `process.env.OPENAI_API_KEY` | Container env (already declares `static envVars`) | MEDIUM |
249
-
250
- #### `elevenlabs/index.ts`
251
-
252
- | Line(s) | Violation | Should Use | Severity |
253
- |---------|-----------|-----------|----------|
254
- | 100 | `process.env.ELEVENLABS_API_KEY` | Container env (already declares `static envVars`) | MEDIUM |
255
-
256
- #### Clean Client Files
257
-
258
- - `civitai/index.ts` — Exemplary (uses `container.fs`, `container.paths`, `container.feature("downloader")`)
259
- - `supabase/index.ts` — Clean
260
- - `client-template.ts` — Clean
261
- - `web/clients/socket.ts` — Clean
262
-
263
- ---
264
-
265
- ### Servers (`src/servers/`)
266
-
267
- #### `express.ts`
268
-
269
- | Line(s) | Violation | Should Use | Severity |
270
- |---------|-----------|-----------|----------|
271
- | 123 | `new Bun.Glob('**/*.ts')` — unguarded | Container glob/fs.walk or guard with `isBun` | HIGH |
272
-
273
- The entire `useEndpoints` method (lines 123-146) depends on `Bun.Glob`.
274
-
275
- #### `mcp.ts`
276
-
277
- | Line(s) | Violation | Should Use | Severity |
278
- |---------|-----------|-----------|----------|
279
- | 440 | `const { randomUUID } = await import('node:crypto')` | `crypto.randomUUID()` (global Web Crypto) or `this.container.utils.uuid()` | MEDIUM |
280
-
281
- #### Clean Server Files
282
-
283
- - `socket.ts` — Clean
284
-
285
- ---
286
-
287
- ### Commands (`src/commands/`)
288
-
289
- #### `prompt.ts`
290
-
291
- | Line(s) | Violation | Should Use | Severity |
292
- |---------|-----------|-----------|----------|
293
- | 250 | `await Bun.write(resolvedPath, updated)` — unguarded | `container.fs.writeFileAsync()` (already destructures `fs` on line 205!) | HIGH |
294
- | 256 | `await Bun.write(outPath, markdown)` — unguarded | `container.fs.writeFileAsync()` | HIGH |
295
- | 85, 88, 118, 147-179 | Extensive `process.stdout.write()` for streaming | Container `ui` feature | MEDIUM |
296
-
297
- Inconsistent — lines 205+ use `container.fs` properly, but lines 250/256 use `Bun.write`.
298
-
299
- #### `chat.ts`
300
-
301
- | Line(s) | Violation | Should Use | Severity |
302
- |---------|-----------|-----------|----------|
303
- | 2 | `import * as readline from 'readline'` | Container `repl` feature or `ui.askQuestion()` | HIGH |
304
- | 94-97 | `readline.createInterface({ input: process.stdin, output: process.stdout })` | Container input abstraction | HIGH |
305
- | 68-69, 76, 81, 86, 90 | `process.stdout.write(...)` | Container `ui` feature | MEDIUM |
306
-
307
- The `console` command demonstrates the correct pattern using `container.feature('repl')`.
308
-
309
- #### `console.ts`
310
-
311
- | Line(s) | Violation | Should Use | Severity |
312
- |---------|-----------|-----------|----------|
313
- | 67 | `Bun` injected into REPL context without guard | Guard with `container.isBun` | MEDIUM |
314
-
315
- #### `sandbox-mcp.ts`
316
-
317
- | Line(s) | Violation | Should Use | Severity |
318
- |---------|-----------|-----------|----------|
319
- | 42 | `Bun` injected into VM context without guard | Guard with `container.isBun` | MEDIUM |
320
-
321
- #### `run.ts`
322
-
323
- | Line(s) | Violation | Should Use | Severity |
324
- |---------|-----------|-----------|----------|
325
- | 218 | `Bun` injected into REPL context without guard | Guard with `container.isBun` | MEDIUM |
326
-
327
- #### Clean Command Files
328
-
329
- - `eval.ts` — Clean
330
- - `describe.ts` — Exemplary
331
- - `help.ts` — Clean
332
- - `index.ts` — Clean (barrel file)
333
- - `serve.ts` — Clean (uses container throughout)
334
- - `mcp.ts` — Clean
335
-
336
- ---
337
-
338
- ## Recurring Patterns
339
-
340
- ### 1. `process.env` for API Keys (MEDIUM, 10+ files)
341
- Many features/clients declare `static envVars = [...]` but then read `process.env.KEY` directly in getters. The container should mediate this. Affected: `google-auth.ts`, `tts.ts`, `runpod.ts`, `telegram.ts`, `openai/index.ts`, `elevenlabs/index.ts`.
342
-
343
- ### 2. Unguarded `Bun.spawn` (HIGH, 5 files)
344
- `claude-code.ts`, `openai-codex.ts`, `process-manager.ts` all call `Bun.spawn` without checking `container.isBun`. These need either proc feature usage or runtime guards.
345
-
346
- ### 3. Unguarded `Bun.write` (HIGH, 3 files)
347
- `prompt.ts`, `claude-code.ts`, `comfyui/index.ts` use `Bun.write` when `container.fs.writeFileAsync()` is available.
348
-
349
- ### 4. Module-level `homedir()`/`join()` (HIGH, 2 files)
350
- `launcher-app-command-listener.ts` and `window-manager.ts` compute paths at import time using `os.homedir()` and `path.join()`, before any container exists. These must be deferred to `enable()` or computed lazily.
351
-
352
- ### 5. Third-party HTTP imports (HIGH, 2 files)
353
- `downloader.ts` imports `cross-fetch` and `runpod.ts` imports `axios` when global `fetch` and `container.client('rest')` are available.
354
-
355
- ### 6. Unguarded `Bun.Glob` (HIGH, 2 files)
356
- `helpers.ts` and `express.ts` use `Bun.Glob` without runtime guards. The container's fs feature provides glob/walk capabilities.
357
-
358
- ---
359
-
360
- ## Recommended Fix Priority
361
-
362
- ### Priority 1 — Bugs
363
- - [ ] `repl.ts` — Fix missing `fs` import (lines 92, 192). Use `this.container.fs` instead.
364
-
365
- ### Priority 2 — Bun-only code (breaks Node compatibility)
366
- - [ ] `claude-code.ts` — Replace `Bun.spawn` with proc feature or add `isBun` guards
367
- - [ ] `openai-codex.ts` — Same pattern as claude-code
368
- - [ ] `process-manager.ts` — Replace `Bun.spawn` with proc feature or guard
369
- - [ ] `google-auth.ts` — Replace `Bun.serve` with guard or container server
370
- - [ ] `express.ts` — Replace `Bun.Glob` with container glob or guard
371
- - [ ] `helpers.ts` — Replace `Bun.Glob` with container glob or guard
372
- - [ ] `prompt.ts` — Replace `Bun.write` with `container.fs.writeFileAsync`
373
- - [ ] `comfyui/index.ts` — Replace `Bun.write` + dynamic imports with container equivalents
374
-
375
- ### Priority 3 — Direct builtin imports (bypasses container)
376
- - [ ] `skills-library.ts` — Replace all `path`, `os`, `fs/promises` with container equivalents
377
- - [ ] `package-finder.ts` — Complete migration to container fs/paths
378
- - [ ] `python.ts` — Replace `existsSync`/`join` with container equivalents
379
- - [ ] `launcher-app-command-listener.ts` — Replace fs/path/os with container, defer module-level computations
380
- - [ ] `window-manager.ts` — Same as launcher-app
381
- - [ ] `downloader.ts` — Remove `cross-fetch`, use global `fetch`
382
- - [ ] `runpod.ts` — Remove `axios`, use global `fetch` or container REST client
383
- - [ ] `chat.ts` — Replace `readline` with container `repl` feature
384
-
385
- ### Priority 4 — `process.env` standardization
386
- - [ ] Create or document a standard pattern for env var access across features/clients
387
- - [ ] Update `google-auth.ts`, `tts.ts`, `runpod.ts`, `telegram.ts`, `openai/index.ts`, `elevenlabs/index.ts`
388
-
389
- ### Priority 5 — Minor guards
390
- - [ ] `console.ts`, `sandbox-mcp.ts`, `run.ts` — Guard `Bun` global injection with `container.isBun`
391
- - [ ] `tmux.ts` — Replace `execSync` dynamic import with `container.feature('proc')`