@agentuity/cli 0.0.101 → 0.0.103

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 (210) hide show
  1. package/AGENTS.md +19 -188
  2. package/bin/cli.ts +21 -14
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +41 -12
  5. package/dist/cli.js.map +1 -1
  6. package/dist/cmd/ai/index.d.ts.map +1 -1
  7. package/dist/cmd/ai/index.js +6 -1
  8. package/dist/cmd/ai/index.js.map +1 -1
  9. package/dist/cmd/ai/prompt/agent.d.ts +7 -0
  10. package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
  11. package/dist/cmd/ai/prompt/agent.js +12 -323
  12. package/dist/cmd/ai/prompt/agent.js.map +1 -1
  13. package/dist/cmd/ai/prompt/api.d.ts +7 -0
  14. package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
  15. package/dist/cmd/ai/prompt/api.js +12 -260
  16. package/dist/cmd/ai/prompt/api.js.map +1 -1
  17. package/dist/cmd/ai/prompt/version.d.ts +35 -0
  18. package/dist/cmd/ai/prompt/version.d.ts.map +1 -0
  19. package/dist/cmd/ai/prompt/version.js +55 -0
  20. package/dist/cmd/ai/prompt/version.js.map +1 -0
  21. package/dist/cmd/ai/prompt/web.d.ts +7 -0
  22. package/dist/cmd/ai/prompt/web.d.ts.map +1 -1
  23. package/dist/cmd/ai/prompt/web.js +12 -283
  24. package/dist/cmd/ai/prompt/web.js.map +1 -1
  25. package/dist/cmd/ai/skills/generate.d.ts +3 -0
  26. package/dist/cmd/ai/skills/generate.d.ts.map +1 -0
  27. package/dist/cmd/ai/skills/generate.js +65 -0
  28. package/dist/cmd/ai/skills/generate.js.map +1 -0
  29. package/dist/cmd/ai/skills/generator.d.ts +4 -0
  30. package/dist/cmd/ai/skills/generator.d.ts.map +1 -0
  31. package/dist/cmd/ai/skills/generator.js +402 -0
  32. package/dist/cmd/ai/skills/generator.js.map +1 -0
  33. package/dist/cmd/ai/skills/index.d.ts +4 -0
  34. package/dist/cmd/ai/skills/index.d.ts.map +1 -0
  35. package/dist/cmd/ai/skills/index.js +21 -0
  36. package/dist/cmd/ai/skills/index.js.map +1 -0
  37. package/dist/cmd/auth/signup.d.ts.map +1 -1
  38. package/dist/cmd/auth/signup.js +1 -0
  39. package/dist/cmd/auth/signup.js.map +1 -1
  40. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  41. package/dist/cmd/build/entry-generator.js +40 -5
  42. package/dist/cmd/build/entry-generator.js.map +1 -1
  43. package/dist/cmd/build/vite/bun-dev-server.d.ts +7 -1
  44. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  45. package/dist/cmd/build/vite/bun-dev-server.js +30 -26
  46. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  47. package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
  48. package/dist/cmd/build/vite/metadata-generator.js +58 -7
  49. package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
  50. package/dist/cmd/build/vite/prompt-generator.d.ts +23 -0
  51. package/dist/cmd/build/vite/prompt-generator.d.ts.map +1 -0
  52. package/dist/cmd/build/vite/prompt-generator.js +123 -0
  53. package/dist/cmd/build/vite/prompt-generator.js.map +1 -0
  54. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  55. package/dist/cmd/build/vite/registry-generator.js +28 -11
  56. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  57. package/dist/cmd/build/vite/server-bundler.d.ts +4 -0
  58. package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
  59. package/dist/cmd/build/vite/server-bundler.js +45 -16
  60. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  61. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  62. package/dist/cmd/build/vite/vite-asset-server-config.js +4 -0
  63. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  64. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  65. package/dist/cmd/build/vite/vite-builder.js +99 -87
  66. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  67. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  68. package/dist/cmd/cloud/deploy.js +80 -27
  69. package/dist/cmd/cloud/deploy.js.map +1 -1
  70. package/dist/cmd/cloud/keyvalue/create-namespace.d.ts.map +1 -1
  71. package/dist/cmd/cloud/keyvalue/create-namespace.js +3 -1
  72. package/dist/cmd/cloud/keyvalue/create-namespace.js.map +1 -1
  73. package/dist/cmd/cloud/keyvalue/delete-namespace.d.ts.map +1 -1
  74. package/dist/cmd/cloud/keyvalue/delete-namespace.js +3 -1
  75. package/dist/cmd/cloud/keyvalue/delete-namespace.js.map +1 -1
  76. package/dist/cmd/cloud/keyvalue/delete.d.ts.map +1 -1
  77. package/dist/cmd/cloud/keyvalue/delete.js +3 -1
  78. package/dist/cmd/cloud/keyvalue/delete.js.map +1 -1
  79. package/dist/cmd/cloud/keyvalue/set.d.ts.map +1 -1
  80. package/dist/cmd/cloud/keyvalue/set.js +4 -2
  81. package/dist/cmd/cloud/keyvalue/set.js.map +1 -1
  82. package/dist/cmd/cloud/stream/get.d.ts.map +1 -1
  83. package/dist/cmd/cloud/stream/get.js +2 -13
  84. package/dist/cmd/cloud/stream/get.js.map +1 -1
  85. package/dist/cmd/cloud/vector/delete-namespace.d.ts +3 -0
  86. package/dist/cmd/cloud/vector/delete-namespace.d.ts.map +1 -0
  87. package/dist/cmd/cloud/vector/delete-namespace.js +77 -0
  88. package/dist/cmd/cloud/vector/delete-namespace.js.map +1 -0
  89. package/dist/cmd/cloud/vector/index.d.ts.map +1 -1
  90. package/dist/cmd/cloud/vector/index.js +21 -4
  91. package/dist/cmd/cloud/vector/index.js.map +1 -1
  92. package/dist/cmd/cloud/vector/list-namespaces.d.ts +3 -0
  93. package/dist/cmd/cloud/vector/list-namespaces.d.ts.map +1 -0
  94. package/dist/cmd/cloud/vector/list-namespaces.js +42 -0
  95. package/dist/cmd/cloud/vector/list-namespaces.js.map +1 -0
  96. package/dist/cmd/cloud/vector/stats.d.ts +3 -0
  97. package/dist/cmd/cloud/vector/stats.d.ts.map +1 -0
  98. package/dist/cmd/cloud/vector/stats.js +142 -0
  99. package/dist/cmd/cloud/vector/stats.js.map +1 -0
  100. package/dist/cmd/cloud/vector/upsert.d.ts +3 -0
  101. package/dist/cmd/cloud/vector/upsert.d.ts.map +1 -0
  102. package/dist/cmd/cloud/vector/upsert.js +192 -0
  103. package/dist/cmd/cloud/vector/upsert.js.map +1 -0
  104. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  105. package/dist/cmd/dev/file-watcher.js +90 -31
  106. package/dist/cmd/dev/file-watcher.js.map +1 -1
  107. package/dist/cmd/dev/index.d.ts.map +1 -1
  108. package/dist/cmd/dev/index.js +244 -64
  109. package/dist/cmd/dev/index.js.map +1 -1
  110. package/dist/cmd/dev/skills.d.ts +10 -0
  111. package/dist/cmd/dev/skills.d.ts.map +1 -0
  112. package/dist/cmd/dev/skills.js +57 -0
  113. package/dist/cmd/dev/skills.js.map +1 -0
  114. package/dist/cmd/dev/sync.js +7 -7
  115. package/dist/cmd/dev/sync.js.map +1 -1
  116. package/dist/cmd/index.d.ts.map +1 -1
  117. package/dist/cmd/index.js +1 -0
  118. package/dist/cmd/index.js.map +1 -1
  119. package/dist/cmd/project/create.d.ts.map +1 -1
  120. package/dist/cmd/project/create.js +3 -0
  121. package/dist/cmd/project/create.js.map +1 -1
  122. package/dist/cmd/project/template-flow.d.ts +1 -0
  123. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  124. package/dist/cmd/project/template-flow.js +30 -5
  125. package/dist/cmd/project/template-flow.js.map +1 -1
  126. package/dist/cmd/setup/index.d.ts.map +1 -1
  127. package/dist/cmd/setup/index.js +1 -0
  128. package/dist/cmd/setup/index.js.map +1 -1
  129. package/dist/cmd/upgrade/index.d.ts +15 -0
  130. package/dist/cmd/upgrade/index.d.ts.map +1 -1
  131. package/dist/cmd/upgrade/index.js +59 -4
  132. package/dist/cmd/upgrade/index.js.map +1 -1
  133. package/dist/domain.d.ts +45 -0
  134. package/dist/domain.d.ts.map +1 -0
  135. package/dist/domain.js +200 -0
  136. package/dist/domain.js.map +1 -0
  137. package/dist/schema-generator.d.ts +2 -0
  138. package/dist/schema-generator.d.ts.map +1 -1
  139. package/dist/schema-generator.js +18 -0
  140. package/dist/schema-generator.js.map +1 -1
  141. package/dist/steps.d.ts +1 -1
  142. package/dist/steps.d.ts.map +1 -1
  143. package/dist/steps.js +16 -5
  144. package/dist/steps.js.map +1 -1
  145. package/dist/tui/prompt.d.ts +1 -2
  146. package/dist/tui/prompt.d.ts.map +1 -1
  147. package/dist/tui/prompt.js +8 -4
  148. package/dist/tui/prompt.js.map +1 -1
  149. package/dist/tui.d.ts +16 -0
  150. package/dist/tui.d.ts.map +1 -1
  151. package/dist/tui.js +23 -2
  152. package/dist/tui.js.map +1 -1
  153. package/dist/types.d.ts +9 -2
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/types.js +3 -3
  156. package/dist/types.js.map +1 -1
  157. package/package.json +4 -4
  158. package/src/cli.ts +47 -12
  159. package/src/cmd/ai/index.ts +6 -1
  160. package/src/cmd/ai/prompt/agent.md +306 -0
  161. package/src/cmd/ai/prompt/agent.ts +12 -322
  162. package/src/cmd/ai/prompt/api.md +360 -0
  163. package/src/cmd/ai/prompt/api.ts +13 -260
  164. package/src/cmd/ai/prompt/version.ts +61 -0
  165. package/src/cmd/ai/prompt/web.md +509 -0
  166. package/src/cmd/ai/prompt/web.ts +12 -282
  167. package/src/cmd/ai/skills/generate.ts +75 -0
  168. package/src/cmd/ai/skills/generator.ts +519 -0
  169. package/src/cmd/ai/skills/index.ts +23 -0
  170. package/src/cmd/auth/signup.ts +1 -0
  171. package/src/cmd/build/entry-generator.ts +43 -7
  172. package/src/cmd/build/vite/bun-dev-server.ts +31 -28
  173. package/src/cmd/build/vite/metadata-generator.ts +73 -7
  174. package/src/cmd/build/vite/prompt-generator.ts +169 -0
  175. package/src/cmd/build/vite/registry-generator.ts +33 -10
  176. package/src/cmd/build/vite/server-bundler.ts +53 -22
  177. package/src/cmd/build/vite/vite-asset-server-config.ts +5 -0
  178. package/src/cmd/build/vite/vite-builder.ts +107 -87
  179. package/src/cmd/cloud/deploy.ts +103 -31
  180. package/src/cmd/cloud/keyvalue/create-namespace.ts +3 -1
  181. package/src/cmd/cloud/keyvalue/delete-namespace.ts +3 -1
  182. package/src/cmd/cloud/keyvalue/delete.ts +3 -1
  183. package/src/cmd/cloud/keyvalue/set.ts +4 -2
  184. package/src/cmd/cloud/stream/get.ts +2 -9
  185. package/src/cmd/cloud/vector/delete-namespace.ts +89 -0
  186. package/src/cmd/cloud/vector/index.ts +21 -4
  187. package/src/cmd/cloud/vector/list-namespaces.ts +46 -0
  188. package/src/cmd/cloud/vector/stats.ts +160 -0
  189. package/src/cmd/cloud/vector/upsert.ts +216 -0
  190. package/src/cmd/dev/file-watcher.ts +101 -32
  191. package/src/cmd/dev/index.ts +343 -115
  192. package/src/cmd/dev/skills.ts +82 -0
  193. package/src/cmd/dev/sync.ts +7 -7
  194. package/src/cmd/index.ts +1 -0
  195. package/src/cmd/project/create.ts +3 -0
  196. package/src/cmd/project/template-flow.ts +37 -5
  197. package/src/cmd/setup/index.ts +1 -0
  198. package/src/cmd/upgrade/index.ts +68 -4
  199. package/src/domain.ts +273 -0
  200. package/src/schema-generator.ts +23 -0
  201. package/src/steps.ts +16 -5
  202. package/src/tui/prompt.ts +11 -5
  203. package/src/tui.ts +21 -2
  204. package/src/types/md.d.ts +8 -0
  205. package/src/types.ts +12 -3
  206. package/dist/cmd/cloud/domain.d.ts +0 -17
  207. package/dist/cmd/cloud/domain.d.ts.map +0 -1
  208. package/dist/cmd/cloud/domain.js +0 -79
  209. package/dist/cmd/cloud/domain.js.map +0 -1
  210. package/src/cmd/cloud/domain.ts +0 -100
