@agentuity/cli 1.0.59 → 2.0.0-beta.1

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 (189) hide show
  1. package/bin/cli.ts +2 -3
  2. package/dist/cmd/build/app-config-extractor.d.ts +27 -0
  3. package/dist/cmd/build/app-config-extractor.d.ts.map +1 -0
  4. package/dist/cmd/build/app-config-extractor.js +152 -0
  5. package/dist/cmd/build/app-config-extractor.js.map +1 -0
  6. package/dist/cmd/build/app-router-detector.d.ts +2 -5
  7. package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
  8. package/dist/cmd/build/app-router-detector.js +130 -154
  9. package/dist/cmd/build/app-router-detector.js.map +1 -1
  10. package/dist/cmd/build/ci.d.ts.map +1 -1
  11. package/dist/cmd/build/ci.js +5 -21
  12. package/dist/cmd/build/ci.js.map +1 -1
  13. package/dist/cmd/build/ids.d.ts +11 -0
  14. package/dist/cmd/build/ids.d.ts.map +1 -0
  15. package/dist/cmd/build/ids.js +18 -0
  16. package/dist/cmd/build/ids.js.map +1 -0
  17. package/dist/cmd/build/index.d.ts.map +1 -1
  18. package/dist/cmd/build/index.js +8 -0
  19. package/dist/cmd/build/index.js.map +1 -1
  20. package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
  21. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  22. package/dist/cmd/build/vite/agent-discovery.js +166 -487
  23. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  24. package/dist/cmd/build/vite/bun-dev-server.d.ts +43 -14
  25. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  26. package/dist/cmd/build/vite/bun-dev-server.js +290 -129
  27. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  28. package/dist/cmd/build/vite/config-loader.d.ts +15 -20
  29. package/dist/cmd/build/vite/config-loader.d.ts.map +1 -1
  30. package/dist/cmd/build/vite/config-loader.js +41 -74
  31. package/dist/cmd/build/vite/config-loader.js.map +1 -1
  32. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
  33. package/dist/cmd/build/vite/docs-generator.js +0 -2
  34. package/dist/cmd/build/vite/docs-generator.js.map +1 -1
  35. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  36. package/dist/cmd/build/vite/index.js +0 -36
  37. package/dist/cmd/build/vite/index.js.map +1 -1
  38. package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
  39. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  40. package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
  41. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  42. package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
  43. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  44. package/dist/cmd/build/vite/route-discovery.js +97 -177
  45. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  46. package/dist/cmd/build/vite/server-bundler.js +1 -1
  47. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  48. package/dist/cmd/build/vite/static-renderer.d.ts +0 -2
  49. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  50. package/dist/cmd/build/vite/static-renderer.js +19 -13
  51. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  52. package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
  53. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  54. package/dist/cmd/build/vite/vite-asset-server-config.js +175 -69
  55. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  56. package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
  57. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  58. package/dist/cmd/build/vite/vite-asset-server.js +14 -13
  59. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  60. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  61. package/dist/cmd/build/vite/vite-builder.js +42 -190
  62. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  63. package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
  64. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
  65. package/dist/cmd/build/vite/ws-proxy.js +95 -0
  66. package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
  67. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  68. package/dist/cmd/build/vite-bundler.js +0 -3
  69. package/dist/cmd/build/vite-bundler.js.map +1 -1
  70. package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -1
  71. package/dist/cmd/cloud/deploy-fork.js +15 -36
  72. package/dist/cmd/cloud/deploy-fork.js.map +1 -1
  73. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  74. package/dist/cmd/cloud/sandbox/exec.js +28 -86
  75. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  76. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  77. package/dist/cmd/cloud/sandbox/run.js +2 -9
  78. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  79. package/dist/cmd/cloud/sandbox/snapshot/build.js +2 -2
  80. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  81. package/dist/cmd/coder/hub-url.d.ts.map +1 -1
  82. package/dist/cmd/coder/hub-url.js +1 -3
  83. package/dist/cmd/coder/hub-url.js.map +1 -1
  84. package/dist/cmd/coder/start.js +6 -6
  85. package/dist/cmd/coder/start.js.map +1 -1
  86. package/dist/cmd/coder/tui-init.d.ts +2 -2
  87. package/dist/cmd/coder/tui-init.js +2 -2
  88. package/dist/cmd/coder/tui-init.js.map +1 -1
  89. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  90. package/dist/cmd/dev/file-watcher.js +2 -8
  91. package/dist/cmd/dev/file-watcher.js.map +1 -1
  92. package/dist/cmd/dev/index.d.ts.map +1 -1
  93. package/dist/cmd/dev/index.js +432 -752
  94. package/dist/cmd/dev/index.js.map +1 -1
  95. package/dist/cmd/dev/process-manager.d.ts +104 -0
  96. package/dist/cmd/dev/process-manager.d.ts.map +1 -0
  97. package/dist/cmd/dev/process-manager.js +204 -0
  98. package/dist/cmd/dev/process-manager.js.map +1 -0
  99. package/dist/errors.d.ts +10 -24
  100. package/dist/errors.d.ts.map +1 -1
  101. package/dist/errors.js +12 -42
  102. package/dist/errors.js.map +1 -1
  103. package/dist/schema-generator.d.ts.map +1 -1
  104. package/dist/schema-generator.js +12 -2
  105. package/dist/schema-generator.js.map +1 -1
  106. package/dist/tui.d.ts.map +1 -1
  107. package/dist/tui.js +5 -19
  108. package/dist/tui.js.map +1 -1
  109. package/dist/utils/version-mismatch.d.ts +39 -0
  110. package/dist/utils/version-mismatch.d.ts.map +1 -0
  111. package/dist/utils/version-mismatch.js +161 -0
  112. package/dist/utils/version-mismatch.js.map +1 -0
  113. package/package.json +6 -6
  114. package/src/cmd/ai/prompt/agent.md +0 -1
  115. package/src/cmd/ai/prompt/api.md +0 -7
  116. package/src/cmd/ai/prompt/web.md +51 -213
  117. package/src/cmd/build/app-config-extractor.ts +186 -0
  118. package/src/cmd/build/app-router-detector.ts +152 -182
  119. package/src/cmd/build/ci.ts +5 -21
  120. package/src/cmd/build/ids.ts +19 -0
  121. package/src/cmd/build/index.ts +10 -0
  122. package/src/cmd/build/vite/agent-discovery.ts +208 -679
  123. package/src/cmd/build/vite/bun-dev-server.ts +383 -146
  124. package/src/cmd/build/vite/config-loader.ts +45 -77
  125. package/src/cmd/build/vite/docs-generator.ts +0 -2
  126. package/src/cmd/build/vite/index.ts +1 -42
  127. package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
  128. package/src/cmd/build/vite/route-discovery.ts +116 -274
  129. package/src/cmd/build/vite/server-bundler.ts +1 -1
  130. package/src/cmd/build/vite/static-renderer.ts +23 -15
  131. package/src/cmd/build/vite/vite-asset-server-config.ts +200 -70
  132. package/src/cmd/build/vite/vite-asset-server.ts +25 -15
  133. package/src/cmd/build/vite/vite-builder.ts +49 -220
  134. package/src/cmd/build/vite/ws-proxy.ts +126 -0
  135. package/src/cmd/build/vite-bundler.ts +0 -4
  136. package/src/cmd/cloud/deploy-fork.ts +16 -39
  137. package/src/cmd/cloud/sandbox/exec.ts +23 -130
  138. package/src/cmd/cloud/sandbox/run.ts +2 -9
  139. package/src/cmd/cloud/sandbox/snapshot/build.ts +2 -2
  140. package/src/cmd/coder/hub-url.ts +1 -3
  141. package/src/cmd/coder/start.ts +6 -6
  142. package/src/cmd/coder/tui-init.ts +4 -4
  143. package/src/cmd/dev/file-watcher.ts +2 -9
  144. package/src/cmd/dev/index.ts +476 -859
  145. package/src/cmd/dev/process-manager.ts +261 -0
  146. package/src/errors.ts +12 -44
  147. package/src/schema-generator.ts +12 -2
  148. package/src/tui.ts +5 -18
  149. package/src/utils/version-mismatch.ts +204 -0
  150. package/dist/cmd/build/ast.d.ts +0 -78
  151. package/dist/cmd/build/ast.d.ts.map +0 -1
  152. package/dist/cmd/build/ast.js +0 -2703
  153. package/dist/cmd/build/ast.js.map +0 -1
  154. package/dist/cmd/build/entry-generator.d.ts +0 -25
  155. package/dist/cmd/build/entry-generator.d.ts.map +0 -1
  156. package/dist/cmd/build/entry-generator.js +0 -695
  157. package/dist/cmd/build/entry-generator.js.map +0 -1
  158. package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
  159. package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
  160. package/dist/cmd/build/vite/api-mount-path.js +0 -83
  161. package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
  162. package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
  163. package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
  164. package/dist/cmd/build/vite/registry-generator.js +0 -1108
  165. package/dist/cmd/build/vite/registry-generator.js.map +0 -1
  166. package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
  167. package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
  168. package/dist/cmd/build/webanalytics-generator.js +0 -178
  169. package/dist/cmd/build/webanalytics-generator.js.map +0 -1
  170. package/dist/cmd/build/workbench.d.ts +0 -7
  171. package/dist/cmd/build/workbench.d.ts.map +0 -1
  172. package/dist/cmd/build/workbench.js +0 -55
  173. package/dist/cmd/build/workbench.js.map +0 -1
  174. package/dist/utils/route-migration.d.ts +0 -62
  175. package/dist/utils/route-migration.d.ts.map +0 -1
  176. package/dist/utils/route-migration.js +0 -630
  177. package/dist/utils/route-migration.js.map +0 -1
  178. package/dist/utils/stream-capture.d.ts +0 -9
  179. package/dist/utils/stream-capture.d.ts.map +0 -1
  180. package/dist/utils/stream-capture.js +0 -34
  181. package/dist/utils/stream-capture.js.map +0 -1
  182. package/src/cmd/build/ast.ts +0 -3529
  183. package/src/cmd/build/entry-generator.ts +0 -760
  184. package/src/cmd/build/vite/api-mount-path.ts +0 -87
  185. package/src/cmd/build/vite/registry-generator.ts +0 -1267
  186. package/src/cmd/build/webanalytics-generator.ts +0 -197
  187. package/src/cmd/build/workbench.ts +0 -58
  188. package/src/utils/route-migration.ts +0 -757
  189. package/src/utils/stream-capture.ts +0 -39
