@agentuity/cli 0.1.41 → 0.1.42

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 (230) hide show
  1. package/dist/agent-detection.d.ts.map +1 -1
  2. package/dist/agent-detection.js +8 -2
  3. package/dist/agent-detection.js.map +1 -1
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +9 -5
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cmd/ai/index.d.ts.map +1 -1
  8. package/dist/cmd/ai/index.js +1 -8
  9. package/dist/cmd/ai/index.js.map +1 -1
  10. package/dist/cmd/ai/prompt/version.js +1 -1
  11. package/dist/cmd/ai/prompt/version.js.map +1 -1
  12. package/dist/cmd/auth/api.d.ts.map +1 -1
  13. package/dist/cmd/auth/api.js +4 -1
  14. package/dist/cmd/auth/api.js.map +1 -1
  15. package/dist/cmd/auth/ssh/api.js +2 -2
  16. package/dist/cmd/auth/ssh/api.js.map +1 -1
  17. package/dist/cmd/build/ast.d.ts.map +1 -1
  18. package/dist/cmd/build/ast.js +14 -13
  19. package/dist/cmd/build/ast.js.map +1 -1
  20. package/dist/cmd/build/patch/index.d.ts.map +1 -1
  21. package/dist/cmd/build/patch/index.js +3 -0
  22. package/dist/cmd/build/patch/index.js.map +1 -1
  23. package/dist/cmd/build/vite/index.d.ts +1 -0
  24. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  25. package/dist/cmd/build/vite/index.js +1 -0
  26. package/dist/cmd/build/vite/index.js.map +1 -1
  27. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +34 -0
  28. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +1 -0
  29. package/dist/cmd/build/vite/public-asset-path-plugin.js +107 -0
  30. package/dist/cmd/build/vite/public-asset-path-plugin.js.map +1 -0
  31. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  32. package/dist/cmd/build/vite/registry-generator.js +14 -5
  33. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  34. package/dist/cmd/build/vite/route-discovery.js +1 -1
  35. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  36. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  37. package/dist/cmd/build/vite/vite-asset-server-config.js +11 -2
  38. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  39. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  40. package/dist/cmd/build/vite/vite-builder.js +3 -0
  41. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  42. package/dist/cmd/canary/index.d.ts.map +1 -1
  43. package/dist/cmd/canary/index.js +9 -1
  44. package/dist/cmd/canary/index.js.map +1 -1
  45. package/dist/cmd/cloud/db/create.d.ts.map +1 -1
  46. package/dist/cmd/cloud/db/create.js +2 -2
  47. package/dist/cmd/cloud/db/create.js.map +1 -1
  48. package/dist/cmd/cloud/db/delete.d.ts.map +1 -1
  49. package/dist/cmd/cloud/db/delete.js +2 -2
  50. package/dist/cmd/cloud/db/delete.js.map +1 -1
  51. package/dist/cmd/cloud/env/import.d.ts.map +1 -1
  52. package/dist/cmd/cloud/env/import.js +4 -1
  53. package/dist/cmd/cloud/env/import.js.map +1 -1
  54. package/dist/cmd/cloud/env/list.d.ts.map +1 -1
  55. package/dist/cmd/cloud/env/list.js +4 -1
  56. package/dist/cmd/cloud/env/list.js.map +1 -1
  57. package/dist/cmd/cloud/env/push.d.ts.map +1 -1
  58. package/dist/cmd/cloud/env/push.js +4 -1
  59. package/dist/cmd/cloud/env/push.js.map +1 -1
  60. package/dist/cmd/cloud/region/index.js +1 -1
  61. package/dist/cmd/cloud/region/index.js.map +1 -1
  62. package/dist/cmd/cloud/sandbox/snapshot/build.d.ts.map +1 -1
  63. package/dist/cmd/cloud/sandbox/snapshot/build.js +22 -10
  64. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  65. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
  66. package/dist/cmd/cloud/sandbox/snapshot/get.js +12 -2
  67. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
  68. package/dist/cmd/cloud/storage/create.d.ts.map +1 -1
  69. package/dist/cmd/cloud/storage/create.js +2 -2
  70. package/dist/cmd/cloud/storage/create.js.map +1 -1
  71. package/dist/cmd/cloud/storage/delete.d.ts.map +1 -1
  72. package/dist/cmd/cloud/storage/delete.js +2 -2
  73. package/dist/cmd/cloud/storage/delete.js.map +1 -1
  74. package/dist/cmd/dev/download.d.ts.map +1 -1
  75. package/dist/cmd/dev/download.js +9 -2
  76. package/dist/cmd/dev/download.js.map +1 -1
  77. package/dist/cmd/dev/index.js +1 -1
  78. package/dist/cmd/dev/index.js.map +1 -1
  79. package/dist/cmd/git/account/add.d.ts.map +1 -1
  80. package/dist/cmd/git/account/add.js +4 -3
  81. package/dist/cmd/git/account/add.js.map +1 -1
  82. package/dist/cmd/git/link.js +2 -2
  83. package/dist/cmd/git/link.js.map +1 -1
  84. package/dist/cmd/git/list.d.ts.map +1 -1
  85. package/dist/cmd/git/list.js +3 -2
  86. package/dist/cmd/git/list.js.map +1 -1
  87. package/dist/cmd/project/auth/init.js +1 -1
  88. package/dist/cmd/project/auth/init.js.map +1 -1
  89. package/dist/cmd/project/auth/shared.d.ts.map +1 -1
  90. package/dist/cmd/project/auth/shared.js +8 -3
  91. package/dist/cmd/project/auth/shared.js.map +1 -1
  92. package/dist/cmd/project/delete.d.ts.map +1 -1
  93. package/dist/cmd/project/delete.js +3 -2
  94. package/dist/cmd/project/delete.js.map +1 -1
  95. package/dist/cmd/project/reconcile.d.ts.map +1 -1
  96. package/dist/cmd/project/reconcile.js +9 -5
  97. package/dist/cmd/project/reconcile.js.map +1 -1
  98. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  99. package/dist/cmd/project/template-flow.js +15 -5
  100. package/dist/cmd/project/template-flow.js.map +1 -1
  101. package/dist/config.d.ts.map +1 -1
  102. package/dist/config.js +3 -2
  103. package/dist/config.js.map +1 -1
  104. package/dist/domain.d.ts.map +1 -1
  105. package/dist/domain.js +4 -3
  106. package/dist/domain.js.map +1 -1
  107. package/dist/internal-logger.d.ts.map +1 -1
  108. package/dist/internal-logger.js +3 -2
  109. package/dist/internal-logger.js.map +1 -1
  110. package/dist/repl.d.ts.map +1 -1
  111. package/dist/repl.js +31 -14
  112. package/dist/repl.js.map +1 -1
  113. package/dist/schema-parser.d.ts.map +1 -1
  114. package/dist/schema-parser.js +4 -1
  115. package/dist/schema-parser.js.map +1 -1
  116. package/dist/sound.d.ts.map +1 -1
  117. package/dist/sound.js +2 -1
  118. package/dist/sound.js.map +1 -1
  119. package/dist/steps.d.ts.map +1 -1
  120. package/dist/steps.js +13 -6
  121. package/dist/steps.js.map +1 -1
  122. package/dist/terminal.js +2 -0
  123. package/dist/terminal.js.map +1 -1
  124. package/dist/tsc-output-parser.d.ts +3 -0
  125. package/dist/tsc-output-parser.d.ts.map +1 -1
  126. package/dist/tsc-output-parser.js +32 -9
  127. package/dist/tsc-output-parser.js.map +1 -1
  128. package/dist/tui/prompt.d.ts.map +1 -1
  129. package/dist/tui/prompt.js +6 -2
  130. package/dist/tui/prompt.js.map +1 -1
  131. package/dist/tui.d.ts.map +1 -1
  132. package/dist/tui.js +26 -15
  133. package/dist/tui.js.map +1 -1
  134. package/dist/typescript-errors.d.ts.map +1 -1
  135. package/dist/typescript-errors.js +5 -2
  136. package/dist/typescript-errors.js.map +1 -1
  137. package/dist/utils/date.d.ts.map +1 -1
  138. package/dist/utils/date.js +5 -1
  139. package/dist/utils/date.js.map +1 -1
  140. package/dist/utils/deps.d.ts.map +1 -1
  141. package/dist/utils/deps.js +5 -3
  142. package/dist/utils/deps.js.map +1 -1
  143. package/dist/utils/detectSubagent.js +1 -1
  144. package/dist/utils/detectSubagent.js.map +1 -1
  145. package/package.json +6 -6
  146. package/src/agent-detection.ts +9 -2
  147. package/src/cli.ts +9 -5
  148. package/src/cmd/ai/index.ts +1 -8
  149. package/src/cmd/ai/prompt/version.ts +1 -1
  150. package/src/cmd/auth/api.ts +4 -1
  151. package/src/cmd/auth/ssh/api.ts +2 -2
  152. package/src/cmd/build/ast.ts +14 -13
  153. package/src/cmd/build/patch/index.ts +3 -0
  154. package/src/cmd/build/vite/index.ts +1 -0
  155. package/src/cmd/build/vite/public-asset-path-plugin.ts +137 -0
  156. package/src/cmd/build/vite/registry-generator.ts +14 -5
  157. package/src/cmd/build/vite/route-discovery.ts +1 -1
  158. package/src/cmd/build/vite/vite-asset-server-config.ts +13 -4
  159. package/src/cmd/build/vite/vite-builder.ts +3 -0
  160. package/src/cmd/canary/index.ts +9 -1
  161. package/src/cmd/cloud/db/create.ts +16 -17
  162. package/src/cmd/cloud/db/delete.ts +19 -20
  163. package/src/cmd/cloud/env/import.ts +6 -3
  164. package/src/cmd/cloud/env/list.ts +11 -9
  165. package/src/cmd/cloud/env/push.ts +6 -3
  166. package/src/cmd/cloud/region/index.ts +3 -3
  167. package/src/cmd/cloud/sandbox/snapshot/build.ts +42 -33
  168. package/src/cmd/cloud/sandbox/snapshot/get.ts +21 -15
  169. package/src/cmd/cloud/storage/create.ts +16 -17
  170. package/src/cmd/cloud/storage/delete.ts +19 -20
  171. package/src/cmd/dev/download.ts +10 -2
  172. package/src/cmd/dev/index.ts +4 -4
  173. package/src/cmd/git/account/add.ts +5 -4
  174. package/src/cmd/git/link.ts +2 -2
  175. package/src/cmd/git/list.ts +7 -6
  176. package/src/cmd/project/auth/init.ts +6 -6
  177. package/src/cmd/project/auth/shared.ts +8 -3
  178. package/src/cmd/project/delete.ts +3 -2
  179. package/src/cmd/project/reconcile.ts +9 -5
  180. package/src/cmd/project/template-flow.ts +15 -5
  181. package/src/config.ts +3 -2
  182. package/src/domain.ts +4 -3
  183. package/src/internal-logger.ts +3 -2
  184. package/src/repl.ts +27 -14
  185. package/src/schema-parser.ts +4 -1
  186. package/src/sound.ts +2 -1
  187. package/src/steps.ts +11 -6
  188. package/src/terminal.ts +2 -1
  189. package/src/tsc-output-parser.ts +61 -38
  190. package/src/tui/prompt.ts +6 -2
  191. package/src/tui.ts +26 -17
  192. package/src/typescript-errors.ts +5 -2
  193. package/src/utils/date.ts +5 -1
  194. package/src/utils/deps.ts +5 -3
  195. package/src/utils/detectSubagent.ts +1 -1
  196. package/dist/cmd/ai/cadence/index.d.ts +0 -3
  197. package/dist/cmd/ai/cadence/index.d.ts.map +0 -1
  198. package/dist/cmd/ai/cadence/index.js +0 -35
  199. package/dist/cmd/ai/cadence/index.js.map +0 -1
  200. package/dist/cmd/ai/cadence/list.d.ts +0 -3
  201. package/dist/cmd/ai/cadence/list.d.ts.map +0 -1
  202. package/dist/cmd/ai/cadence/list.js +0 -167
  203. package/dist/cmd/ai/cadence/list.js.map +0 -1
  204. package/dist/cmd/ai/cadence/pause.d.ts +0 -3
  205. package/dist/cmd/ai/cadence/pause.d.ts.map +0 -1
  206. package/dist/cmd/ai/cadence/pause.js +0 -103
  207. package/dist/cmd/ai/cadence/pause.js.map +0 -1
  208. package/dist/cmd/ai/cadence/resume.d.ts +0 -3
  209. package/dist/cmd/ai/cadence/resume.d.ts.map +0 -1
  210. package/dist/cmd/ai/cadence/resume.js +0 -106
  211. package/dist/cmd/ai/cadence/resume.js.map +0 -1
  212. package/dist/cmd/ai/cadence/status.d.ts +0 -3
  213. package/dist/cmd/ai/cadence/status.d.ts.map +0 -1
  214. package/dist/cmd/ai/cadence/status.js +0 -129
  215. package/dist/cmd/ai/cadence/status.js.map +0 -1
  216. package/dist/cmd/ai/cadence/stop.d.ts +0 -3
  217. package/dist/cmd/ai/cadence/stop.d.ts.map +0 -1
  218. package/dist/cmd/ai/cadence/stop.js +0 -107
  219. package/dist/cmd/ai/cadence/stop.js.map +0 -1
  220. package/dist/cmd/ai/cadence/util.d.ts +0 -44
  221. package/dist/cmd/ai/cadence/util.d.ts.map +0 -1
  222. package/dist/cmd/ai/cadence/util.js +0 -52
  223. package/dist/cmd/ai/cadence/util.js.map +0 -1
  224. package/src/cmd/ai/cadence/index.ts +0 -36
  225. package/src/cmd/ai/cadence/list.ts +0 -183
  226. package/src/cmd/ai/cadence/pause.ts +0 -119
  227. package/src/cmd/ai/cadence/resume.ts +0 -124
  228. package/src/cmd/ai/cadence/status.ts +0 -141
  229. package/src/cmd/ai/cadence/stop.ts +0 -124
  230. package/src/cmd/ai/cadence/util.ts +0 -86
