@soederpop/luca 0.0.32 → 0.0.35

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 (92) hide show
  1. package/README.md +241 -36
  2. package/bun.lock +24 -6
  3. package/commands/build-python-bridge.ts +43 -0
  4. package/docs/README.md +1 -1
  5. package/docs/TABLE-OF-CONTENTS.md +0 -1
  6. package/docs/apis/clients/rest.md +7 -7
  7. package/docs/apis/clients/websocket.md +23 -10
  8. package/docs/apis/features/agi/assistant.md +155 -8
  9. package/docs/apis/features/agi/assistants-manager.md +90 -22
  10. package/docs/apis/features/agi/auto-assistant.md +377 -0
  11. package/docs/apis/features/agi/browser-use.md +802 -0
  12. package/docs/apis/features/agi/claude-code.md +6 -1
  13. package/docs/apis/features/agi/conversation-history.md +7 -6
  14. package/docs/apis/features/agi/conversation.md +111 -38
  15. package/docs/apis/features/agi/docs-reader.md +35 -57
  16. package/docs/apis/features/agi/file-tools.md +163 -0
  17. package/docs/apis/features/agi/openapi.md +2 -2
  18. package/docs/apis/features/agi/skills-library.md +227 -0
  19. package/docs/apis/features/node/content-db.md +125 -4
  20. package/docs/apis/features/node/disk-cache.md +11 -11
  21. package/docs/apis/features/node/downloader.md +1 -1
  22. package/docs/apis/features/node/file-manager.md +15 -15
  23. package/docs/apis/features/node/fs.md +78 -21
  24. package/docs/apis/features/node/git.md +50 -10
  25. package/docs/apis/features/node/google-calendar.md +3 -0
  26. package/docs/apis/features/node/google-docs.md +10 -1
  27. package/docs/apis/features/node/google-drive.md +3 -0
  28. package/docs/apis/features/node/google-mail.md +214 -0
  29. package/docs/apis/features/node/google-sheets.md +3 -0
  30. package/docs/apis/features/node/ink.md +10 -10
  31. package/docs/apis/features/node/ipc-socket.md +83 -93
  32. package/docs/apis/features/node/networking.md +5 -5
  33. package/docs/apis/features/node/os.md +7 -7
  34. package/docs/apis/features/node/package-finder.md +14 -14
  35. package/docs/apis/features/node/proc.md +2 -1
  36. package/docs/apis/features/node/process-manager.md +70 -3
  37. package/docs/apis/features/node/python.md +265 -9
  38. package/docs/apis/features/node/redis.md +380 -0
  39. package/docs/apis/features/node/ui.md +13 -13
  40. package/docs/apis/servers/express.md +35 -7
  41. package/docs/apis/servers/mcp.md +3 -3
  42. package/docs/apis/servers/websocket.md +51 -8
  43. package/docs/bootstrap/CLAUDE.md +1 -1
  44. package/docs/bootstrap/SKILL.md +93 -7
  45. package/docs/examples/feature-as-tool-provider.md +143 -0
  46. package/docs/examples/python.md +42 -1
  47. package/docs/introspection.md +15 -5
  48. package/docs/tutorials/00-bootstrap.md +3 -3
  49. package/docs/tutorials/02-container.md +2 -2
  50. package/docs/tutorials/10-creating-features.md +5 -0
  51. package/docs/tutorials/13-introspection.md +12 -2
  52. package/docs/tutorials/19-python-sessions.md +401 -0
  53. package/package.json +8 -5
  54. package/scripts/examples/using-assistant-with-mcp.ts +2 -7
  55. package/scripts/test-linux-binary.sh +80 -0
  56. package/src/agi/container.server.ts +8 -0
  57. package/src/agi/features/assistant.ts +18 -0
  58. package/src/agi/features/autonomous-assistant.ts +435 -0
  59. package/src/agi/features/conversation.ts +58 -6
  60. package/src/agi/features/file-tools.ts +286 -0
  61. package/src/agi/features/luca-coder.ts +643 -0
  62. package/src/bootstrap/generated.ts +705 -107
  63. package/src/cli/build-info.ts +2 -2
  64. package/src/cli/cli.ts +22 -13
  65. package/src/commands/bootstrap.ts +49 -6
  66. package/src/commands/code.ts +369 -0
  67. package/src/commands/describe.ts +7 -2
  68. package/src/commands/index.ts +1 -0
  69. package/src/commands/sandbox-mcp.ts +7 -7
  70. package/src/commands/save-api-docs.ts +1 -1
  71. package/src/container-describer.ts +4 -4
  72. package/src/container.ts +10 -19
  73. package/src/helper.ts +24 -33
  74. package/src/introspection/generated.agi.ts +3026 -849
  75. package/src/introspection/generated.node.ts +1690 -1012
  76. package/src/introspection/generated.web.ts +15 -57
  77. package/src/node/container.ts +5 -5
  78. package/src/node/features/figlet-fonts.ts +597 -0
  79. package/src/node/features/fs.ts +3 -9
  80. package/src/node/features/helpers.ts +20 -0
  81. package/src/node/features/python.ts +429 -16
  82. package/src/node/features/redis.ts +446 -0
  83. package/src/node/features/ui.ts +4 -11
  84. package/src/python/bridge.py +220 -0
  85. package/src/python/generated.ts +227 -0
  86. package/src/scaffolds/generated.ts +1 -1
  87. package/test/python-session.test.ts +105 -0
  88. package/assistants/lucaExpert/CORE.md +0 -37
  89. package/assistants/lucaExpert/hooks.ts +0 -9
  90. package/assistants/lucaExpert/tools.ts +0 -177
  91. package/docs/examples/port-exposer.md +0 -89
  92. package/src/node/features/port-exposer.ts +0 -351