package/bin/cli.ts CHANGED
@@ -153,6 +153,7 @@ if (!hasHelp) {
153
153
  parsedOperands = parsed.operands;
154
154
  }
155
155
  const earlyOpts = program.opts();
156
+
156
157
  // Normalize --org alias → orgId (agents prefer --org over --org-id)
157
158
  if (earlyOpts.org !== undefined && earlyOpts.orgId === undefined) {
158
159
  earlyOpts.orgId = earlyOpts.org;
@@ -325,9 +326,7 @@ async function main() {
325
326
  closeDatabase();
326
327
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
327
328
  const exit = (globalThis as any).AGENTUITY_PROCESS_EXIT || process.exit;
328
- // Preserve process.exitCode set by command handlers (e.g., sandbox run/exec
329
- // propagate the sandbox process's exit code). Default to 0 for success.
330
- exit(process.exitCode ?? 0);
329
+ exit(0);
331
330
  }
332
331
 
333
332
  try {
@@ -0,0 +1,27 @@
1
+ /**
2
+ * App Config Extractor
3
+ *
4
+ * Extracts analytics and workbench config from the user's createApp() call
5
+ * in app.ts. This is the v2 approach where createApp() is the single source
6
+ * of truth for runtime configuration (replacing agentuity.config.ts).
7
+ *
8
+ * Uses TypeScript's compiler API to reliably detect and extract values.
9
+ */
10
+ import type { Logger } from '../../types';
11
+ /**
12
+ * Extracted runtime config from createApp() call.
13
+ */
14
+ export interface ExtractedAppConfig {
15
+ /** analytics option value: boolean, object, or undefined if not set */
16
+ analytics?: boolean | Record<string, unknown>;
17
+ /** workbench option value: boolean, string, object, or undefined if not set */
18
+ workbench?: boolean | string | Record<string, unknown>;
19
+ }
20
+ /**
21
+ * Detect and extract analytics/workbench config from app.ts.
22
+ *
23
+ * This is the v2 approach: runtime config lives in createApp() only.
24
+ * The CLI reads these values at build time via AST parsing.
25
+ */
26
+ export declare function extractAppConfig(rootDir: string, logger: Logger): Promise<ExtractedAppConfig>;
27
+ //# sourceMappingURL=app-config-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-config-extractor.d.ts","sourceRoot":"","sources":["../../../src/cmd/build/app-config-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvD;AA+GD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC,CA2C7B"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * App Config Extractor
3
+ *
4
+ * Extracts analytics and workbench config from the user's createApp() call
5
+ * in app.ts. This is the v2 approach where createApp() is the single source
6
+ * of truth for runtime configuration (replacing agentuity.config.ts).
7
+ *
8
+ * Uses TypeScript's compiler API to reliably detect and extract values.
9
+ */
10
+ import ts from 'typescript';
11
+ import { join } from 'node:path';
12
+ /**
13
+ * Extract analytics and workbench config from a createApp() call.
14
+ *
15
+ * Uses TypeScript AST to find `createApp({ ... })` and extract the values
16
+ * of the `analytics` and `workbench` properties.
17
+ */
18
+ function extractCreateAppConfig(sourceFile) {
19
+ const result = {};
20
+ // Walk the AST looking for createApp({ ... }) calls
21
+ function visit(node) {
22
+ // Check for createApp(...) call
23
+ if (ts.isCallExpression(node) &&
24
+ ts.isIdentifier(node.expression) &&
25
+ node.expression.text === 'createApp' &&
26
+ node.arguments.length > 0) {
27
+ const firstArg = node.arguments[0];
28
+ if (!firstArg)
29
+ return;
30
+ if (ts.isObjectLiteralExpression(firstArg)) {
31
+ // Found createApp({ ... }) — extract properties
32
+ for (const prop of firstArg.properties) {
33
+ if (!ts.isPropertyAssignment(prop))
34
+ continue;
35
+ const name = ts.isIdentifier(prop.name) ? prop.name.text : undefined;
36
+ if (!name)
37
+ continue;
38
+ // prop.initializer should always exist for PropertyAssignment, but check to satisfy TS
39
+ if (!('initializer' in prop))
40
+ continue;
41
+ const initializer = prop.initializer;
42
+ if (name === 'analytics') {
43
+ const value = extractValue(initializer);
44
+ if (value !== undefined) {
45
+ if (typeof value === 'boolean') {
46
+ result.analytics = value;
47
+ }
48
+ else if (typeof value === 'object') {
49
+ result.analytics = value;
50
+ }
51
+ // Ignore string/number for analytics
52
+ }
53
+ }
54
+ else if (name === 'workbench') {
55
+ const value = extractValue(initializer);
56
+ if (value !== undefined) {
57
+ if (typeof value === 'boolean' || typeof value === 'string') {
58
+ result.workbench = value;
59
+ }
60
+ else if (typeof value === 'object') {
61
+ result.workbench = value;
62
+ }
63
+ // Ignore number for workbench
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ ts.forEachChild(node, visit);
70
+ }
71
+ visit(sourceFile);
72
+ return result;
73
+ }
74
+ /**
75
+ * Extract a JavaScript value from a TypeScript AST expression node.
76
+ * Handles: boolean literals, string literals, numeric literals,
77
+ * object literals (as Record), and identifier references (by name).
78
+ */
79
+ function extractValue(node) {
80
+ if (ts.isLiteralExpression(node)) {
81
+ // String literal or numeric literal
82
+ if (ts.isStringLiteral(node)) {
83
+ return node.text;
84
+ }
85
+ if (ts.isNumericLiteral(node)) {
86
+ return Number(node.text);
87
+ }
88
+ }
89
+ if (node.kind === ts.SyntaxKind.TrueKeyword) {
90
+ return true;
91
+ }
92
+ if (node.kind === ts.SyntaxKind.FalseKeyword) {
93
+ return false;
94
+ }
95
+ if (ts.isIdentifier(node)) {
96
+ // Return the identifier name (e.g., a variable reference)
97
+ return node.text;
98
+ }
99
+ if (ts.isObjectLiteralExpression(node)) {
100
+ const obj = {};
101
+ for (const prop of node.properties) {
102
+ if (!ts.isPropertyAssignment(prop))
103
+ continue;
104
+ if (!ts.isIdentifier(prop.name))
105
+ continue;
106
+ const key = prop.name.text;
107
+ obj[key] = extractValue(prop.initializer);
108
+ }
109
+ return obj;
110
+ }
111
+ return undefined;
112
+ }
113
+ /**
114
+ * Detect and extract analytics/workbench config from app.ts.
115
+ *
116
+ * This is the v2 approach: runtime config lives in createApp() only.
117
+ * The CLI reads these values at build time via AST parsing.
118
+ */
119
+ export async function extractAppConfig(rootDir, logger) {
120
+ // Look for app.ts in root first, then src/
121
+ let appFile = join(rootDir, 'app.ts');
122
+ if (!(await Bun.file(appFile).exists())) {
123
+ appFile = join(rootDir, 'src', 'app.ts');
124
+ if (!(await Bun.file(appFile).exists())) {
125
+ logger.trace('[config-extract] No app.ts found');
126
+ return {};
127
+ }
128
+ }
129
+ try {
130
+ const source = await Bun.file(appFile).text();
131
+ // Quick bail-out before parsing
132
+ if (!source.includes('createApp')) {
133
+ logger.trace('[config-extract] No createApp call in %s', appFile);
134
+ return {};
135
+ }
136
+ // Parse with TypeScript
137
+ const sourceFile = ts.createSourceFile(appFile, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
138
+ const config = extractCreateAppConfig(sourceFile);
139
+ if (config.analytics !== undefined) {
140
+ logger.debug('[config-extract] Found analytics in createApp(): %o', config.analytics);
141
+ }
142
+ if (config.workbench !== undefined) {
143
+ logger.debug('[config-extract] Found workbench in createApp(): %o', config.workbench);
144
+ }
145
+ return config;
146
+ }
147
+ catch (error) {
148
+ logger.warn('[config-extract] Failed to parse app.ts:', error);
149
+ return {};
150
+ }
151
+ }
152
+ //# sourceMappingURL=app-config-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-config-extractor.js","sourceRoot":"","sources":["../../../src/cmd/build/app-config-extractor.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,8 @@
5
5
  * to `createApp()`. If detected, resolves the router variable(s) to their import
6
6
  * sources and mount paths.
7
7
  *
8
- * This allows the build tooling to derive route metadata from the actual code-based
9
- * route tree instead of relying on filesystem-based discovery.
8
+ * Uses TypeScript's compiler API to reliably detect the pattern, consistent with
9
+ * the lifecycle generator approach.
10
10
  */
11
11
  import type { Logger } from '../../types';
12
12
  /**
@@ -30,9 +30,6 @@ export interface AppRouterDetection {
30
30
  /**
31
31
  * Detect whether `src/app.ts` uses `createApp({ router })`.
32
32
  *
33
- * Parses the file with acorn-loose, finds `createApp()` calls,
34
- * and resolves router variables to their import source files.
35
- *
36
33
  * Returns `{ detected: false, mounts: [] }` when:
37
34
  * - `src/app.ts` doesn't exist
38
35
  * - `createApp()` is called without a `router` property
@@ -1 +1 @@
1
- {"version":3,"file":"app-router-detector.d.ts","sourceRoot":"","sources":["../../../src/cmd/build/app-router-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,MAAM,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAgHD;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC,CAgB7B"}
1
+ {"version":3,"file":"app-router-detector.d.ts","sourceRoot":"","sources":["../../../src/cmd/build/app-router-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,MAAM,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAuLD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC,CA2F7B"}
@@ -5,23 +5,24 @@
5
5
  * to `createApp()`. If detected, resolves the router variable(s) to their import
6
6
  * sources and mount paths.
7
7
  *
8
- * This allows the build tooling to derive route metadata from the actual code-based
9
- * route tree instead of relying on filesystem-based discovery.
8
+ * Uses TypeScript's compiler API to reliably detect the pattern, consistent with
9
+ * the lifecycle generator approach.
10
10
  */
11
- import * as acornLoose from 'acorn-loose';
11
+ import ts from 'typescript';
12
12
  import { join, dirname, resolve } from 'node:path';
13
- import { existsSync, statSync } from 'node:fs';
13
+ import { statSync } from 'node:fs';
14
14
  /**
15
15
  * Resolve an import path to an actual file on disk.
16
16
  * Tries the path as-is, then with common extensions.
17
17
  */
18
- function resolveImportFile(fromDir, importPath) {
18
+ async function resolveImportFile(fromDir, importPath) {
19
19
  if (!importPath.startsWith('.') && !importPath.startsWith('/')) {
20
20
  return null; // Package import — can't resolve
21
21
  }
22
22
  const basePath = resolve(fromDir, importPath);
23
23
  const extensions = ['.ts', '.tsx', '/index.ts', '/index.tsx'];
24
- if (existsSync(basePath)) {
24
+ const baseFile = Bun.file(basePath);
25
+ if (await baseFile.exists()) {
25
26
  try {
26
27
  if (statSync(basePath).isFile())
27
28
  return basePath;
@@ -32,82 +33,138 @@ function resolveImportFile(fromDir, importPath) {
32
33
  }
33
34
  for (const ext of extensions) {
34
35
  const candidate = basePath + ext;
35
- if (existsSync(candidate)) {
36
+ if (await Bun.file(candidate).exists()) {
36
37
  return candidate;
37
38
  }
38
39
  }
39
40
  return null;
40
41
  }
41
42
  /**
42
- * Extract the `router` property value from a `createApp()` call's argument object.
43
- *
44
- * Handles three forms:
45
- * - `createApp({ router: myVar })` → plain Hono, default /api mount
46
- * - `createApp({ router: { path: '/v1', router: myVar } })` → single RouteMount
47
- * - `createApp({ router: [{ path: '/v1', router: v1 }, ...] })` → array of RouteMounts
43
+ * Extract router mounts from a createApp() call using TypeScript's AST.
44
+ * Returns null if no router property found.
48
45
  */
49
- function extractRouterFromCreateApp(callNode) {
50
- // createApp() must have at least one argument (the config object)
51
- if (!callNode.arguments || callNode.arguments.length === 0) {
52
- return null;
53
- }
54
- const configArg = callNode.arguments[0];
55
- if (configArg.type !== 'ObjectExpression') {
46
+ function extractRouterMounts(sourceFile) {
47
+ let result = null;
48
+ function getStringLiteral(node) {
49
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
50
+ return node.text;
51
+ }
56
52
  return null;
57
53
  }
58
- // Find the `router` property
59
- const routerProp = configArg.properties?.find((p) => p.type === 'Property' && p.key?.type === 'Identifier' && p.key?.name === 'router');
60
- if (!routerProp) {
61
- return null; // No router property — file-based routing
62
- }
63
- const routerValue = routerProp.value;
64
- // Form 1: Plain Hono variable → createApp({ router: myRouter })
65
- if (routerValue.type === 'Identifier') {
66
- return [{ path: '/api', varName: routerValue.name }];
54
+ function extractMountFromObject(obj) {
55
+ let path;
56
+ let varName;
57
+ for (const prop of obj.properties) {
58
+ if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
59
+ continue;
60
+ if (prop.name.text === 'path') {
61
+ path = getStringLiteral(prop.initializer) ?? undefined;
62
+ }
63
+ if (prop.name.text === 'router') {
64
+ if (ts.isIdentifier(prop.initializer)) {
65
+ varName = prop.initializer.text;
66
+ }
67
+ }
68
+ }
69
+ // Also handle shorthand: { path: '/v1', router } where router is shorthand
70
+ for (const prop of obj.properties) {
71
+ if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === 'router') {
72
+ varName = prop.name.text;
73
+ }
74
+ }
75
+ return path && varName ? { path, varName } : null;
67
76
  }
68
- // Form 2: Single RouteMount → createApp({ router: { path: '/v1', router: myRouter } })
69
- if (routerValue.type === 'ObjectExpression') {
70
- const mount = extractRouteMountFromObject(routerValue);
71
- return mount ? [mount] : null;
77
+ function processRouterValue(value) {
78
+ // Form 1: Identifier → createApp({ router: myRouter })
79
+ if (ts.isIdentifier(value)) {
80
+ return [{ path: '/api', varName: value.text }];
81
+ }
82
+ // Form 2: Object → createApp({ router: { path: '/v1', router: myRouter } })
83
+ if (ts.isObjectLiteralExpression(value)) {
84
+ const mount = extractMountFromObject(value);
85
+ return mount ? [mount] : null;
86
+ }
87
+ // Form 3: Array → createApp({ router: [...] })
88
+ if (ts.isArrayLiteralExpression(value)) {
89
+ const mounts = [];
90
+ for (const element of value.elements) {
91
+ if (ts.isObjectLiteralExpression(element)) {
92
+ const mount = extractMountFromObject(element);
93
+ if (mount)
94
+ mounts.push(mount);
95
+ }
96
+ }
97
+ return mounts.length > 0 ? mounts : null;
98
+ }
99
+ return null;
72
100
  }
73
- // Form 3: Array of RouteMounts → createApp({ router: [{ path: '/v1', router: v1 }, ...] })
74
- if (routerValue.type === 'ArrayExpression') {
75
- const mounts = [];
76
- for (const element of routerValue.elements || []) {
77
- if (element?.type === 'ObjectExpression') {
78
- const mount = extractRouteMountFromObject(element);
79
- if (mount)
80
- mounts.push(mount);
101
+ function visit(node) {
102
+ if (result)
103
+ return;
104
+ // Find createApp(...) with or without await
105
+ let callExpr;
106
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
107
+ if (node.expression.text === 'createApp')
108
+ callExpr = node;
109
+ }
110
+ else if (ts.isAwaitExpression(node) && ts.isCallExpression(node.expression)) {
111
+ const call = node.expression;
112
+ if (ts.isIdentifier(call.expression) && call.expression.text === 'createApp') {
113
+ callExpr = call;
81
114
  }
82
115
  }
83
- return mounts.length > 0 ? mounts : null;
116
+ if (callExpr && callExpr.arguments.length > 0) {
117
+ const configArg = callExpr.arguments[0];
118
+ if (configArg && ts.isObjectLiteralExpression(configArg)) {
119
+ for (const prop of configArg.properties) {
120
+ // Handle: router: value
121
+ if (ts.isPropertyAssignment(prop) &&
122
+ ts.isIdentifier(prop.name) &&
123
+ prop.name.text === 'router') {
124
+ result = processRouterValue(prop.initializer);
125
+ return;
126
+ }
127
+ // Handle shorthand: createApp({ router })
128
+ if (ts.isShorthandPropertyAssignment(prop) && prop.name.text === 'router') {
129
+ result = [{ path: '/api', varName: 'router' }];
130
+ return;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ ts.forEachChild(node, visit);
84
136
  }
85
- return null;
137
+ visit(sourceFile);
138
+ return result;
86
139
  }
87
140
  /**
88
- * Extract { path, router } from an object literal AST node.
141
+ * Build import map from the source file: variable name import path
89
142
  */
90
- function extractRouteMountFromObject(objNode) {
91
- let path;
92
- let varName;
93
- for (const prop of objNode.properties || []) {
94
- if (prop.type !== 'Property' || prop.key?.type !== 'Identifier')
143
+ function buildImportMap(sourceFile) {
144
+ const importMap = new Map();
145
+ for (const stmt of sourceFile.statements) {
146
+ if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier))
147
+ continue;
148
+ const importPath = stmt.moduleSpecifier.text;
149
+ const clause = stmt.importClause;
150
+ if (!clause)
95
151
  continue;
96
- if (prop.key.name === 'path' && prop.value?.type === 'Literal') {
97
- path = String(prop.value.value);
152
+ // Default import: import router from './api'
153
+ if (clause.name) {
154
+ importMap.set(clause.name.text, importPath);
98
155
  }
99
- if (prop.key.name === 'router' && prop.value?.type === 'Identifier') {
100
- varName = prop.value.name;
156
+ // Named imports: import { v1, v2 } from './routers'
157
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
158
+ for (const spec of clause.namedBindings.elements) {
159
+ importMap.set(spec.name.text, importPath);
160
+ }
101
161
  }
102
162
  }
103
- return path && varName ? { path, varName } : null;
163
+ return importMap;
104
164
  }
105
165
  /**
106
166
  * Detect whether `src/app.ts` uses `createApp({ router })`.
107
167
  *
108
- * Parses the file with acorn-loose, finds `createApp()` calls,
109
- * and resolves router variables to their import source files.
110
- *
111
168
  * Returns `{ detected: false, mounts: [] }` when:
112
169
  * - `src/app.ts` doesn't exist
113
170
  * - `createApp()` is called without a `router` property
@@ -115,63 +172,41 @@ function extractRouteMountFromObject(objNode) {
115
172
  */
116
173
  export async function detectExplicitRouter(rootDir, logger) {
117
174
  const noDetection = { detected: false, mounts: [] };
118
- // Look for app.ts in src/ (standard location)
119
- const appFile = join(rootDir, 'src', 'app.ts');
120
- if (!existsSync(appFile)) {
121
- // Also try root-level app.ts
122
- const rootAppFile = join(rootDir, 'app.ts');
123
- if (!existsSync(rootAppFile)) {
175
+ // Look for app.ts in src/ (standard location), then root
176
+ let appFile = join(rootDir, 'src', 'app.ts');
177
+ if (!(await Bun.file(appFile).exists())) {
178
+ appFile = join(rootDir, 'app.ts');
179
+ if (!(await Bun.file(appFile).exists())) {
124
180
  logger.trace('[router-detect] No app.ts found');
125
181
  return noDetection;
126
182
  }
127
- return detectInFile(rootAppFile, logger);
128
183
  }
129
- return detectInFile(appFile, logger);
130
- }
131
- async function detectInFile(appFile, logger) {
132
- const noDetection = { detected: false, mounts: [] };
133
- const appDir = dirname(appFile);
134
184
  try {
135
185
  const source = await Bun.file(appFile).text();
136
- const transpiler = new Bun.Transpiler({ loader: 'ts', target: 'bun' });
137
- const contents = transpiler.transformSync(source);
138
- // Quick check: skip AST parsing if createApp is not called with router
139
- if (!contents.includes('createApp') || !contents.includes('router')) {
186
+ const appDir = dirname(appFile);
187
+ // Quick bail-out before parsing
188
+ if (!source.includes('createApp') || !source.includes('router')) {
140
189
  logger.trace('[router-detect] No createApp + router pattern found in %s', appFile);
141
190
  return noDetection;
142
191
  }
143
- const ast = acornLoose.parse(contents, {
144
- locations: true,
145
- ecmaVersion: 'latest',
146
- sourceType: 'module',
147
- });
148
- // Build import map: variable name → import path
149
- const importMap = new Map();
150
- for (const node of ast.body || []) {
151
- if (node.type === 'ImportDeclaration' && node.source?.value) {
152
- for (const spec of node.specifiers || []) {
153
- if (spec.local?.name) {
154
- importMap.set(spec.local.name, String(node.source.value));
155
- }
156
- }
157
- }
158
- }
159
- // Walk all statements looking for createApp() calls
160
- const routerMounts = findCreateAppRouterCalls(ast, importMap);
161
- if (!routerMounts || routerMounts.length === 0) {
192
+ // Parse with TypeScript
193
+ const sourceFile = ts.createSourceFile(appFile, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
194
+ const rawMounts = extractRouterMounts(sourceFile);
195
+ if (!rawMounts || rawMounts.length === 0) {
162
196
  logger.trace('[router-detect] createApp() found but no router property');
163
197
  return noDetection;
164
198
  }
199
+ // Build import map to resolve variable names to file paths
200
+ const importMap = buildImportMap(sourceFile);
165
201
  // Resolve each router variable to its file
166
202
  const mounts = [];
167
- for (const { path, varName } of routerMounts) {
203
+ for (const { path, varName } of rawMounts) {
168
204
  const importPath = importMap.get(varName);
169
205
  if (!importPath) {
170
206
  logger.debug('[router-detect] Router variable %s is not imported — may be defined locally', varName);
171
- // Could be defined in the same file — skip for now
172
207
  continue;
173
208
  }
174
- const resolvedFile = resolveImportFile(appDir, importPath);
209
+ const resolvedFile = await resolveImportFile(appDir, importPath);
175
210
  if (!resolvedFile) {
176
211
  logger.warn('[router-detect] Could not resolve import %s for router variable %s', importPath, varName);
177
212
  continue;
@@ -191,63 +226,4 @@ async function detectInFile(appFile, logger) {
191
226
  return noDetection;
192
227
  }
193
228
  }
194
- /**
195
- * Walk the AST looking for `createApp({ router: ... })` calls.
196
- * Handles:
197
- * - `createApp({ router })` (top-level expression)
198
- * - `const app = await createApp({ router })` (variable declaration)
199
- * - `export const app = await createApp({ router })` (exported)
200
- */
201
- function findCreateAppRouterCalls(ast, importMap) {
202
- for (const node of ast.body || []) {
203
- // Check expression statements: createApp({ router })
204
- if (node.type === 'ExpressionStatement') {
205
- const result = checkForCreateAppCall(node.expression, importMap);
206
- if (result)
207
- return result;
208
- }
209
- // Check variable declarations: const app = await createApp({ router })
210
- if (node.type === 'VariableDeclaration') {
211
- for (const decl of node.declarations || []) {
212
- if (decl.init) {
213
- const result = checkForCreateAppCall(decl.init, importMap);
214
- if (result)
215
- return result;
216
- }
217
- }
218
- }
219
- // Check exports: export const app = await createApp({ router })
220
- if (node.type === 'ExportNamedDeclaration' && node.declaration) {
221
- if (node.declaration.type === 'VariableDeclaration') {
222
- for (const decl of node.declaration.declarations || []) {
223
- if (decl.init) {
224
- const result = checkForCreateAppCall(decl.init, importMap);
225
- if (result)
226
- return result;
227
- }
228
- }
229
- }
230
- }
231
- }
232
- return null;
233
- }
234
- /**
235
- * Check if an expression node is a `createApp({ router })` call.
236
- * Unwraps `await` expressions.
237
- */
238
- function checkForCreateAppCall(expr, importMap) {
239
- if (!expr)
240
- return null;
241
- // Unwrap AwaitExpression: await createApp(...)
242
- if (expr.type === 'AwaitExpression' && expr.argument) {
243
- return checkForCreateAppCall(expr.argument, importMap);
244
- }
245
- // Check for createApp({ router })
246
- if (expr.type === 'CallExpression' &&
247
- expr.callee?.type === 'Identifier' &&
248
- expr.callee?.name === 'createApp') {
249
- return extractRouterFromCreateApp(expr);
250
- }
251
- return null;
252
- }
253
229
  //# sourceMappingURL=app-router-detector.js.map