thinkwell 0.5.5 → 0.5.6

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 (44) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +207 -279
  3. package/dist/agent.js.map +1 -1
  4. package/dist/build.js +44 -98
  5. package/dist/cli/build.js +92 -227
  6. package/dist/cli/bundle.js +570 -1136
  7. package/dist/cli/check.js +125 -214
  8. package/dist/cli/commands.js +63 -177
  9. package/dist/cli/compiler-host.js +81 -190
  10. package/dist/cli/dependency-check.js +125 -269
  11. package/dist/cli/dependency-errors.js +12 -84
  12. package/dist/cli/fmt.js +1 -13
  13. package/dist/cli/init-command.js +21 -68
  14. package/dist/cli/init.js +90 -220
  15. package/dist/cli/loader.js +95 -361
  16. package/dist/cli/new-command.js +25 -73
  17. package/dist/cli/package-manager.js +50 -117
  18. package/dist/cli/schema.js +89 -245
  19. package/dist/cli/workspace.js +92 -226
  20. package/dist/connectors/index.js +1 -7
  21. package/dist/generated/features.d.ts +5 -0
  22. package/dist/generated/features.d.ts.map +1 -0
  23. package/dist/generated/features.js +4 -0
  24. package/dist/generated/features.js.map +1 -0
  25. package/dist/index.js +0 -5
  26. package/dist/schema.js +3 -36
  27. package/dist/session.js +50 -82
  28. package/dist/think-builder.d.ts.map +1 -1
  29. package/dist/think-builder.js +269 -370
  30. package/dist/think-builder.js.map +1 -1
  31. package/dist/thought-event.d.ts +1 -0
  32. package/dist/thought-event.d.ts.map +1 -1
  33. package/dist/thought-event.js +0 -1
  34. package/dist/thought-stream.js +60 -96
  35. package/dist-pkg/acp.cjs +13385 -1876
  36. package/dist-pkg/cli-build.cjs +171 -369
  37. package/dist-pkg/cli-bundle.cjs +289 -690
  38. package/dist-pkg/cli-check.cjs +202 -415
  39. package/dist-pkg/cli-dependency-check.cjs +39 -82
  40. package/dist-pkg/cli-dependency-errors.cjs +9 -41
  41. package/dist-pkg/cli-loader.cjs +90 -173
  42. package/dist-pkg/protocol.cjs +2 -8
  43. package/dist-pkg/thinkwell.cjs +876 -1842
  44. package/package.json +7 -6
@@ -1,395 +1,129 @@
1
- /**
2
- * Custom script loader for the compiled binary.
3
- *
4
- * This module provides the runtime infrastructure for loading and executing
5
- * user scripts in the compiled binary. It handles:
6
- *
7
- * 1. **Module Resolution**: Routes imports to the appropriate source:
8
- * - thinkwell packages → bundled packages via `global.__bundled__`
9
- * - External packages → user's node_modules via `require.resolve()`
10
- *
11
- * 2. **Import Transformation**: Rewrites user script imports before execution:
12
- * - `import { Agent } from "thinkwell"` → bundled thinkwell
13
- *
14
- * 3. **@JSONSchema Processing**: Generates JSON schemas for marked types and
15
- * injects namespace declarations with SchemaProvider implementations.
16
- *
17
- * 4. **Script Loading**: Uses Node's require() with temp files for transformed scripts
18
- *
19
- * Unlike the Bun plugin which runs at bundle time, this loader operates at
20
- * runtime when the user script is executed.
21
- */
22
1
  import { readFileSync, writeFileSync, rmSync, existsSync } from "node:fs";
23
2
  import { dirname, join, isAbsolute, resolve, basename } from "node:path";
24
3
  import { randomBytes } from "node:crypto";
25
4
  import { createRequire } from "node:module";
26
5
  import { hasJsonSchemaMarkers, transformJsonSchemas } from "./schema.js";
27
- /**
28
- * Package names that should be resolved from bundled modules.
29
- */
30
6
  const BUNDLED_PACKAGES = ["thinkwell", "@thinkwell/acp", "@thinkwell/protocol"];
31
- /**
32
- * Initialize the bundled module registry.
33
- *
34
- * This should be called from main.cjs with the bundled package exports.
35
- * The registry is used by createCustomRequire to route thinkwell imports.
36
- *
37
- * @param modules - Map of package names to their exports
38
- */
39
7
  export function initializeBundledRegistry(modules) {
40
- global.__bundled__ = modules;
8
+ global.__bundled__ = modules;
41
9
  }