@@ -0,0 +1,519 @@
1
+ import type {
2
+ CLISchema,
3
+ SchemaCommand,
4
+ SchemaOption,
5
+ SchemaArgument,
6
+ } from '../../../schema-generator';
7
+ import * as path from 'node:path';
8
+
9
+ interface SkillInfo {
10
+ skillPath: string;
11
+ skillName: string;
12
+ command: SchemaCommand;
13
+ fullCommandPath: string[];
14
+ }
15
+
16
+ const EXCLUDED_COMMANDS = new Set(['ai', 'help', 'version']);
17
+
18
+ function isValidSkillName(name: string): boolean {
19
+ if (name.length < 1 || name.length > 64) return false;
20
+ if (!/^[a-z0-9-]+$/.test(name)) return false;
21
+ if (name.startsWith('-') || name.endsWith('-')) return false;
22
+ if (name.includes('--')) return false;
23
+ return true;
24
+ }
25
+
26
+ function toSkillName(parts: string[]): string {
27
+ return parts.join('-').toLowerCase();
28
+ }
29
+
30
+ function enhanceDescription(command: SchemaCommand, fullPath: string[]): string {
31
+ let description = command.description;
32
+
33
+ const context = getCommandContext(command, fullPath);
34
+ if (context) {
35
+ description = `${description}. ${context}`;
36
+ }
37
+
38
+ if (description.length > 1024) {
39
+ description = description.substring(0, 1021) + '...';
40
+ }
41
+
42
+ return description;
43
+ }
44
+
45
+ function getCommandContext(command: SchemaCommand, fullPath: string[]): string {
46
+ const parts: string[] = [];
47
+
48
+ if (command.requires?.auth) {
49
+ parts.push('Requires authentication');
50
+ }
51
+
52
+ if (fullPath.includes('cloud')) {
53
+ parts.push('Use for Agentuity cloud platform operations');
54
+ } else if (fullPath.includes('auth')) {
55
+ parts.push('Use for managing authentication credentials');
56
+ } else if (fullPath.includes('project')) {
57
+ parts.push('Use for project management operations');
58
+ }
59
+
60
+ return parts.join('. ');
61
+ }
62
+
63
+ function collectLeafCommands(
64
+ command: SchemaCommand,
65
+ parentPath: string[],
66
+ baseDir: string,
67
+ _isHidden: boolean
68
+ ): SkillInfo[] {
69
+ const skills: SkillInfo[] = [];
70
+ const currentPath = [...parentPath, command.name];
71
+
72
+ // Skip commands marked with skipSkill
73
+ if (command.skipSkill) {
74
+ return skills;
75
+ }
76
+
77
+ // Skip toplevel aliases (subcommands that have toplevel: true create duplicates)
78
+ if (command.toplevel && parentPath.length === 0) {
79
+ return skills;
80
+ }
81
+
82
+ if (command.subcommands && command.subcommands.length > 0) {
83
+ for (const sub of command.subcommands) {
84
+ skills.push(...collectLeafCommands(sub, currentPath, baseDir, _isHidden));
85
+ }
86
+ } else {
87
+ const skillName = `agentuity-cli-${toSkillName(currentPath)}`;
88
+
89
+ if (!isValidSkillName(skillName)) {
90
+ return skills;
91
+ }
92
+
93
+ const skillPath = path.join(baseDir, skillName, 'SKILL.md');
94
+
95
+ skills.push({
96
+ skillPath,
97
+ skillName,
98
+ command,
99
+ fullCommandPath: currentPath,
100
+ });
101
+ }
102
+
103
+ return skills;
104
+ }
105
+
106
+ function formatPrerequisites(command: SchemaCommand): string[] {
107
+ const prereqs: string[] = [];
108
+
109
+ if (command.requires?.auth) {
110
+ prereqs.push('Authenticated with `agentuity auth login`');
111
+ }
112
+
113
+ if (command.requires?.project) {
114
+ prereqs.push('Project context required (run from project directory or use `--project-id`)');
115
+ }
116
+
117
+ if (command.requires?.org) {
118
+ prereqs.push('Organization context required (`--org-id` or default org)');
119
+ }
120
+
121
+ if (command.prerequisites) {
122
+ prereqs.push(...command.prerequisites);
123
+ }
124
+
125
+ return prereqs;
126
+ }
127
+
128
+ function formatOptionsTable(options: SchemaOption[]): string {
129
+ if (options.length === 0) return '';
130
+
131
+ const lines: string[] = [
132
+ '| Option | Type | Required | Default | Description |',
133
+ '|--------|------|----------|---------|-------------|',
134
+ ];
135
+
136
+ for (const opt of options) {
137
+ const optName = `\`--${opt.name}\``;
138
+ const optType = opt.enum ? opt.enum.join(' \\| ') : opt.type;
139
+ const required = opt.required ? 'Yes' : 'No';
140
+ const defaultVal = opt.default !== undefined ? `\`${JSON.stringify(opt.default)}\`` : '-';
141
+ const desc = opt.description ?? '-';
142
+
143
+ lines.push(`| ${optName} | ${optType} | ${required} | ${defaultVal} | ${desc} |`);
144
+ }
145
+
146
+ return lines.join('\n');
147
+ }
148
+
149
+ function formatArgumentsTable(args: SchemaArgument[]): string {
150
+ if (args.length === 0) return '';
151
+
152
+ const lines: string[] = [
153
+ '| Argument | Type | Required | Description |',
154
+ '|----------|------|----------|-------------|',
155
+ ];
156
+
157
+ for (const arg of args) {
158
+ const argName = `\`<${arg.name}${arg.variadic ? '...' : ''}>\``;
159
+ const argType = arg.variadic ? 'array' : arg.type;
160
+ const required = arg.required ? 'Yes' : 'No';
161
+ const desc = arg.description ?? '-';
162
+
163
+ lines.push(`| ${argName} | ${argType} | ${required} | ${desc} |`);
164
+ }
165
+
166
+ return lines.join('\n');
167
+ }
168
+
169
+ function formatExamples(command: SchemaCommand): string {
170
+ if (!command.examples || command.examples.length === 0) {
171
+ return '';
172
+ }
173
+
174
+ const lines: string[] = [];
175
+
176
+ for (const example of command.examples) {
177
+ lines.push(`${example.description}:`);
178
+ lines.push('');
179
+ lines.push('```bash');
180
+ lines.push(example.command);
181
+ lines.push('```');
182
+ lines.push('');
183
+ }
184
+
185
+ return lines.join('\n').trim();
186
+ }
187
+
188
+ function formatResponse(command: SchemaCommand): string {
189
+ if (!command.response) {
190
+ return '';
191
+ }
192
+
193
+ const response = command.response as Record<string, unknown>;
194
+ const lines: string[] = [];
195
+
196
+ if (response.type === 'object' && response.properties) {
197
+ const props = response.properties as Record<string, { type?: string; description?: string }>;
198
+
199
+ lines.push('Returns JSON object:');
200
+ lines.push('');
201
+ lines.push('```json');
202
+ const sample: Record<string, string> = {};
203
+ for (const [key, val] of Object.entries(props)) {
204
+ sample[key] = val.type ?? 'unknown';
205
+ }
206
+ lines.push(JSON.stringify(sample, null, 2));
207
+ lines.push('```');
208
+ lines.push('');
209
+ lines.push('| Field | Type | Description |');
210
+ lines.push('|-------|------|-------------|');
211
+
212
+ for (const [key, val] of Object.entries(props)) {
213
+ lines.push(`| \`${key}\` | ${val.type ?? 'unknown'} | ${val.description ?? '-'} |`);
214
+ }
215
+ } else if (response.type) {
216
+ lines.push(`Returns: \`${response.type}\``);
217
+ }
218
+
219
+ return lines.join('\n');
220
+ }
221
+
222
+ function buildUsageString(command: SchemaCommand, fullPath: string[]): string {
223
+ const parts = ['agentuity', ...fullPath];
224
+
225
+ if (command.arguments) {
226
+ for (const arg of command.arguments) {
227
+ const argStr = arg.required
228
+ ? `<${arg.name}${arg.variadic ? '...' : ''}>`
229
+ : `[${arg.name}${arg.variadic ? '...' : ''}]`;
230
+ parts.push(argStr);
231
+ }
232
+ }
233
+
234
+ if (command.options && command.options.length > 0) {
235
+ parts.push('[options]');
236
+ }
237
+
238
+ return parts.join(' ');
239
+ }
240
+
241
+ function escapeYamlString(str: string): string {
242
+ // Check if string needs quoting:
243
+ // - Contains YAML special characters
244
+ // - Has leading/trailing whitespace
245
+ // - Looks like a boolean, null, or number
246
+ // - Contains control characters
247
+ const specialCharsRegex = /[:[\]{}#&*!|>'"%@`,?<>=~-]/;
248
+ // eslint-disable-next-line no-control-regex
249
+ const controlCharsRegex = new RegExp('[\\x00-\\x1f\\x7f]');
250
+ const needsQuoting =
251
+ specialCharsRegex.test(str) ||
252
+ controlCharsRegex.test(str) ||
253
+ str !== str.trim() ||
254
+ /^(true|false|yes|no|on|off|null|~)$/i.test(str) ||
255
+ /^-?(\d+\.?\d*|\.\d+)(e[+-]?\d+)?$/i.test(str) ||
256
+ str === '';
257
+
258
+ if (!needsQuoting) {
259
+ return str;
260
+ }
261
+
262
+ // Escape special characters for double-quoted YAML string
263
+ // eslint-disable-next-line no-control-regex
264
+ const nonPrintableRegex = new RegExp('[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]', 'g');
265
+ const escaped = str
266
+ .replace(/\\/g, '\\\\')
267
+ .replace(/"/g, '\\"')
268
+ .replace(/\n/g, '\\n')
269
+ .replace(/\r/g, '\\r')
270
+ .replace(/\t/g, '\\t')
271
+ .replace(nonPrintableRegex, (char) => {
272
+ const code = char.charCodeAt(0);
273
+ return `\\x${code.toString(16).padStart(2, '0')}`;
274
+ });
275
+
276
+ return `"${escaped}"`;
277
+ }
278
+
279
+ function buildArgumentHint(command: SchemaCommand): string | null {
280
+ if (!command.arguments || command.arguments.length === 0) {
281
+ return null;
282
+ }
283
+
284
+ const hints = command.arguments.map((arg) => {
285
+ const name = arg.variadic ? `${arg.name}...` : arg.name;
286
+ return arg.required ? `<${name}>` : `[${name}]`;
287
+ });
288
+
289
+ return hints.join(' ');
290
+ }
291
+
292
+ function generateSkillContent(skill: SkillInfo, version: string): string {
293
+ const { command, skillName, fullCommandPath } = skill;
294
+ const fullCommand = ['agentuity', ...fullCommandPath].join(' ');
295
+
296
+ const enhancedDescription = enhanceDescription(command, fullCommandPath);
297
+ const tags = command.tags?.join(' ') ?? '';
298
+ const argumentHint = buildArgumentHint(command);
299
+
300
+ const lines: string[] = [
301
+ '---',
302
+ `name: ${skillName}`,
303
+ `description: ${escapeYamlString(enhancedDescription)}`,
304
+ `version: "${version}"`,
305
+ 'license: Apache-2.0',
306
+ `allowed-tools: "Bash(agentuity:*)"`,
307
+ ];
308
+
309
+ if (argumentHint) {
310
+ lines.push(`argument-hint: "${argumentHint}"`);
311
+ }
312
+
313
+ lines.push('metadata:');
314
+ lines.push(` command: "${fullCommand}"`);
315
+
316
+ if (tags) {
317
+ lines.push(` tags: "${tags}"`);
318
+ }
319
+
320
+ lines.push('---');
321
+ lines.push('');
322
+
323
+ const title = fullCommandPath.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(' ');
324
+ lines.push(`# ${title}`);
325
+ lines.push('');
326
+ lines.push(command.description);
327
+ lines.push('');
328
+
329
+ const prerequisites = formatPrerequisites(command);
330
+ if (prerequisites.length > 0) {
331
+ lines.push('## Prerequisites');
332
+ lines.push('');
333
+ for (const prereq of prerequisites) {
334
+ lines.push(`- ${prereq}`);
335
+ }
336
+ lines.push('');
337
+ }
338
+
339
+ lines.push('## Usage');
340
+ lines.push('');
341
+ lines.push('```bash');
342
+ lines.push(buildUsageString(command, fullCommandPath));
343
+ lines.push('```');
344
+ lines.push('');
345
+
346
+ if (command.arguments && command.arguments.length > 0) {
347
+ lines.push('## Arguments');
348
+ lines.push('');
349
+ lines.push(formatArgumentsTable(command.arguments));
350
+ lines.push('');
351
+ }
352
+
353
+ if (command.options && command.options.length > 0) {
354
+ lines.push('## Options');
355
+ lines.push('');
356
+ lines.push(formatOptionsTable(command.options));
357
+ lines.push('');
358
+ }
359
+
360
+ const examples = formatExamples(command);
361
+ if (examples) {
362
+ lines.push('## Examples');
363
+ lines.push('');
364
+ lines.push(examples);
365
+ lines.push('');
366
+ }
367
+
368
+ const response = formatResponse(command);
369
+ if (response) {
370
+ lines.push('## Output');
371
+ lines.push('');
372
+ lines.push(response);
373
+ lines.push('');
374
+ }
375
+
376
+ return lines.join('\n');
377
+ }
378
+
379
+ function collectAllSkills(
380
+ schema: CLISchema,
381
+ outputDir: string,
382
+ includeHidden: boolean
383
+ ): SkillInfo[] {
384
+ const baseDir = path.join(outputDir, 'skills');
385
+ const allSkills: SkillInfo[] = [];
386
+
387
+ for (const command of schema.commands) {
388
+ if (EXCLUDED_COMMANDS.has(command.name)) {
389
+ continue;
390
+ }
391
+
392
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
393
+ const isHidden = (command as any).hidden === true;
394
+ if (isHidden && !includeHidden) {
395
+ continue;
396
+ }
397
+
398
+ const skills = collectLeafCommands(command, [], baseDir, isHidden);
399
+ allSkills.push(...skills);
400
+ }
401
+
402
+ return allSkills;
403
+ }
404
+
405
+ function generateReadme(version: string, skills: SkillInfo[]): string {
406
+ const groups = new Map<string, SkillInfo[]>();
407
+ for (const skill of skills) {
408
+ const group = skill.fullCommandPath[0];
409
+ if (!groups.has(group)) {
410
+ groups.set(group, []);
411
+ }
412
+ groups.get(group)!.push(skill);
413
+ }
414
+
415
+ const lines: string[] = [
416
+ '# Agentuity CLI Skills',
417
+ '',
418
+ 'This directory contains auto-generated [Agent Skills](https://agentskills.io) for the Agentuity CLI.',
419
+ '',
420
+ '## What are Agent Skills?',
421
+ '',
422
+ 'Agent Skills are modular capabilities that extend AI coding agents. Each skill is a directory',
423
+ 'containing a `SKILL.md` file with instructions that agents read when performing relevant tasks.',
424
+ '',
425
+ 'Learn more at the [Agent Skills Specification](https://agentskills.io/specification).',
426
+ '',
427
+ '## Generated From',
428
+ '',
429
+ `- **CLI Version**: ${version}`,
430
+ `- **Generated**: ${new Date().toISOString().split('T')[0]}`,
431
+ `- **Total Skills**: ${skills.length}`,
432
+ '',
433
+ '## Available Skills',
434
+ '',
435
+ ];
436
+
437
+ for (const [group, groupSkills] of [...groups.entries()].sort()) {
438
+ lines.push(`### ${group}`);
439
+ lines.push('');
440
+ lines.push('| Skill | Command | Description |');
441
+ lines.push('|-------|---------|-------------|');
442
+
443
+ for (const skill of groupSkills.sort((a, b) => a.skillName.localeCompare(b.skillName))) {
444
+ const cmd = `\`agentuity ${skill.fullCommandPath.join(' ')}\``;
445
+ const desc =
446
+ skill.command.description.substring(0, 60) +
447
+ (skill.command.description.length > 60 ? '...' : '');
448
+ lines.push(`| [${skill.skillName}](./${skill.skillName}) | ${cmd} | ${desc} |`);
449
+ }
450
+
451
+ lines.push('');
452
+ }
453
+
454
+ lines.push('## Usage');
455
+ lines.push('');
456
+ lines.push(
457
+ 'These skills are designed for AI coding agents that support the Agent Skills format.'
458
+ );
459
+ lines.push(
460
+ 'Place this directory in your project or install globally for your agent to discover.'
461
+ );
462
+ lines.push('');
463
+ lines.push('## Regenerating');
464
+ lines.push('');
465
+ lines.push('To regenerate these skills with the latest CLI schema:');
466
+ lines.push('');
467
+ lines.push('```bash');
468
+ lines.push('agentuity ai skills generate --output ./skills');
469
+ lines.push('```');
470
+ lines.push('');
471
+ lines.push('---');
472
+ lines.push('');
473
+ lines.push('*This file was auto-generated by the Agentuity CLI. Do not edit manually.*');
474
+ lines.push('');
475
+
476
+ return lines.join('\n');
477
+ }
478
+
479
+ export function collectSkillsForPreview(
480
+ schema: CLISchema,
481
+ outputDir: string,
482
+ includeHidden: boolean
483
+ ): string[] {
484
+ const allSkills = collectAllSkills(schema, outputDir, includeHidden);
485
+ return allSkills.map((s) => s.skillPath);
486
+ }
487
+
488
+ export async function generateSkills(
489
+ schema: CLISchema,
490
+ outputDir: string,
491
+ includeHidden: boolean
492
+ ): Promise<number> {
493
+ const allSkills = collectAllSkills(schema, outputDir, includeHidden);
494
+
495
+ if (allSkills.length === 0) {
496
+ return 0;
497
+ }
498
+
499
+ const baseDir = path.join(outputDir, 'skills');
500
+ let created = 0;
501
+
502
+ for (const skill of allSkills) {
503
+ const content = generateSkillContent(skill, schema.version);
504
+ const skillDir = path.dirname(skill.skillPath);
505
+
506
+ await Bun.$`mkdir -p ${skillDir}`.quiet();
507
+ await Bun.write(Bun.file(skill.skillPath), content);
508
+ created++;
509
+ }
510
+
511
+ const readmePath = path.join(baseDir, 'README.md');
512
+ const readmeContent = generateReadme(schema.version, allSkills);
513
+ await Bun.write(Bun.file(readmePath), readmeContent);
514
+
515
+ const versionPath = path.join(baseDir, 'agentuity-version.txt');
516
+ await Bun.write(Bun.file(versionPath), schema.version);
517
+
518
+ return created;
519
+ }
@@ -0,0 +1,23 @@
1
+ import type { CommandDefinition } from '../../../types';
2
+ import { createCommand } from '../../../types';
3
+ import { generateSubcommand } from './generate';
4
+ import { getCommand } from '../../../command-prefix';
5
+
6
+ export const skillsCommand: CommandDefinition = createCommand({
7
+ name: 'skills',
8
+ description: 'Generate Agent Skills from CLI schema',
9
+ tags: ['read-only', 'fast'],
10
+ examples: [
11
+ {
12
+ command: getCommand('ai skills generate --output ./skills'),
13
+ description: 'Generate skills to a directory',
14
+ },
15
+ {
16
+ command: getCommand('--dry-run ai skills generate --output ./skills'),
17
+ description: 'Preview without writing files',
18
+ },
19
+ ],
20
+ subcommands: [generateSubcommand],
21
+ });
22
+
23
+ export default skillsCommand;
@@ -11,6 +11,7 @@ export const signupCommand = createSubcommand({
11
11
  description: 'Create a new Agentuity Cloud Platform account',
12
12
  tags: ['mutating', 'creates-resource', 'slow', 'api-intensive'],
13
13
  toplevel: true,
14
+ skipSkill: true,
14
15
  idempotent: false,
15
16
  requires: { apiClient: true },
16
17
  examples: [
@@ -53,6 +53,7 @@ export async function generateEntryFile(options: GenerateEntryOptions): Promise<
53
53
  ` createCorsMiddleware,`,
54
54
  ` createOtelMiddleware,`,
55
55
  ` createAgentMiddleware,`,
56
+ ` createCompressionMiddleware,`,
56
57
  ` getAppState,`,
57
58
  ` getAppConfig,`,
58
59
  ` register,`,
@@ -130,12 +131,13 @@ app.route('/', workbenchRouter);
130
131
  `
131
132
  : '';
132
133
 
133
- // Asset proxy routes - only generated in dev mode when vitePort is available
134
- const assetProxyRoutes = vitePort
135
- ? `
134
+ // Asset proxy routes - generated for dev mode, reads VITE_PORT from env at runtime
135
+ const assetProxyRoutes =
136
+ mode === 'dev'
137
+ ? `
136
138
  // Asset proxy routes - Development mode only (proxies to Vite asset server)
137
- if (process.env.NODE_ENV !== 'production') {
138
- const VITE_ASSET_PORT = parseInt(process.env.VITE_PORT || '${vitePort}', 10);
139
+ if (isDevelopment() && process.env.VITE_PORT) {
140
+ const VITE_ASSET_PORT = parseInt(process.env.VITE_PORT, 10);
139
141
 
140
142
  const proxyToVite = async (c: Context) => {
141
143
  const viteUrl = \`http://127.0.0.1:\${VITE_ASSET_PORT}\${c.req.path}\`;
@@ -181,7 +183,7 @@ if (process.env.NODE_ENV !== 'production') {
181
183
  // File system access (for Vite's @fs protocol)
182
184
  app.get('/@fs/*', proxyToVite);
183
185
 
184
- // Module resolution (for Vite's @id protocol)
186
+ // Module resolution (for Vite's @id protocol)
185
187
  app.get('/@id/*', proxyToVite);
186
188
 
187
189
  // Any .js, .jsx, .ts, .tsx files (catch remaining modules)
@@ -192,7 +194,7 @@ if (process.env.NODE_ENV !== 'production') {
192
194
  app.get('/*.css', proxyToVite);
193
195
  }
194
196
  `
195
- : '';
197
+ : '';
196
198
 
197
199
  // Runtime mode detection helper (defined at top level for reuse)
198
200
  // Dynamic property access prevents Bun.build from inlining NODE_ENV at build time
@@ -294,6 +296,8 @@ if (isDevelopment()) {
294
296
  const workbenchRoutes = hasWorkbench
295
297
  ? `
296
298
  // Workbench routes - Runtime mode detection
299
+ // Both dev and prod run from .agentuity/app.js (dev bundles before running)
300
+ // So workbench-src is always in the same directory
297
301
  const workbenchSrcDir = import.meta.dir + '/workbench-src';
298
302
  const workbenchIndexPath = import.meta.dir + '/workbench/index.html';
299
303
  const workbenchIndex = existsSync(workbenchIndexPath)
@@ -373,6 +377,35 @@ if (!isDevelopment()) {
373
377
  app.get('/_agentuity/idle', idleHandler);
374
378
  app.get('/_idle', idleHandler);
375
379
  }
380
+
381
+ // Dev readiness check - verifies Vite asset server is ready to serve frontend
382
+ if (isDevelopment()) {
383
+ app.get('/_agentuity/ready', async (c: Context) => {
384
+ const vitePort = process.env.VITE_PORT;
385
+ if (!vitePort) {
386
+ // No Vite port means we're not using Vite proxy
387
+ return c.text('OK', 200, { 'Content-Type': 'text/plain; charset=utf-8' });
388
+ }
389
+
390
+ try {
391
+ // Probe Vite to check if it can serve the main entry point
392
+ // Use @vite/client as a lightweight check - it's always available
393
+ const viteUrl = \`http://127.0.0.1:\${vitePort}/@vite/client\`;
394
+ const res = await fetch(viteUrl, {
395
+ signal: AbortSignal.timeout(5000),
396
+ method: 'HEAD'
397
+ });
398
+
399
+ if (res.ok) {
400
+ return c.text('OK', 200, { 'Content-Type': 'text/plain; charset=utf-8' });
401
+ }
402
+ return c.text('VITE_NOT_READY', 503, { 'Content-Type': 'text/plain; charset=utf-8' });
403
+ } catch (err) {
404
+ otel.logger.debug('Vite readiness check failed: %s', err instanceof Error ? err.message : String(err));
405
+ return c.text('VITE_NOT_READY', 503, { 'Content-Type': 'text/plain; charset=utf-8' });
406
+ }
407
+ });
408
+ }
376
409
  `;
377
410
 
378
411
  const code = `// @generated
@@ -410,6 +443,9 @@ const app = createRouter();
410
443
  setGlobalRouter(app);
411
444
 
412
445
  // Step 3: Apply middleware in correct order (BEFORE mounting routes)
446
+ // Compression runs first (outermost) so it can compress the final response
447
+ app.use('*', createCompressionMiddleware());
448
+
413
449
  app.use('*', createBaseMiddleware({
414
450
  logger: otel.logger,
415
451
  tracer: otel.tracer,