@@ -1,351 +0,0 @@
1
- import { z } from 'zod'
2
- import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
- import * as ngrok from '@ngrok/ngrok'
4
- import { Feature } from '../../feature.js'
5
-
6
- /**
7
- * Zod schema for the Port Exposer feature state
8
- */
9
- export const PortExposerStateSchema = FeatureStateSchema.extend({
10
- /** Whether ngrok is currently connected */
11
- connected: z.boolean().describe('Whether ngrok is currently connected'),
12
- /** The public URL provided by ngrok */
13
- publicUrl: z.string().optional().describe('The public URL provided by ngrok'),
14
- /** The local port being exposed */
15
- localPort: z.number().optional().describe('The local port being exposed'),
16
- /** Ngrok session information */
17
- sessionInfo: z.object({
18
- authToken: z.string().optional().describe('Ngrok authentication token'),
19
- region: z.string().optional().describe('Ngrok region'),
20
- subdomain: z.string().optional().describe('Ngrok subdomain'),
21
- }).optional().describe('Ngrok session information'),
22
- /** Connection timestamp */
23
- connectedAt: z.coerce.date().optional().describe('Timestamp when the connection was established'),
24
- /** Any error that occurred */
25
- lastError: z.string().optional().describe('Last error message from an ngrok operation'),
26
- })
27
- export type PortExposerState = z.infer<typeof PortExposerStateSchema>
28
-
29
- /**
30
- * Zod schema for Port Exposer feature options
31
- */
32
- export const PortExposerOptionsSchema = FeatureOptionsSchema.extend({
33
- /** Local port to expose */
34
- port: z.number().optional().describe('Local port to expose'),
35
- /** Optional ngrok auth token for premium features */
36
- authToken: z.string().optional().describe('Ngrok auth token for premium features'),
37
- /** Preferred region (us, eu, ap, au, sa, jp, in) */
38
- region: z.string().optional().describe('Preferred ngrok region (us, eu, ap, au, sa, jp, in)'),
39
- /** Custom subdomain (requires paid plan) */
40
- subdomain: z.string().optional().describe('Custom subdomain (requires paid plan)'),
41
- /** Domain to use (requires paid plan) */
42
- domain: z.string().optional().describe('Domain to use (requires paid plan)'),
43
- /** Basic auth for the tunnel */
44
- basicAuth: z.string().optional().describe('Basic auth credentials for the tunnel'),
45
- /** OAuth provider for authentication */
46
- oauth: z.string().optional().describe('OAuth provider for authentication'),
47
- /** Additional ngrok configuration */
48
- config: z.any().describe('Additional ngrok configuration'),
49
- })
50
- export type PortExposerOptions = z.infer<typeof PortExposerOptionsSchema>
51
-
52
- export const PortExposerEventsSchema = FeatureEventsSchema.extend({
53
- exposed: z.tuple([z.object({
54
- publicUrl: z.string().optional().describe('The public ngrok URL'),
55
- localPort: z.number().describe('The local port being exposed'),
56
- }).describe('Exposure details')]).describe('When a local port is successfully exposed via ngrok'),
57
- closed: z.tuple([]).describe('When the ngrok tunnel is closed'),
58
- error: z.tuple([z.any().describe('The error object')]).describe('When an ngrok operation fails'),
59
- }).describe('Port Exposer events')
60
-
61
- /**
62
- * Port Exposer Feature
63
- *
64
- * Exposes local HTTP services via ngrok with SSL-enabled public URLs.
65
- * Perfect for development, testing, and sharing local services securely.
66
- *
67
- * Features:
68
- * - SSL-enabled public URLs for local services
69
- * - Custom subdomains and domains (with paid plans)
70
- * - Authentication options (basic auth, OAuth)
71
- * - Regional endpoint selection
72
- * - Connection state management
73
- *
74
- * @example
75
- * ```typescript
76
- * // Basic usage
77
- * const exposer = container.feature('portExposer', { port: 3000 })
78
- * const url = await exposer.expose()
79
- * console.log(`Service available at: ${url}`)
80
- *
81
- * // With custom subdomain
82
- * const exposer = container.feature('portExposer', {
83
- * port: 8080,
84
- * subdomain: 'my-app',
85
- * authToken: 'your-ngrok-token'
86
- * })
87
- * ```
88
- */
89
- export class PortExposer extends Feature<PortExposerState, PortExposerOptions> {
90
- static override shortcut = 'portExposer' as const
91
- static override stateSchema = PortExposerStateSchema
92
- static override optionsSchema = PortExposerOptionsSchema
93
- static override eventsSchema = PortExposerEventsSchema
94
- static { Feature.register(this, 'portExposer') }
95
-
96
- private ngrokListener?: ngrok.Listener
97
-
98
- override get initialState(): PortExposerState {
99
- return {
100
- ...super.initialState,
101
- connected: false
102
- }
103
- }
104
-
105
- /**
106
- * Expose the local port via ngrok.
107
- *
108
- * Creates an ngrok tunnel to the specified local port and returns
109
- * the SSL-enabled public URL. Emits `exposed` on success or `error` on failure.
110
- *
111
- * @param port - Optional port override; falls back to `options.port`
112
- * @returns Promise resolving to the public URL string
113
- * @throws {Error} When no port is specified in options or parameter
114
- *
115
- * @example
116
- * ```typescript
117
- * const exposer = container.feature('portExposer', { port: 3000 })
118
- * const url = await exposer.expose()
119
- * console.log(`Public URL: ${url}`)
120
- *
121
- * // Override port at call time
122
- * const url2 = await exposer.expose(8080)
123
- * ```
124
- */
125
- async expose(port?: number): Promise<string> {
126
- const targetPort = port || this.options.port
127
-
128
- if (!targetPort) {
129
- throw new Error('Port must be specified either in options or as parameter')
130
- }
131
-
132
- try {
133
- // Set up ngrok configuration
134
- const config: any = {
135
- addr: targetPort,
136
- ...this.options.config
137
- }
138
-
139
- // Add optional configuration
140
- if (this.options.authToken) {
141
- config.authtoken = this.options.authToken
142
- }
143
- if (this.options.region) {
144
- config.region = this.options.region
145
- }
146
- if (this.options.subdomain) {
147
- config.subdomain = this.options.subdomain
148
- }
149
- if (this.options.domain) {
150
- config.domain = this.options.domain
151
- }
152
- if (this.options.basicAuth) {
153
- config.basic_auth = this.options.basicAuth
154
- }
155
- if (this.options.oauth) {
156
- config.oauth = this.options.oauth
157
- }
158
-
159
- // Start ngrok listener
160
- this.ngrokListener = await ngrok.forward(config)
161
- const publicUrl = this.ngrokListener.url() || undefined
162
-
163
- // Update state
164
- this.setState({
165
- connected: true,
166
- publicUrl,
167
- localPort: targetPort,
168
- sessionInfo: {
169
- authToken: this.options.authToken,
170
- region: this.options.region,
171
- subdomain: this.options.subdomain
172
- },
173
- connectedAt: new Date(),
174
- lastError: undefined
175
- })
176
-
177
- this.emit('exposed', { publicUrl, localPort: targetPort })
178
-
179
- return publicUrl!
180
-
181
- } catch (error) {
182
- const errorMessage = error instanceof Error ? error.message : 'Unknown error'
183
-
184
- this.setState({
185
- connected: false,
186
- lastError: errorMessage
187
- })
188
-
189
- this.emit('error', error)
190
- throw error
191
- }
192
- }
193
-
194
- /**
195
- * Stop exposing the port and close the ngrok tunnel.
196
- *
197
- * Tears down the ngrok listener, resets connection state, and emits `closed`.
198
- * Safe to call when no tunnel is active (no-op).
199
- *
200
- * @returns Promise that resolves when the tunnel is fully closed
201
- * @throws {Error} When the ngrok listener fails to close
202
- *
203
- * @example
204
- * ```typescript
205
- * const exposer = container.feature('portExposer', { port: 3000 })
206
- * await exposer.expose()
207
- * // ... later
208
- * await exposer.close()
209
- * console.log(exposer.isConnected()) // false
210
- * ```
211
- */
212
- async close(): Promise<void> {
213
- if (this.ngrokListener) {
214
- try {
215
- await this.ngrokListener.close()
216
- this.ngrokListener = undefined
217
-
218
- this.setState({
219
- connected: false,
220
- publicUrl: undefined,
221
- localPort: undefined,
222
- connectedAt: undefined
223
- })
224
-
225
- this.emit('closed')
226
- } catch (error) {
227
- const errorMessage = error instanceof Error ? error.message : 'Unknown error'
228
- this.setState({ lastError: errorMessage })
229
- this.emit('error', error)
230
- throw error
231
- }
232
- }
233
- }
234
-
235
- /**
236
- * Get the current public URL if connected.
237
- *
238
- * Returns the live URL from the ngrok listener, or `undefined` if no tunnel is active.
239
- *
240
- * @returns The public HTTPS URL string, or undefined when disconnected
241
- *
242
- * @example
243
- * ```typescript
244
- * const exposer = container.feature('portExposer', { port: 3000 })
245
- * await exposer.expose()
246
- * console.log(exposer.getPublicUrl()) // 'https://abc123.ngrok.io'
247
- * ```
248
- */
249
- getPublicUrl(): string | undefined {
250
- return this.ngrokListener?.url() || undefined
251
- }
252
-
253
- /**
254
- * Check if the ngrok tunnel is currently connected.
255
- *
256
- * @returns `true` when an active tunnel exists, `false` otherwise
257
- *
258
- * @example
259
- * ```typescript
260
- * const exposer = container.feature('portExposer', { port: 3000 })
261
- * console.log(exposer.isConnected()) // false
262
- * await exposer.expose()
263
- * console.log(exposer.isConnected()) // true
264
- * ```
265
- */
266
- isConnected(): boolean {
267
- return this.state.get('connected') ?? false
268
- }
269
-
270
- /**
271
- * Get a snapshot of the current connection information.
272
- *
273
- * Returns an object with the tunnel's connected status, public URL,
274
- * local port, connection timestamp, and session metadata.
275
- *
276
- * @returns An object containing `connected`, `publicUrl`, `localPort`, `connectedAt`, and `sessionInfo`
277
- *
278
- * @example
279
- * ```typescript
280
- * const exposer = container.feature('portExposer', { port: 3000 })
281
- * await exposer.expose()
282
- * const info = exposer.getConnectionInfo()
283
- * console.log(info.publicUrl, info.localPort, info.connectedAt)
284
- * ```
285
- */
286
- getConnectionInfo() {
287
- const state = this.state.current
288
- return {
289
- connected: state.connected,
290
- publicUrl: state.publicUrl,
291
- localPort: state.localPort,
292
- connectedAt: state.connectedAt,
293
- sessionInfo: state.sessionInfo
294
- }
295
- }
296
-
297
- /**
298
- * Close the existing tunnel and re-expose with optionally updated options.
299
- *
300
- * Calls `close()` first, merges any new options, then calls `expose()`.
301
- *
302
- * @param newOptions - Optional partial options to merge before reconnecting
303
- * @returns Promise resolving to the new public URL string
304
- *
305
- * @example
306
- * ```typescript
307
- * const exposer = container.feature('portExposer', { port: 3000 })
308
- * await exposer.expose()
309
- * // Switch to a different port
310
- * const newUrl = await exposer.reconnect({ port: 8080 })
311
- * ```
312
- */
313
- async reconnect(newOptions?: Partial<PortExposerOptions>): Promise<string> {
314
- await this.close()
315
-
316
- if (newOptions) {
317
- Object.assign(this.options, newOptions)
318
- }
319
-
320
- return this.expose()
321
- }
322
-
323
- /**
324
- * Disable the feature, ensuring the ngrok tunnel is closed first.
325
- *
326
- * Overrides the base `disable()` to guarantee that the tunnel is
327
- * torn down before the feature is marked as disabled.
328
- *
329
- * @returns This PortExposer instance
330
- *
331
- * @example
332
- * ```typescript
333
- * const exposer = container.feature('portExposer', { port: 3000 })
334
- * await exposer.expose()
335
- * await exposer.disable()
336
- * ```
337
- */
338
- async disable(): Promise<this> {
339
- await this.close()
340
- return this
341
- }
342
- }
343
-
344
- export default PortExposer
345
- // Module augmentation for type safety
346
- declare module '../../feature.js' {
347
- interface AvailableFeatures {
348
- portExposer: typeof PortExposer
349
- }
350
- }
351
-