42
- /**
43
- * When set, thinkwell imports resolve from the project's node_modules
44
- * instead of the bundled modules in global.__bundled__.
45
- *
46
- * Contains the project root directory path (for resolving project-local
47
- * dependencies like ts-json-schema-generator), or undefined in zero-config mode.
48
- *
49
- * Set by main.cjs when a project has an explicit thinkwell dependency
50
- * in its package.json (i.e., it's not using the zero-config binary mode).
51
- */
52
- let __projectDir = undefined;
53
- /**
54
- * Enable explicit config mode.
55
- *
56
- * When called with a project directory, the loader skips bundled module lookups
57
- * and virtual import transforms, allowing thinkwell packages to resolve from
58
- * node_modules. The project directory is also used to resolve project-local
59
- * ts-json-schema-generator for @JSONSchema processing.
60
- */
10
+ let __projectDir;
61
11
  export function setExplicitConfig(projectDir) {
62
- __projectDir = projectDir;
12
+ __projectDir = projectDir;
63
13
  }
64
- /**
65
- * Check if a module name refers to a bundled package.
66
- */
67
14
  function isBundledPackage(moduleName) {
68
- return BUNDLED_PACKAGES.includes(moduleName);
15
+ return BUNDLED_PACKAGES.includes(moduleName);
69
16
  }
70
- /**
71
- * Strip shebang line from source if present.
72
- *
73
- * Shebangs are valid for executable scripts but not valid JS/TS syntax.
74
- * We need to strip them before Module._compile processes the source.
75
- *
76
- * @param source - The script source code
77
- * @returns Tuple of [shebang line or empty string, rest of source]
78
- */
79
17
  export function extractShebang(source) {
80
- if (source.startsWith("#!")) {
81
- const newlineIndex = source.indexOf("\n");
82
- if (newlineIndex !== -1) {
83
- return [source.slice(0, newlineIndex + 1), source.slice(newlineIndex + 1)];
84
- }
85
- return [source, ""];
86
- }
87
- return ["", source];
18
+ if (source.startsWith("#!")) {
19
+ const newlineIndex = source.indexOf(`
20
+ `);
21
+ return newlineIndex !== -1 ? [source.slice(0, newlineIndex + 1), source.slice(newlineIndex + 1)] : [source, ""];
22
+ }
23
+ return ["", source];
88
24
  }
89
- /**
90
- * Transform imports to use the bundled module registry.
91
- *
92
- * In the compiled binary, we can't rely on Node's normal module resolution
93
- * for bundled packages (they're in the /snapshot/ virtual filesystem).
94
- * This transform rewrites imports to use global.__bundled__ directly.
95
- *
96
- * @example
97
- * ```typescript
98
- * // Input:
99
- * import { Agent } from "thinkwell";
100
- *
101
- * // Output:
102
- * const { Agent } = global.__bundled__["thinkwell"];
103
- * ```
104
- *
105
- * @param source - The script source code
106
- * @returns The source with bundled package imports transformed
107
- */
108
25
  export function transformVirtualImports(source) {
109
- // Match named imports from thinkwell packages
110
- // Pattern: import { x, y } from "thinkwell" or import { x } from "@thinkwell/acp"
111
- const importPattern = /import\s+\{([^}]+)\}\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]/g;
112
- source = source.replace(importPattern, (_, imports, packageName) => {
113
- const cleanImports = imports.trim();
114
- return `const {${cleanImports}} = global.__bundled__["${packageName}"]`;
115
- });
116
- // Match default imports from thinkwell packages
117
- // Pattern: import Foo from "thinkwell" or import Foo from "@thinkwell/acp"
118
- const defaultImportPattern = /import\s+(\w+)\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]/g;
119
- source = source.replace(defaultImportPattern, (_, importName, packageName) => {
120
- return `const ${importName} = global.__bundled__["${packageName}"].default || global.__bundled__["${packageName}"]`;
121
- });
122
- // Match namespace imports from thinkwell packages
123
- // Pattern: import * as Foo from "thinkwell"
124
- const namespaceImportPattern = /import\s+\*\s+as\s+(\w+)\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]/g;
125
- source = source.replace(namespaceImportPattern, (_, importName, packageName) => {
126
- return `const ${importName} = global.__bundled__["${packageName}"]`;
127
- });
128
- // Match type-only imports (remove them - they're only for TypeScript)
129
- // Pattern: import type { Foo } from "thinkwell"
130
- const typeImportPattern = /import\s+type\s+\{[^}]+\}\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]\s*;?/g;
131
- source = source.replace(typeImportPattern, "");
132
- return source;
26
+ const importPattern = /import\s+\{([^}]+)\}\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]/g;
27
+ source = source.replace(importPattern, (_, imports, packageName) => `const {${imports.trim()}} = global.__bundled__["${packageName}"]`);
28
+ const defaultImportPattern = /import\s+(\w+)\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]/g;
29
+ source = source.replace(defaultImportPattern, (_, importName, packageName) => `const ${importName} = global.__bundled__["${packageName}"].default || global.__bundled__["${packageName}"]`);
30
+ const namespaceImportPattern = /import\s+\*\s+as\s+(\w+)\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]/g;
31
+ source = source.replace(namespaceImportPattern, (_, importName, packageName) => `const ${importName} = global.__bundled__["${packageName}"]`);
32
+ const typeImportPattern = /import\s+type\s+\{[^}]+\}\s+from\s+['"](@thinkwell\/(?:acp|protocol)|thinkwell)['"]\s*;?/g;
33
+ return source = source.replace(typeImportPattern, ""), source;
133
34
  }