@@ -2079,8 +2079,9 @@ export function checkRouteConflicts(content: string, workbenchEndpoint: string):
2079
2079
  node.expression.name.text === 'get'
2080
2080
  ) {
2081
2081
  // Check if first argument is the workbench endpoint
2082
- if (node.arguments.length > 0 && ts.isStringLiteral(node.arguments[0])) {
2083
- if (node.arguments[0].text === workbenchEndpoint) {
2082
+ const firstArg = node.arguments[0];
2083
+ if (node.arguments.length > 0 && firstArg && ts.isStringLiteral(firstArg)) {
2084
+ if (firstArg.text === workbenchEndpoint) {
2084
2085
  hasConflict = true;
2085
2086
  }
2086
2087
  }
@@ -2135,8 +2136,8 @@ export function extractAppStateType(content: string): string | null {
2135
2136
 
2136
2137
  if (callExpr) {
2137
2138
  // Check if it has a config object argument
2138
- if (callExpr.arguments.length > 0) {
2139
- const configArg = callExpr.arguments[0];
2139
+ const configArg = callExpr.arguments[0];
2140
+ if (callExpr.arguments.length > 0 && configArg) {
2140
2141
  if (ts.isObjectLiteralExpression(configArg)) {
2141
2142
  // Find setup property
2142
2143
  for (const prop of configArg.properties) {
@@ -2637,9 +2638,9 @@ export function analyzeWorkbench(content: string): WorkbenchAnalysis {
2637
2638
  if (ts.isIdentifier(node.name)) {
2638
2639
  // Extract configuration from the first argument (if any)
2639
2640
  let varConfig: WorkbenchConfig;
2640
- if (node.initializer.arguments.length > 0) {
2641
- const configArg = node.initializer.arguments[0];
2642
- varConfig = parseConfigObject(configArg) || { route: '/workbench' };
2641
+ const firstInitArg = node.initializer.arguments[0];
2642
+ if (node.initializer.arguments.length > 0 && firstInitArg) {
2643
+ varConfig = parseConfigObject(firstInitArg) || { route: '/workbench' };
2643
2644
  } else {
2644
2645
  // Default config if no arguments provided
2645
2646
  varConfig = { route: '/workbench' };
@@ -2655,10 +2656,10 @@ export function analyzeWorkbench(content: string): WorkbenchAnalysis {
2655
2656
  node.expression.text === 'createApp' &&
2656
2657
  node.arguments.length > 0
2657
2658
  ) {
2658
- const configArg = node.arguments[0];
2659
- if (ts.isObjectLiteralExpression(configArg)) {
2659
+ const createAppConfigArg = node.arguments[0];
2660
+ if (createAppConfigArg && ts.isObjectLiteralExpression(createAppConfigArg)) {
2660
2661
  // Find the services property
2661
- for (const prop of configArg.properties) {
2662
+ for (const prop of createAppConfigArg.properties) {
2662
2663
  if (
2663
2664
  ts.isPropertyAssignment(prop) &&
2664
2665
  ts.isIdentifier(prop.name) &&
@@ -2740,9 +2741,9 @@ export function analyzeWorkbench(content: string): WorkbenchAnalysis {
2740
2741
  node.expression.text === 'createApp' &&
2741
2742
  node.arguments.length > 0
2742
2743
  ) {
2743
- const configArg = node.arguments[0];
2744
- if (ts.isObjectLiteralExpression(configArg)) {
2745
- for (const prop of configArg.properties) {
2744
+ const checkConfigArg = node.arguments[0];
2745
+ if (checkConfigArg && ts.isObjectLiteralExpression(checkConfigArg)) {
2746
+ for (const prop of checkConfigArg.properties) {
2746
2747
  if (
2747
2748
  ts.isPropertyAssignment(prop) &&
2748
2749
  ts.isIdentifier(prop.name) &&
@@ -27,6 +27,9 @@ export async function applyPatch(
27
27
  if (patch.functions) {
28
28
  for (const fn of Object.keys(patch.functions)) {
29
29
  const mod = patch.functions[fn];
30
+ if (!mod) {
31
+ continue;
32
+ }
30
33
  let fnname = `function ${fn}`;
31
34
  let index = contents.indexOf(fnname);
32
35
  let isConstVariable = false;
@@ -12,6 +12,7 @@ import { loadAgentuityConfig, getWorkbenchConfig } from './config-loader';
12
12
 
13
13
  // Re-export plugins
14
14
  export { browserEnvPlugin } from './browser-env-plugin';
15
+ export { publicAssetPathPlugin } from './public-asset-path-plugin';
15
16
 
16
17
  export interface AgentuityPluginOptions {
17
18
  dev?: boolean;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Vite plugin to fix incorrect public asset paths
3
+ *
4
+ * Developers sometimes accidentally use source paths or relative paths instead
5
+ * of the correct absolute production path '/public/...'. This plugin:
6
+ *
7
+ * 1. During build: Rewrites incorrect paths to '/public/*' in the bundle
8
+ * 2. During dev: Warns about incorrect paths so developers can fix them
9
+ *
10
+ * Patterns handled:
11
+ * - '/src/web/public/...' → '/public/...'
12
+ * - './src/web/public/...' → '/public/...'
13
+ * - 'src/web/public/...' → '/public/...'
14
+ * - './public/...' → '/public/...'
15
+ */
16
+
17
+ import type { Plugin } from 'vite';
18
+
19
+ export interface PublicAssetPathPluginOptions {
20
+ /** Whether to show warnings in dev mode (default: true) */
21
+ warnInDev?: boolean;
22
+ }
23
+
24
+ interface PathPattern {
25
+ regex: RegExp;
26
+ description: string;
27
+ }
28
+
29
+ /**
30
+ * Create fresh regex instances for each transform call
31
+ * (RegExp with global flag maintains state via lastIndex)
32
+ */
33
+ function createPatterns(): PathPattern[] {
34
+ return [
35
+ // '/src/web/public/...' or './src/web/public/...' or 'src/web/public/...'
36
+ {
37
+ regex: /(['"`])(?:\.?\/)?src\/web\/public\//g,
38
+ description: 'src/web/public/',
39
+ },
40
+ // './public/...' (relative public path - should be absolute)
41
+ {
42
+ regex: /(['"`])\.\/public\//g,
43
+ description: './public/',
44
+ },
45
+ ];
46
+ }
47
+
48
+ /**
49
+ * Vite plugin that fixes incorrect public asset paths
50
+ *
51
+ * @example
52
+ * // In vite config:
53
+ * plugins: [publicAssetPathPlugin()]
54
+ *
55
+ * // Transforms:
56
+ * // '/src/web/public/logo.svg' → '/public/logo.svg'
57
+ * // './src/web/public/logo.svg' → '/public/logo.svg'
58
+ * // './public/logo.svg' → '/public/logo.svg'
59
+ */
60
+ export function publicAssetPathPlugin(options: PublicAssetPathPluginOptions = {}): Plugin {
61
+ const { warnInDev = true } = options;
62
+
63
+ let isDev = false;
64
+ const warnedFiles = new Map<string, Set<string>>(); // file -> set of patterns warned
65
+
66
+ return {
67
+ name: 'agentuity:public-asset-path',
68
+
69
+ configResolved(config) {
70
+ isDev = config.command === 'serve';
71
+ },
72
+
73
+ transform(code, id) {
74
+ // Only transform files in src/web (browser code)
75
+ if (!id.includes('/src/web/') && !id.includes('\\src\\web\\')) {
76
+ return null;
77
+ }
78
+
79
+ // Quick check: does the code contain any patterns we care about?
80
+ const hasIncorrectPaths = code.includes('src/web/public/') || code.includes('./public/');
81
+
82
+ if (!hasIncorrectPaths) {
83
+ return null;
84
+ }
85
+
86
+ // Create fresh patterns for this transform
87
+ const patterns = createPatterns();
88
+
89
+ // Track which patterns were found for warnings
90
+ const foundPatterns: string[] = [];
91
+ let transformed = code;
92
+
93
+ for (const { regex, description } of patterns) {
94
+ if (regex.test(transformed)) {
95
+ foundPatterns.push(description);
96
+
97
+ // Create a fresh regex for the replacement (test() consumed the previous one)
98
+ const replaceRegex = new RegExp(regex.source, regex.flags);
99
+ transformed = transformed.replace(replaceRegex, '$1/public/');
100
+ }
101
+ }
102
+
103
+ // In dev mode, optionally warn but don't transform (Vite serves from source paths)
104
+ if (isDev) {
105
+ if (warnInDev && foundPatterns.length > 0) {
106
+ const fileWarnings = warnedFiles.get(id) || new Set();
107
+ const newWarnings = foundPatterns.filter((p) => !fileWarnings.has(p));
108
+
109
+ if (newWarnings.length > 0) {
110
+ for (const p of newWarnings) {
111
+ fileWarnings.add(p);
112
+ }
113
+ warnedFiles.set(id, fileWarnings);
114
+
115
+ this.warn(
116
+ `Found incorrect asset path(s) in ${id}:\n` +
117
+ newWarnings.map((p) => ` - '${p}' should be '/public/'`).join('\n') +
118
+ `\nUse absolute '/public/...' paths for production compatibility.`
119
+ );
120
+ }
121
+ }
122
+ // In dev mode, never transform - Vite serves from source paths
123
+ return null;
124
+ }
125
+
126
+ // In build mode, return transformed code if changed
127
+ if (transformed !== code) {
128
+ return {
129
+ code: transformed,
130
+ map: null,
131
+ };
132
+ }
133
+
134
+ return null;
135
+ },
136
+ };
137
+ }
@@ -374,7 +374,11 @@ function generateRPCRegistryType(
374
374
 
375
375
  // Add path segments - sanitize for valid TypeScript property names
376
376
  for (let i = 0; i < pathParts.length; i++) {
377
- const part = sanitizePathSegment(pathParts[i]);
377
+ const rawPart = pathParts[i];
378
+ if (!rawPart) {
379
+ continue;
380
+ }
381
+ const part = sanitizePathSegment(rawPart);
378
382
  // Skip empty segments (e.g., wildcards like '*' that sanitize to '')
379
383
  if (!part) {
380
384
  continue;
@@ -561,7 +565,10 @@ function generateRPCRuntimeMetadata(
561
565
  const sorted: MetadataNode = {};
562
566
  for (const key of Object.keys(obj).sort()) {
563
567
  const value = obj[key];
564
- if (value && typeof value === 'object' && !('type' in value)) {
568
+ if (value === undefined) {
569
+ continue;
570
+ }
571
+ if (typeof value === 'object' && !('type' in value)) {
565
572
  sorted[key] = sortObject(value as MetadataNode);
566
573
  } else {
567
574
  sorted[key] = value;
@@ -640,9 +647,11 @@ export async function generateRouteRegistry(
640
647
  const match = route.agentImportPath.match(/@agent[s]?\/([^/]+)/);
641
648
  if (match) {
642
649
  const agentName = match[1];
643
- const metadata = agentNameMap.get(agentName);
644
- if (metadata) {
645
- agentMetadataMap.set(route.agentVariable, metadata);
650
+ if (agentName) {
651
+ const metadata = agentNameMap.get(agentName);
652
+ if (metadata) {
653
+ agentMetadataMap.set(route.agentVariable, metadata);
654
+ }
646
655
  }
647
656
  }
648
657
  }
@@ -213,7 +213,7 @@ export function detectRouteConflicts(
213
213
  // Check for exact duplicates
214
214
  for (const [methodPath, routeList] of methodPathMap.entries()) {
215
215
  if (routeList.length > 1) {
216
- const [method] = methodPath.split(' ', 2);
216
+ const [method = 'UNKNOWN'] = methodPath.split(' ', 2);
217
217
  conflicts.push({
218
218
  type: 'duplicate',
219
219
  routes: routeList.map((r) => ({ method, path: r.path, filename: r.filename })),
@@ -49,10 +49,16 @@ export async function generateAssetServerConfig(
49
49
  const tsconfig = JSON.parse(await Bun.file(tsconfigPath).text());
50
50
  const paths = tsconfig?.compilerOptions?.paths || {};
51
51
  alias = Object.fromEntries(
52
- Object.entries(paths).map(([key, value]) => {
53
- const pathArray = value as string[];
54
- return [key.replace('/*', ''), join(rootDir, pathArray[0].replace('/*', ''))];
55
- })
52
+ Object.entries(paths)
53
+ .filter(([, value]) => {
54
+ const pathArray = value as string[];
55
+ return pathArray.length > 0 && pathArray[0] !== undefined;
56
+ })
57
+ .map(([key, value]) => {
58
+ const pathArray = value as string[];
59
+ const firstPath = pathArray[0] ?? '';
60
+ return [key.replace('/*', ''), join(rootDir, firstPath.replace('/*', ''))];
61
+ })
56
62
  );
57
63
  } catch {
58
64
  // No tsconfig or no paths - that's fine
@@ -131,6 +137,7 @@ export async function generateAssetServerConfig(
131
137
  }
132
138
  const reactPlugin = (await import(reactPluginPath)).default();
133
139
  const { browserEnvPlugin } = await import('./browser-env-plugin');
140
+ const { publicAssetPathPlugin } = await import('./public-asset-path-plugin');
134
141
  return [
135
142
  // User-defined plugins from agentuity.config.ts (e.g., Tailwind CSS)
136
143
  ...userPlugins,
@@ -138,6 +145,8 @@ export async function generateAssetServerConfig(
138
145
  reactPlugin,
139
146
  // Browser env plugin to map process.env to import.meta.env
140
147
  browserEnvPlugin(),
148
+ // Warn about incorrect public asset paths in dev mode
149
+ publicAssetPathPlugin({ warnInDev: true }),
141
150
  ];
142
151
  })(),
143
152
 
@@ -11,6 +11,7 @@ import type { InlineConfig, Plugin } from 'vite';
11
11
  import type { Logger, DeployOptions } from '../../../types';
12
12
  import { browserEnvPlugin } from './browser-env-plugin';
13
13
  import { beaconPlugin } from './beacon-plugin';
14
+ import { publicAssetPathPlugin } from './public-asset-path-plugin';
14
15
  import type { BuildReportCollector } from '../../../build-report';
15
16
 
16
17
  /**
@@ -153,6 +154,8 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
153
154
  const plugins = [
154
155
  react(),
155
156
  browserEnvPlugin(),
157
+ // Fix incorrect public asset paths (e.g., '/src/web/public/...' → '/public/...')
158
+ publicAssetPathPlugin(),
156
159
  flattenHtmlOutputPlugin(clientOutDir),
157
160
  // Emit analytics beacon as hashed CDN asset (prod builds only)
158
161
  beaconPlugin({ enabled: analyticsEnabled && !dev }),
@@ -58,6 +58,14 @@ export const command = createCommand({
58
58
 
59
59
  // Get target from parsed args, but get forward args from raw argv
60
60
  const target = args.args[0];
61
+ if (!target) {
62
+ tui.error('Usage: agentuity canary <version> [commands...]');
63
+ return {
64
+ executed: false,
65
+ version: '',
66
+ message: 'No target specified',
67
+ };
68
+ }
61
69
  const targetIndex = canaryIndex >= 0 ? argv.indexOf(target, canaryIndex) : -1;
62
70
  const forwardArgs = targetIndex >= 0 ? argv.slice(targetIndex + 1) : args.args.slice(1);
63
71
 
@@ -79,7 +87,7 @@ export const command = createCommand({
79
87
  tarballUrl = target;
80
88
  // Extract version from URL if possible
81
89
  const match = target.match(/agentuity-cli-(\d+\.\d+\.\d+-[a-f0-9]+)\.tgz/);
82
- version = match ? match[1] : 'custom';
90
+ version = match?.[1] ?? 'custom';
83
91
  } else {
84
92
  // Version string - construct URL
85
93
  version = target;
@@ -74,25 +74,24 @@ export const createSubcommand = defineSubcommand({
74
74
  ]);
75
75
  },
76
76
  });
77
- if (created.length > 0) {
78
- const resource = created[0];
79
-
80
- // Write environment variables to .env if running inside a project
81
- if (ctx.projectDir && resource.env && Object.keys(resource.env).length > 0) {
82
- await addResourceEnvVars(ctx.projectDir, resource.env);
83
- if (!options.json) {
84
- tui.info('Environment variables written to .env');
85
- }
86
- }
87
-
77
+ const resource = created[0];
78
+ if (resource) {
79
+ // Write environment variables to .env if running inside a project
80
+ if (ctx.projectDir && resource.env && Object.keys(resource.env).length > 0) {
81
+ await addResourceEnvVars(ctx.projectDir, resource.env);
88
82
  if (!options.json) {
89
- tui.success(`Created database: ${tui.bold(resource.name)}`);
83
+ tui.info('Environment variables written to .env');
90
84
  }
91
- return {
92
- success: true,
93
- name: resource.name,
94
- };
95
- } else {
85
+ }
86
+
87
+ if (!options.json) {
88
+ tui.success(`Created database: ${tui.bold(resource.name)}`);
89
+ }
90
+ return {
91
+ success: true,
92
+ name: resource.name,
93
+ };
94
+ } else {
96
95
  tui.fatal('Failed to create database');
97
96
  }
98
97
  } catch (ex) {
@@ -178,28 +178,27 @@ export const deleteSubcommand = createSubcommand({
178
178
  },
179
179
  });
180
180
 
181
- if (deleted.length > 0) {
182
- const resource = deleted[0];
183
-
184
- // Clear cache entry for deleted database
185
- await deleteResourceRegion('db', profileName, resource.name);
186
-
187
- // Remove env vars from .env if running inside a project
188
- if (ctx.projectDir && resource.env_keys.length > 0) {
189
- await removeResourceEnvVars(ctx.projectDir, resource.env_keys);
190
- if (!options.json) {
191
- tui.info(`Removed ${resource.env_keys.join(', ')} from .env`);
192
- }
193
- }
194
-
181
+ const resource = deleted[0];
182
+ if (resource) {
183
+ // Clear cache entry for deleted database
184
+ await deleteResourceRegion('db', profileName, resource.name);
185
+
186
+ // Remove env vars from .env if running inside a project
187
+ if (ctx.projectDir && resource.env_keys.length > 0) {
188
+ await removeResourceEnvVars(ctx.projectDir, resource.env_keys);
195
189
  if (!options.json) {
196
- tui.success(`Deleted database: ${tui.bold(resource.name)}`);
190
+ tui.info(`Removed ${resource.env_keys.join(', ')} from .env`);
197
191
  }
198
- return {
199
- success: true,
200
- name: resource.name,
201
- };
202
- } else {
192
+ }
193
+
194
+ if (!options.json) {
195
+ tui.success(`Deleted database: ${tui.bold(resource.name)}`);
196
+ }
197
+ return {
198
+ success: true,
199
+ name: resource.name,
200
+ };
201
+ } else {
203
202
  tui.error('Failed to delete database');
204
203
  return { success: false, name: dbName };
205
204
  }
@@ -113,11 +113,14 @@ export const importSubcommand = createSubcommand({
113
113
  tui.warning(
114
114
  `Moving public variables to env: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
115
115
  );
116
- for (const key of publicSecretKeys) {
117
- delete secrets[key];
118
- env[key] = filteredVars[key];
116
+ for (const key of publicSecretKeys) {
117
+ delete secrets[key];
118
+ const value = filteredVars[key];
119
+ if (value !== undefined) {
120
+ env[key] = value;
119
121
  }
120
122
  }
123
+ }
121
124
 
122
125
  const envCount = Object.keys(env).length;
123
126
  const secretCount = Object.keys(secrets).length;
@@ -168,15 +168,17 @@ export const listSubcommand = createSubcommand({
168
168
  const sortedKeys = Object.keys(result).sort();
169
169
  const shouldMask = opts?.mask !== false;
170
170
 
171
- for (const key of sortedKeys) {
172
- const { value, secret, scope } = result[key];
173
- const displayValue = shouldMask && secret ? tui.maskSecret(value) : value;
174
- const typeIndicator = secret ? ' [secret]' : '';
175
- const scopeIndicator = !useOrgScope ? ` [${scope}]` : '';
176
- console.log(
177
- `${tui.bold(key)}=${displayValue}${tui.muted(typeIndicator + scopeIndicator)}`
178
- );
179
- }
171
+ for (const key of sortedKeys) {
172
+ const entry = result[key];
173
+ if (!entry) continue;
174
+ const { value, secret, scope } = entry;
175
+ const displayValue = shouldMask && secret ? tui.maskSecret(value) : value;
176
+ const typeIndicator = secret ? ' [secret]' : '';
177
+ const scopeIndicator = !useOrgScope ? ` [${scope}]` : '';
178
+ console.log(
179
+ `${tui.bold(key)}=${displayValue}${tui.muted(typeIndicator + scopeIndicator)}`
180
+ );
181
+ }
180
182
  }
181
183
  }
182
184
 
@@ -80,11 +80,14 @@ export const pushSubcommand = createSubcommand({
80
80
  tui.warning(
81
81
  `Moving public variables to env: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
82
82
  );
83
- for (const key of publicSecretKeys) {
84
- delete secrets[key];
85
- env[key] = filteredEnv[key];
83
+ for (const key of publicSecretKeys) {
84
+ delete secrets[key];
85
+ const value = filteredEnv[key];
86
+ if (value !== undefined) {
87
+ env[key] = value;
86
88
  }
87
89
  }
90
+ }
88
91
 
89
92
  if (useOrgScope) {
90
93
  // Organization scope
@@ -45,9 +45,9 @@ const selectCommand = createSubcommand({
45
45
  );
46
46
  }
47
47
 
48
- if (regions.length === 1) {
49
- selectedRegion = regions[0].region;
50
- } else {
48
+ if (regions.length === 1 && regions[0]) {
49
+ selectedRegion = regions[0].region;
50
+ } else {
51
51
  const response = await tui.createPrompt().select<string>({
52
52
  message: 'Select a default region',
53
53
  options: regions.map((r) => ({
@@ -65,23 +65,26 @@ function buildFileTree(files: SnapshotFileInfo[]): TreeNode {
65
65
  const parts = file.path.split('/');
66
66
  let current = root;
67
67
 
68
- for (let i = 0; i < parts.length; i++) {
69
- const part = parts[i];
70
- if (!current.children.has(part)) {
71
- current.children.set(part, {
72
- name: part,
73
- isFile: i === parts.length - 1,
74
- children: new Map(),
75
- });
76
- }
77
- current = current.children.get(part)!;
68
+ for (let i = 0; i < parts.length; i++) {
69
+ const part = parts[i];
70
+ if (!part) continue;
71
+ if (!current.children.has(part)) {
72
+ current.children.set(part, {
73
+ name: part,
74
+ isFile: i === parts.length - 1,
75
+ children: new Map(),
76
+ });
77
+ }
78
+ const child = current.children.get(part);
79
+ if (!child) continue;
80
+ current = child;
78
81
 
79
- if (i === parts.length - 1) {
80
- current.size = file.size;
81
- current.isFile = true;
82
- }
82
+ if (i === parts.length - 1) {
83
+ current.size = file.size;
84
+ current.isFile = true;
83
85
  }
84
86
  }
87
+ }
85
88
 
86
89
  return root;
87
90
  }
@@ -100,7 +103,9 @@ function printTreeNode(node: TreeNode, prefix: string): void {
100
103
  });
101
104
 
102
105
  for (let i = 0; i < entries.length; i++) {
103
- const [, child] = entries[i];
106
+ const entry = entries[i];
107
+ if (!entry) continue;
108
+ const [, child] = entry;
104
109
  const isLast = i === entries.length - 1;
105
110
  const connector = tui.muted(isLast ? '└── ' : '├── ');
106
111
  const sizeStr =
@@ -146,17 +151,21 @@ function substituteVariables(
146
151
 
147
152
  for (const [key, value] of Object.entries(values)) {
148
153
  let substituted = value;
149
- let match: RegExpExecArray | null;
150
154
 
151
155
  varPattern.lastIndex = 0;
152
- while ((match = varPattern.exec(value)) !== null) {
156
+ let match = varPattern.exec(value);
157
+ while (match !== null) {
153
158
  const varName = match[1];
154
- if (!(varName in variables)) {
159
+ if (!varName || !(varName in variables)) {
155
160
  throw new Error(
156
161
  `Variable "\${${varName}}" in "${key}" is not defined. Use --${flagName} ${varName}=value to provide it.`
157
162
  );
158
163
  }
159
- substituted = substituted.replace(match[0], variables[varName]);
164
+ const varValue = variables[varName];
165
+ if (varValue !== undefined) {
166
+ substituted = substituted.replace(match[0], varValue);
167
+ }
168
+ match = varPattern.exec(value);
160
169
  }
161
170
  result[key] = substituted;
162
171
  }
@@ -638,15 +647,15 @@ export const buildSubcommand = createCommand({
638
647
  }
639
648
  }
640
649
 
641
- if (finalEnv && Object.keys(finalEnv).length > 0) {
642
- console.log('');
643
- tui.info('Environment:');
644
- for (const key of Object.keys(finalEnv)) {
645
- console.log(` ${tui.muted('•')} ${key}=${tui.maskSecret(finalEnv[key])}`);
646
- }
650
+ if (finalEnv && Object.keys(finalEnv).length > 0) {
651
+ console.log('');
652
+ tui.info('Environment:');
653
+ for (const [envKey, envValue] of Object.entries(finalEnv)) {
654
+ console.log(` ${tui.muted('•')} ${envKey}=${tui.maskSecret(envValue)}`);
647
655
  }
656
+ }
648
657
 
649
- if (fileList.length > 0) {
658
+ if (fileList.length > 0) {
650
659
  console.log('');
651
660
  tui.info('Files:');
652
661
  printFileTree(fileList);
@@ -940,15 +949,15 @@ export const buildSubcommand = createCommand({
940
949
  }
941
950
  }
942
951
 
943
- if (finalEnv && Object.keys(finalEnv).length > 0) {
944
- console.log('');
945
- tui.info('Environment:');
946
- for (const key of Object.keys(finalEnv)) {
947
- console.log(` ${tui.muted('•')} ${key}=${tui.maskSecret(finalEnv[key])}`);
948
- }
952
+ if (finalEnv && Object.keys(finalEnv).length > 0) {
953
+ console.log('');
954
+ tui.info('Environment:');
955
+ for (const [envKey, envValue] of Object.entries(finalEnv)) {
956
+ console.log(` ${tui.muted('•')} ${envKey}=${tui.maskSecret(envValue)}`);
949
957
  }
958
+ }
950
959
 
951
- if (finalMetadata && Object.keys(finalMetadata).length > 0) {
960
+ if (finalMetadata && Object.keys(finalMetadata).length > 0) {
952
961
  console.log('');
953
962
  tui.info('Metadata:');
954
963
  for (const key of Object.keys(finalMetadata)) {