@soederpop/luca 0.0.21 → 0.0.23
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/docs/prompts/check-for-undocumented-features.md +27 -0
- package/luca.cli.ts +14 -1
- package/package.json +1 -1
- package/src/bootstrap/generated.ts +1 -1
- package/src/cli/cli.ts +45 -6
- package/src/commands/prompt.ts +18 -2
- package/src/introspection/generated.agi.ts +1207 -872
- package/src/introspection/generated.node.ts +841 -506
- package/src/introspection/generated.web.ts +1 -1
- package/src/node/container.ts +31 -1
- package/src/node/features/google-auth.ts +1 -0
- package/src/node/features/google-calendar.ts +5 -0
- package/src/node/features/google-docs.ts +8 -1
- package/src/node/features/google-drive.ts +6 -0
- package/src/node/features/google-mail.ts +540 -0
- package/src/node/features/google-sheets.ts +6 -0
- package/src/scaffolds/generated.ts +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
agentOptions:
|
|
3
|
+
permissionMode: bypassPermissions
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Check for undocumented features
|
|
7
|
+
|
|
8
|
+
The luca introspection and luca cli's describe command is powered by the JSDoc comments in the code base, and the values passed to the describe methods in the zod schema. This documentation is what is fed to AI Coding assistants to be able to understand how to use the individual features
|
|
9
|
+
|
|
10
|
+
Please scan the following paths:
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
const fm = await container.feature('fileManager').start()
|
|
14
|
+
const results = fm.match(['src/node/features/*.ts', 'src/agi/features/*.ts', 'src/web/features/*.ts'])
|
|
15
|
+
console.log(results.join("\n"))
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Please ensure every feature has accurate and valid JSDoc documentation for the class definitions, methods, and getters.
|
|
19
|
+
|
|
20
|
+
Validate the output of `bun run src/cli/cli.ts describe whatever` for each item you're working on, that it displays properly, is easy to understand, accurate, in terms of how your comments display there. You may need to run `bun run src/cli/cli.ts introspect` to generate the build time data.
|
|
21
|
+
|
|
22
|
+
You can pass `--platform=web` to see web specific output.
|
|
23
|
+
|
|
24
|
+
## Quality not just Quantity
|
|
25
|
+
|
|
26
|
+
- The presence of documentation isn't sufficient. Is it good documentation? Is it not overly verbose? Does it not explain stuff that doesn't matter? Is it accurate? If there are examples, do they work?
|
|
27
|
+
- The main consumer of `luca describe` will be an LLM so token budget matters. Every word has to be doing work. It should still be nice to look at for human coders too.
|
package/luca.cli.ts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
export async function main(container) {
|
|
1
|
+
export async function main(container: any) {
|
|
2
2
|
container.addContext('luca', container)
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
container.onMissingCommand(handleMissingCommand)
|
|
6
|
+
} catch(error) {
|
|
7
|
+
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async function handleMissingCommand({ words, phrase } : { words: string[], phrase: string }) {
|
|
12
|
+
const { ui } = container
|
|
13
|
+
|
|
14
|
+
ui.print.red('oh shit ' + phrase)
|
|
15
|
+
}
|
|
3
16
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soederpop/luca",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"website": "https://luca.soederpop.com",
|
|
5
5
|
"description": "lightweight universal conversational architecture AKA Le Ultimate Component Architecture AKA Last Universal Common Ancestor, part AI part Human",
|
|
6
6
|
"author": "jon soeder aka the people's champ <jon@soederpop.com>",
|
package/src/cli/cli.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { join } from 'path'
|
|
|
19
19
|
async function main() {
|
|
20
20
|
const profile = process.env.LUCA_PROFILE === '1'
|
|
21
21
|
const t = (label?: string) => {
|
|
22
|
-
if (!profile) return () => {}
|
|
22
|
+
if (!profile) return () => { }
|
|
23
23
|
const start = performance.now()
|
|
24
24
|
return (suffix?: string) => {
|
|
25
25
|
const ms = (performance.now() - start).toFixed(1)
|
|
@@ -59,8 +59,8 @@ async function main() {
|
|
|
59
59
|
const afterUser = new Set(container.commands.available as string[])
|
|
60
60
|
const userCommands = new Set([...afterUser].filter((n) => !builtinCommands.has(n) && !projectCommands.has(n)))
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// Store command sources for help display
|
|
63
|
+
; (container as any)._commandSources = { builtinCommands, projectCommands, userCommands }
|
|
64
64
|
|
|
65
65
|
// Load generated introspection data if present
|
|
66
66
|
done = t('loadProjectIntrospection')
|
|
@@ -82,9 +82,33 @@ async function main() {
|
|
|
82
82
|
await cmd.dispatch()
|
|
83
83
|
} else if (commandName) {
|
|
84
84
|
// not a known command — treat as implicit `run`
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
//
|
|
86
|
+
if (resolveScript(commandName, container)) {
|
|
87
|
+
container.argv._.splice(0, 0, 'run')
|
|
88
|
+
const cmd = container.command('run' as any)
|
|
89
|
+
await cmd.dispatch()
|
|
90
|
+
} else {
|
|
91
|
+
|
|
92
|
+
// @ts-ignore TODO come up with a typesafe way to do this
|
|
93
|
+
if (container.state.get('missingCommandHandler')) {
|
|
94
|
+
// @ts-ignore TODO come up with a typesafe way to do this
|
|
95
|
+
const missingCommandHandler = container.state.get('missingCommandHandler') as any
|
|
96
|
+
|
|
97
|
+
if (typeof missingCommandHandler === 'function') {
|
|
98
|
+
await missingCommandHandler({
|
|
99
|
+
words: container.argv._,
|
|
100
|
+
phrase: container.argv._.join(' ')
|
|
101
|
+
}).catch((err: any) => {
|
|
102
|
+
console.error(`Missing command handler error: ${err.message}`, err)
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
container.argv._.splice(0, 0, 'help')
|
|
107
|
+
const cmd = container.command('help' as any)
|
|
108
|
+
await cmd.dispatch()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
88
112
|
} else {
|
|
89
113
|
container.argv._.splice(0, 0, 'help')
|
|
90
114
|
const cmd = container.command('help' as any)
|
|
@@ -94,6 +118,21 @@ async function main() {
|
|
|
94
118
|
tTotal()
|
|
95
119
|
}
|
|
96
120
|
|
|
121
|
+
function resolveScript(ref: string, container: any) {
|
|
122
|
+
const candidates = [
|
|
123
|
+
ref,
|
|
124
|
+
`${ref}.ts`,
|
|
125
|
+
`${ref}.js`,
|
|
126
|
+
`${ref}.md`,
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
for (const candidate of candidates) {
|
|
130
|
+
const resolved = container.paths.resolve(candidate)
|
|
131
|
+
if (container.fs.exists(resolved)) return resolved
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return null
|
|
135
|
+
}
|
|
97
136
|
|
|
98
137
|
async function loadCliModule() {
|
|
99
138
|
const modulePath = container.paths.resolve('luca.cli.ts')
|
package/src/commands/prompt.ts
CHANGED
|
@@ -12,7 +12,7 @@ declare module '../command.js' {
|
|
|
12
12
|
|
|
13
13
|
export const argsSchema = CommandOptionsSchema.extend({
|
|
14
14
|
model: z.string().optional().describe('Override the LLM model (assistant mode only)'),
|
|
15
|
-
'preserve-frontmatter': z.boolean().default(false).describe('Keep YAML frontmatter in the prompt instead of stripping it'),
|
|
15
|
+
'preserve-frontmatter': z.boolean().default(false).describe('Keep YAML frontmatter in the prompt instead of stripping it before sending to the agent.'),
|
|
16
16
|
'permission-mode': z.enum(['default', 'acceptEdits', 'bypassPermissions', 'plan']).default('acceptEdits').describe('Permission mode for CLI agents (default: acceptEdits)'),
|
|
17
17
|
'in-folder': z.string().optional().describe('Run the CLI agent in this directory (resolved via container.paths)'),
|
|
18
18
|
'out-file': z.string().optional().describe('Save session output as a markdown file'),
|
|
@@ -22,8 +22,16 @@ export const argsSchema = CommandOptionsSchema.extend({
|
|
|
22
22
|
'exclude-sections': z.string().optional().describe('Comma-separated list of section headings to exclude from the prompt'),
|
|
23
23
|
'chrome': z.boolean().default(false).describe('Launch Claude Code with a Chrome browser tool'),
|
|
24
24
|
'dry-run': z.boolean().default(false).describe('Display the resolved prompt and options without running the assistant'),
|
|
25
|
+
'local': z.boolean().default(false).describe('Use local models for assistant mode'),
|
|
25
26
|
})
|
|
26
27
|
|
|
28
|
+
function normalizeTarget(raw: string): string {
|
|
29
|
+
const lower = raw.toLowerCase().replace(/[-_]/g, '')
|
|
30
|
+
if (/claude/.test(lower)) return 'claude'
|
|
31
|
+
if (/codex/.test(lower) || /openai/.test(lower)) return 'codex'
|
|
32
|
+
return raw
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
const CLI_TARGETS = new Set(['claude', 'codex'])
|
|
28
36
|
|
|
29
37
|
function formatSessionMarkdown(events: any[], includeOutput: boolean): string {
|
|
@@ -163,6 +171,7 @@ async function runAssistant(name: string, promptContent: string, options: z.infe
|
|
|
163
171
|
const createOptions: Record<string, any> = { ...agentOptions }
|
|
164
172
|
// CLI flags override agentOptions from frontmatter
|
|
165
173
|
if (options.model) createOptions.model = options.model
|
|
174
|
+
if (options.local) createOptions.local = true
|
|
166
175
|
|
|
167
176
|
const assistant = manager.create(name, createOptions)
|
|
168
177
|
let isFirstChunk = true
|
|
@@ -360,6 +369,7 @@ async function runParallel(
|
|
|
360
369
|
const assistants = prepared.map((p, i) => {
|
|
361
370
|
const createOptions: Record<string, any> = { ...p.agentOptions }
|
|
362
371
|
if (options.model) createOptions.model = options.model
|
|
372
|
+
if (options.local) createOptions.local = true
|
|
363
373
|
const assistant = manager.create(target, createOptions)
|
|
364
374
|
|
|
365
375
|
assistant.on('chunk', (text: string) => {
|
|
@@ -827,10 +837,16 @@ export default async function prompt(options: z.infer<typeof argsSchema>, contex
|
|
|
827
837
|
const candidate = paths.resolve(target)
|
|
828
838
|
if (fs.exists(candidate)) {
|
|
829
839
|
allPaths.push(target)
|
|
830
|
-
|
|
840
|
+
// this gives a way for you to say on a per project basis what you want the default coding assistant to be for the prompt command
|
|
841
|
+
// TODO need to document this somewhere
|
|
842
|
+
const { codingAssistant } = (container.manifest.luca || {})
|
|
843
|
+
target = codingAssistant || 'claude'
|
|
831
844
|
}
|
|
832
845
|
}
|
|
833
846
|
|
|
847
|
+
// Normalize target aliases (e.g. claude-code → claude, openai-codex → codex)
|
|
848
|
+
if (target) target = normalizeTarget(target)
|
|
849
|
+
|
|
834
850
|
if (!target || allPaths.length === 0) {
|
|
835
851
|
console.error('Usage: luca prompt [claude|codex|assistant-name] <path/to/prompt.md> [more paths...]')
|
|
836
852
|
process.exit(1)
|