134
- /**
135
- * Create a custom require function that routes imports appropriately.
136
- *
137
- * This function creates a require implementation that:
138
- * 1. Checks bundled modules first (thinkwell packages)
139
- * 2. Falls back to require.resolve from the script's directory
140
- * 3. Falls back to global require for built-in modules
141
- *
142
- * @param scriptPath - Absolute path to the user script
143
- * @returns A require function bound to the script's directory
144
- */
145
35
  export function createCustomRequire(scriptPath) {
146
- const scriptDir = dirname(scriptPath);
147
- const nodeModulesPath = join(scriptDir, "node_modules");
148
- // Create a base require function using Node's createRequire
149
- const baseRequire = createRequire(scriptPath);
150
- function customRequire(moduleName) {
151
- // In zero-config mode, resolve thinkwell packages from bundled modules
152
- if (!__projectDir && global.__bundled__ && isBundledPackage(moduleName)) {
153
- const bundled = global.__bundled__[moduleName];
154
- if (bundled) {
155
- return bundled;
156
- }
157
- }
158
- // Try to resolve from the script's directory using baseRequire
159
- try {
160
- const resolved = baseRequire.resolve(moduleName, {
161
- paths: [scriptDir, nodeModulesPath],
162
- });
163
- return baseRequire(resolved);
164
- }
165
- catch {
166
- // Fall back to the base require without custom paths
167
- return baseRequire(moduleName);
168
- }
36
+ const scriptDir = dirname(scriptPath), nodeModulesPath = join(scriptDir, "node_modules"), baseRequire = createRequire(scriptPath);
37
+ function customRequire(moduleName) {
38
+ if (!__projectDir && global.__bundled__ && isBundledPackage(moduleName)) {
39
+ const bundled = global.__bundled__[moduleName];
40
+ if (bundled)
41
+ return bundled;
169
42
  }
170
- // Copy over require properties that modules might depend on
171
- customRequire.resolve = ((id, options) => {
172
- // In zero-config mode, resolve thinkwell packages from bundled modules
173
- if (!__projectDir && global.__bundled__ && isBundledPackage(id)) {
174
- // Return a fake path for bundled modules
175
- return `/__bundled__/${id}`;
176
- }
177
- // Try script directory paths first
178
- const paths = options?.paths ?? [scriptDir, nodeModulesPath];
179
- try {
180
- return baseRequire.resolve(id, { paths });
181
- }
182
- catch {
183
- return baseRequire.resolve(id, options);
184
- }
185
- });
186
- // Stub paths property
187
- customRequire.resolve.paths = baseRequire.resolve.paths;
188
- customRequire.cache = baseRequire.cache;
189
- customRequire.extensions = baseRequire.extensions;
190
- customRequire.main = baseRequire.main;
191
- return customRequire;
192
- }
193
- /**
194
- * Check if source code needs transformation.
195
- *
196
- * In zero-config mode, thinkwell imports require transformation to use
197
- * global.__bundled__. In explicit-config mode, thinkwell imports are left
198
- * as-is (they resolve from node_modules), so they don't trigger transformation.
199
- *
200
- * @JSONSchema markers always require transformation regardless of mode.
201
- *
202
- * @param source - The script source code
203
- * @returns true if the source needs transformation before loading
204
- */
205
- function needsTransformation(source) {
206
- // Check for @JSONSchema markers (always needs transformation)
207
- if (hasJsonSchemaMarkers(source)) {
208
- return true;
43
+ try {
44
+ const resolved = baseRequire.resolve(moduleName, {
45
+ paths: [scriptDir, nodeModulesPath]
46
+ });
47
+ return baseRequire(resolved);
48
+ } catch {
49
+ return baseRequire(moduleName);
209
50
  }
210
- // In zero-config mode, thinkwell imports need rewriting to global.__bundled__
211
- if (!__projectDir && /from\s+['"](?:thinkwell|@thinkwell\/(?:acp|protocol))['"]/.test(source)) {
212
- return true;
51
+ }
52
+ return customRequire.resolve = ((id, options) => {
53
+ if (!__projectDir && global.__bundled__ && isBundledPackage(id))
54
+ return `/__bundled__/${id}`;
55
+ const paths = options?.paths ?? [scriptDir, nodeModulesPath];
56
+ try {
57
+ return baseRequire.resolve(id, { paths });
58
+ } catch {
59
+ return baseRequire.resolve(id, options);
213
60
  }
214
- return false;
61
+ }), customRequire.resolve.paths = baseRequire.resolve.paths, customRequire.cache = baseRequire.cache, customRequire.extensions = baseRequire.extensions, customRequire.main = baseRequire.main, customRequire;
62
+ }
63
+ function needsTransformation(source) {
64
+ return !!(hasJsonSchemaMarkers(source) || !__projectDir && /from\s+['"](?:thinkwell|@thinkwell\/(?:acp|protocol))['"]/.test(source));
215
65
  }
216
- /**
217
- * Generate a short random ID for temp file names.
218
- */
219
66
  function randomId() {
220
- return randomBytes(6).toString("base64url");
67
+ return randomBytes(6).toString("base64url");
221
68
  }
222
- /**
223
- * Rewrite .js extensions to .ts in relative import specifiers when the .ts file exists.
224
- *
225
- * TypeScript convention allows importing `./foo.js` even when the source file is
226
- * `./foo.ts` (since tsc compiles .ts to .js). Node's --experimental-transform-types
227
- * does not perform this remapping, so we do it here to support the common convention.
228
- *
229
- * @param originalPath - Absolute path to the original script (used to resolve relative paths)
230
- * @param source - The script source code
231
- * @returns The source with .js extensions rewritten to .ts where the .ts file exists
232
- */
233
69
  export function rewriteJsToTsExtensions(originalPath, source) {
234
- const scriptDir = dirname(originalPath);
235
- // Match static imports/re-exports: from "./foo.js" or from '../bar.js'
236
- source = source.replace(/(from\s+['"])(\.\.?\/[^'"]*?)\.js(['"])/g, (match, prefix, specifierBase, suffix) => {
237
- const tsPath = resolve(scriptDir, `${specifierBase}.ts`);
238
- if (existsSync(tsPath)) {
239
- return `${prefix}${specifierBase}.ts${suffix}`;
240
- }
241
- return match;
242
- });
243
- // Match dynamic imports: import("./foo.js") or import('../bar.js')
244
- source = source.replace(/(import\s*\(\s*['"])(\.\.?\/[^'"]*?)\.js(['"]\s*\))/g, (match, prefix, specifierBase, suffix) => {
245
- const tsPath = resolve(scriptDir, `${specifierBase}.ts`);
246
- if (existsSync(tsPath)) {
247
- return `${prefix}${specifierBase}.ts${suffix}`;
248
- }
249
- return match;
250
- });
251
- return source;
70
+ const scriptDir = dirname(originalPath);
71
+ return source = source.replace(/(from\s+['"])(\.\.?\/[^'"]*?)\.js(['"])/g, (match, prefix, specifierBase, suffix) => {
72
+ const tsPath = resolve(scriptDir, `${specifierBase}.ts`);
73
+ return existsSync(tsPath) ? `${prefix}${specifierBase}.ts${suffix}` : match;
74
+ }), source = source.replace(/(import\s*\(\s*['"])(\.\.?\/[^'"]*?)\.js(['"]\s*\))/g, (match, prefix, specifierBase, suffix) => {
75
+ const tsPath = resolve(scriptDir, `${specifierBase}.ts`);
76
+ return existsSync(tsPath) ? `${prefix}${specifierBase}.ts${suffix}` : match;
77
+ }), source;
252
78
  }
253
- /**
254
- * Generate a preamble that patches import.meta properties to point to the original script.
255
- *
256
- * When we transform a script and write it to a temp file, import.meta.url, dirname,
257
- * and filename would point to the temp file instead of the original. This breaks
258
- * scripts that use these properties to locate sibling files.
259
- *
260
- * We patch import.meta by redefining these properties to return values based on
261
- * the original script's location.
262
- *
263
- * @param originalPath - Absolute path to the original script
264
- * @returns JavaScript code to prepend to the transformed script
265
- */
266
79
  function generateImportMetaPatch(originalPath) {
267
- // Convert to file:// URL format
268
- const fileUrl = `file://${originalPath}`;
269
- // Get dirname and filename from the path
270
- const originalDir = dirname(originalPath);
271
- const originalFilename = originalPath;
272
- // Escape backslashes and quotes for string literals
273
- const escape = (s) => s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
274
- return [
275
- `Object.defineProperty(import.meta, 'url', { value: '${escape(fileUrl)}', writable: false, configurable: true });`,
276
- `Object.defineProperty(import.meta, 'dirname', { value: '${escape(originalDir)}', writable: false, configurable: true });`,
277
- `Object.defineProperty(import.meta, 'filename', { value: '${escape(originalFilename)}', writable: false, configurable: true });`,
278
- "",
279
- ].join("\n");
80
+ const fileUrl = `file://${originalPath}`, originalDir = dirname(originalPath), originalFilename = originalPath, escape = (s) => s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
81
+ return [
82
+ `Object.defineProperty(import.meta, 'url', { value: '${escape(fileUrl)}', writable: false, configurable: true });`,
83
+ `Object.defineProperty(import.meta, 'dirname', { value: '${escape(originalDir)}', writable: false, configurable: true });`,
84
+ `Object.defineProperty(import.meta, 'filename', { value: '${escape(originalFilename)}', writable: false, configurable: true });`,
85
+ ""
86
+ ].join(`
87
+ `);
280
88
  }
281
- /**
282
- * Load and execute a user script with custom module resolution.
283
- *
284
- * This function handles two loading strategies:
285
- *
286
- * 1. **Direct require()** - For scripts that don't use thinkwell imports.
287
- * This leverages Node's --experimental-strip-types for TypeScript support.
288
- *
289
- * 2. **Transform and compile** - For scripts that use thinkwell:* imports
290
- * or import from bundled packages. The script is transformed and written
291
- * to a temp file, then required (which applies type stripping).
292
- *
293
- * @param scriptPath - Absolute path to the script to load
294
- * @returns The module exports from the script
295
- * @throws Error if the script cannot be loaded or executed
296
- */
297
89
  export function loadScript(scriptPath) {
298
- // Ensure absolute path
299
- const absolutePath = isAbsolute(scriptPath)
300
- ? scriptPath
301
- : resolve(process.cwd(), scriptPath);
302
- // Read the script source to check if transformation is needed
303
- const rawSource = readFileSync(absolutePath, "utf-8");
304
- // Strip shebang for analysis (shebang is stripped by Node's loader anyway)
305
- const [, sourceWithoutShebang] = extractShebang(rawSource);
306
- // Check if source needs our transformation
307
- if (!needsTransformation(sourceWithoutShebang)) {
308
- // No transformation needed - use direct require()
309
- // This preserves Node's type stripping for TypeScript files
310
- const baseRequire = createRequire(absolutePath);
311
- return baseRequire(absolutePath);
312
- }
313
- // Source needs transformation - apply transforms and use a temp file
314
- // Process @JSONSchema types (must happen before import transformation
315
- // because it adds an import statement that also needs transformation)
316
- let source = transformJsonSchemas(absolutePath, sourceWithoutShebang, __projectDir);
317
- // In zero-config mode, rewrite thinkwell imports to use global.__bundled__.
318
- // In explicit-config mode, leave imports as-is so they resolve from node_modules.
319
- if (!__projectDir) {
320
- source = transformVirtualImports(source);
321
- }
322
- // Rewrite .js → .ts in relative imports for TypeScript convention compatibility
323
- source = rewriteJsToTsExtensions(absolutePath, source);
324
- // Prepend import.meta.url patch so scripts can locate sibling files
325
- source = generateImportMetaPatch(absolutePath) + source;
326
- // Write transformed source as a sibling of the original script so that
327
- // relative imports resolve correctly through Node's module loader.
328
- const ext = absolutePath.endsWith(".ts") ? ".ts" : ".js";
329
- const scriptDir = dirname(absolutePath);
330
- const tempFile = join(scriptDir, `.thinkwell-${basename(absolutePath, ext)}-${randomId()}${ext}`);
90
+ const absolutePath = isAbsolute(scriptPath) ? scriptPath : resolve(process.cwd(), scriptPath), rawSource = readFileSync(absolutePath, "utf-8"), [, sourceWithoutShebang] = extractShebang(rawSource);
91
+ if (!needsTransformation(sourceWithoutShebang))
92
+ return createRequire(absolutePath)(absolutePath);
93
+ let source = transformJsonSchemas(absolutePath, sourceWithoutShebang, __projectDir);
94
+ __projectDir || (source = transformVirtualImports(source)), source = rewriteJsToTsExtensions(absolutePath, source), source = generateImportMetaPatch(absolutePath) + source;
95
+ const ext = absolutePath.endsWith(".ts") ? ".ts" : ".js", scriptDir = dirname(absolutePath), tempFile = join(scriptDir, `.thinkwell-${basename(absolutePath, ext)}-${randomId()}${ext}`);
96
+ try {
97
+ return writeFileSync(tempFile, source, "utf-8"), createRequire(absolutePath)(tempFile);
98
+ } finally {
331
99
  try {
332
- // Write transformed source
333
- writeFileSync(tempFile, source, "utf-8");
334
- // Require the transformed file - this uses Node's type stripping
335
- const baseRequire = createRequire(absolutePath);
336
- const result = baseRequire(tempFile);
337
- return result;
338
- }
339
- finally {
340
- // Clean up temp file
341
- try {
342
- rmSync(tempFile);
343
- }
344
- catch {
345
- // Ignore cleanup errors
346
- }
100
+ rmSync(tempFile);
101
+ } catch {
347
102
  }
103
+ }
348
104
  }
349
- /**
350
- * Load and execute a user script, handling both sync and async exports.
351
- *
352
- * After loading, this function checks if the script exports a main function
353
- * or default export and executes it if present.
354
- *
355
- * @param scriptPath - Absolute path to the script to load
356
- * @param args - Additional arguments to pass to the script's argv
357
- * @returns Promise that resolves when script execution completes
358
- */
359
105
  export async function runScript(scriptPath, args = []) {
360
- // Set up process.argv for the script
361
- const originalArgv = process.argv;
362
- process.argv = [process.execPath, scriptPath, ...args];
363
- try {
364
- const exports = loadScript(scriptPath);
365
- // Check for common entry point patterns
366
- if (exports && typeof exports === "object") {
367
- const mod = exports;
368
- // Pattern 1: default export function
369
- if (typeof mod.default === "function") {
370
- await mod.default();
371
- return;
372
- }
373
- // Pattern 2: main function
374
- if (typeof mod.main === "function") {
375
- await mod.main();
376
- return;
377
- }
378
- // Pattern 3: run function
379
- if (typeof mod.run === "function") {
380
- await mod.run();
381
- return;
382
- }
383
- }
384
- // Pattern 4: direct function export
385
- if (typeof exports === "function") {
386
- await exports();
387
- }
388
- // Otherwise, the script executed its code at module level
389
- }
390
- finally {
391
- // Restore original argv
392
- process.argv = originalArgv;
106
+ const originalArgv = process.argv;
107
+ process.argv = [process.execPath, scriptPath, ...args];
108
+ try {
109
+ const exports = loadScript(scriptPath);
110
+ if (exports && typeof exports == "object") {
111
+ const mod = exports;
112
+ if (typeof mod.default == "function") {
113
+ await mod.default();
114
+ return;
115
+ }
116
+ if (typeof mod.main == "function") {
117
+ await mod.main();
118
+ return;
119
+ }
120
+ if (typeof mod.run == "function") {
121
+ await mod.run();
122
+ return;
123
+ }
393
124
  }
125
+ typeof exports == "function" && await exports();
126
+ } finally {
127
+ process.argv = originalArgv;
128
+ }
394
129
  }
395
- //# sourceMappingURL=loader.js.map
@@ -1,12 +1,3 @@
1
- /**
2
- * CLI command for creating a new thinkwell project in a new directory.
3
- *
4
- * This command scaffolds a new project with the necessary configuration
5
- * and example files.
6
- *
7
- * Following Cargo's design: "new" creates a new directory, while "init"
8
- * modifies existing state in the current directory.
9
- */
10
1
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
11
2
  import { join, resolve } from "node:path";
12
3
  import { cyan, cyanBold, greenBold, whiteBold, dim, redBold } from "./fmt.js";
@@ -22,8 +13,7 @@ const PACKAGE_JSON_TEMPLATE = (name) => `{
22
13
  "thinkwell": "^0.2.0"
23
14
  }
24
15
  }
25
- `;
26
- const MAIN_TS_TEMPLATE = `import { open } from "thinkwell";
16
+ `, MAIN_TS_TEMPLATE = `import { open } from "thinkwell";
27
17
 
28
18
  /**
29
19
  * A greeting response from the agent.
@@ -46,8 +36,7 @@ async function main() {
46
36
  }
47
37
 
48
38
  main().catch(console.error);
49
- `;
50
- const TSCONFIG_TEMPLATE = `{
39
+ `, TSCONFIG_TEMPLATE = `{
51
40
  "compilerOptions": {
52
41
  "target": "ES2022",
53
42
  "module": "NodeNext",
@@ -60,30 +49,20 @@ const TSCONFIG_TEMPLATE = `{
60
49
  },
61
50
  "include": ["src/**/*"]
62
51
  }
63
- `;
64
- const GITIGNORE_TEMPLATE = `node_modules/
52
+ `, GITIGNORE_TEMPLATE = `node_modules/
65
53
  dist/
66
54
  *.thinkwell.d.ts
67
55
  .env
68
- `;
69
- const ENV_EXAMPLE_TEMPLATE = `# Configure your agent command
56
+ `, ENV_EXAMPLE_TEMPLATE = `# Configure your agent command
70
57
  # Example for Claude Code:
71
58
  # THINKWELL_AGENT_CMD=claude --dangerously-skip-permissions
72
59
  `;
73
60
  function createProject(options) {
74
- const { name, targetDir } = options;
75
- // Create directories
76
- mkdirSync(targetDir, { recursive: true });
77
- mkdirSync(join(targetDir, "src"), { recursive: true });
78
- // Write files
79
- writeFileSync(join(targetDir, "package.json"), PACKAGE_JSON_TEMPLATE(name));
80
- writeFileSync(join(targetDir, "src/main.ts"), MAIN_TS_TEMPLATE);
81
- writeFileSync(join(targetDir, "tsconfig.json"), TSCONFIG_TEMPLATE);
82
- writeFileSync(join(targetDir, ".gitignore"), GITIGNORE_TEMPLATE);
83
- writeFileSync(join(targetDir, ".env.example"), ENV_EXAMPLE_TEMPLATE);
61
+ const { name, targetDir } = options;
62
+ mkdirSync(targetDir, { recursive: !0 }), mkdirSync(join(targetDir, "src"), { recursive: !0 }), writeFileSync(join(targetDir, "package.json"), PACKAGE_JSON_TEMPLATE(name)), writeFileSync(join(targetDir, "src/main.ts"), MAIN_TS_TEMPLATE), writeFileSync(join(targetDir, "tsconfig.json"), TSCONFIG_TEMPLATE), writeFileSync(join(targetDir, ".gitignore"), GITIGNORE_TEMPLATE), writeFileSync(join(targetDir, ".env.example"), ENV_EXAMPLE_TEMPLATE);
84
63
  }
85
64
  function showHelp() {
86
- console.log(`
65
+ console.log(`
87
66
  ${cyanBold("thinkwell new")} - ${whiteBold("Create a new thinkwell project in a new directory")}
88
67
 
89
68
  ${greenBold("Usage:")}
@@ -104,52 +83,25 @@ ${greenBold("This command creates:")}
104
83
 
105
84
  ${greenBold("To initialize the current directory instead:")}
106
85
  ${cyanBold("thinkwell init")}
107
- `.trim() + "\n");
86
+ `.trim() + `
87
+ `);
108
88
  }
109
89
  export async function runNew(args) {
110
- // Check for help flag
111
- if (args.includes("--help") || args.includes("-h")) {
112
- showHelp();
113
- return;
114
- }
115
- // Get project name from args - required
116
- const projectArg = args.find((arg) => !arg.startsWith("-"));
117
- if (!projectArg) {
118
- console.error(`${redBold("Error:")} Project name is required.`);
119
- console.error("");
120
- console.error("Usage:");
121
- console.error(` ${cyanBold("thinkwell new")} ${cyan("<project-name>")}`);
122
- console.error("");
123
- console.error("To initialize the current directory instead:");
124
- console.error(` ${cyanBold("thinkwell init")}`);
125
- process.exit(1);
126
- }
127
- const targetDir = resolve(projectArg);
128
- const name = projectArg;
129
- // Check if directory exists and is not empty
130
- if (existsSync(targetDir)) {
131
- const files = ["package.json", "tsconfig.json", "src/main.ts"];
132
- const existingFiles = files.filter((f) => existsSync(join(targetDir, f)));
133
- if (existingFiles.length > 0) {
134
- console.error(`${redBold("Error:")} Directory already contains project files:`);
135
- for (const file of existingFiles) {
136
- console.error(` - ${file}`);
137
- }
138
- console.error("");
139
- console.error("Use a different directory or remove existing files.");
140
- process.exit(1);
141
- }
90
+ if (args.includes("--help") || args.includes("-h")) {
91
+ showHelp();
92
+ return;
93
+ }
94
+ const projectArg = args.find((arg) => !arg.startsWith("-"));
95
+ projectArg || (console.error(`${redBold("Error:")} Project name is required.`), console.error(""), console.error("Usage:"), console.error(` ${cyanBold("thinkwell new")} ${cyan("<project-name>")}`), console.error(""), console.error("To initialize the current directory instead:"), console.error(` ${cyanBold("thinkwell init")}`), process.exit(1));
96
+ const targetDir = resolve(projectArg), name = projectArg;
97
+ if (existsSync(targetDir)) {
98
+ const existingFiles = ["package.json", "tsconfig.json", "src/main.ts"].filter((f) => existsSync(join(targetDir, f)));
99
+ if (existingFiles.length > 0) {
100
+ console.error(`${redBold("Error:")} Directory already contains project files:`);
101
+ for (const file of existingFiles)
102
+ console.error(` - ${file}`);
103
+ console.error(""), console.error("Use a different directory or remove existing files."), process.exit(1);
142
104
  }
143
- console.log(`${greenBold("Creating")} thinkwell project in ${targetDir}...`);
144
- console.log("");
145
- createProject({ name, targetDir });
146
- console.log(greenBold("Next steps:"));
147
- console.log("");
148
- console.log(` ${cyanBold("cd")} ${cyan(projectArg)}`);
149
- console.log(` ${cyanBold("npm install")} ${dim("# or: pnpm install")}`);
150
- console.log(` ${cyanBold("cp")} ${cyan(".env.example .env")}`);
151
- console.log(` ${dim("# Edit .env to configure your agent")}`);
152
- console.log(` ${cyanBold("thinkwell")} ${cyan("src/main.ts")}`);
153
- console.log("");
105
+ }
106
+ console.log(`${greenBold("Creating")} thinkwell project in ${targetDir}...`), console.log(""), createProject({ name, targetDir }), console.log(greenBold("Next steps:")), console.log(""), console.log(` ${cyanBold("cd")} ${cyan(projectArg)}`), console.log(` ${cyanBold("npm install")} ${dim("# or: pnpm install")}`), console.log(` ${cyanBold("cp")} ${cyan(".env.example .env")}`), console.log(` ${dim("# Edit .env to configure your agent")}`), console.log(` ${cyanBold("thinkwell")} ${cyan("src/main.ts")}`), console.log("");
154
107
  }
155
- //# sourceMappingURL=new-command.js.map