@soederpop/luca 0.0.22 → 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.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +6 -1
- package/assistants/codingAssistant/hooks.ts +0 -1
- package/assistants/lucaExpert/CORE.md +37 -0
- package/assistants/lucaExpert/hooks.ts +9 -0
- package/assistants/lucaExpert/tools.ts +177 -0
- package/commands/build-bootstrap.ts +41 -1
- package/docs/TABLE-OF-CONTENTS.md +0 -1
- package/docs/apis/clients/rest.md +5 -5
- package/docs/apis/features/agi/assistant.md +1 -1
- package/docs/apis/features/agi/conversation-history.md +6 -7
- package/docs/apis/features/agi/conversation.md +1 -1
- package/docs/apis/features/agi/semantic-search.md +1 -1
- package/docs/bootstrap/CLAUDE.md +1 -1
- package/docs/bootstrap/SKILL.md +7 -3
- package/docs/bootstrap/templates/luca-cli.ts +5 -0
- package/docs/mcp/readme.md +1 -1
- package/docs/prompts/check-for-undocumented-features.md +27 -0
- package/docs/tutorials/00-bootstrap.md +18 -0
- package/package.json +2 -2
- package/scripts/stamp-build.sh +12 -0
- package/scripts/test-docs-reader.ts +10 -0
- package/src/agi/container.server.ts +8 -5
- package/src/agi/features/assistant.ts +208 -55
- package/src/agi/features/assistants-manager.ts +138 -66
- package/src/agi/features/conversation.ts +46 -14
- package/src/agi/features/docs-reader.ts +142 -0
- package/src/agi/features/openapi.ts +1 -1
- package/src/agi/features/skills-library.ts +257 -313
- package/src/bootstrap/generated.ts +8163 -6
- package/src/cli/build-info.ts +4 -0
- package/src/cli/cli.ts +2 -1
- package/src/commands/bootstrap.ts +16 -1
- package/src/commands/eval.ts +6 -1
- package/src/commands/prompt.ts +4 -1
- package/src/commands/sandbox-mcp.ts +17 -7
- package/src/helper.ts +56 -2
- package/src/introspection/generated.agi.ts +2409 -1608
- package/src/introspection/generated.node.ts +902 -594
- package/src/introspection/generated.web.ts +1 -1
- package/src/node/container.ts +1 -1
- package/src/node/features/content-db.ts +251 -13
- package/src/node/features/git.ts +90 -0
- package/src/node/features/grep.ts +1 -1
- package/src/node/features/proc.ts +1 -0
- package/src/node/features/tts.ts +1 -1
- package/src/node/features/vm.ts +48 -0
- package/src/scaffolds/generated.ts +2 -2
- package/assistants/architect/CORE.md +0 -3
- package/assistants/architect/hooks.ts +0 -3
- package/assistants/architect/tools.ts +0 -10
- package/docs/apis/features/agi/skills-library.md +0 -234
- package/docs/reports/assistant-bugs.md +0 -38
- package/docs/reports/attach-pattern-usage.md +0 -18
- package/docs/reports/code-audit-results.md +0 -391
- package/docs/reports/console-hmr-design.md +0 -170
- package/docs/reports/helper-semantic-search.md +0 -72
- package/docs/reports/introspection-audit-tasks.md +0 -378
- package/docs/reports/luca-mcp-improvements.md +0 -128
- 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')`
|