veryfront 0.1.854 → 0.1.856

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 (66) hide show
  1. package/esm/cli/commands/generate/command-help.d.ts.map +1 -1
  2. package/esm/cli/commands/generate/command-help.js +7 -2
  3. package/esm/cli/commands/generate/command.d.ts.map +1 -1
  4. package/esm/cli/commands/generate/command.js +25 -101
  5. package/esm/cli/commands/generate/handler.d.ts +1 -1
  6. package/esm/cli/commands/generate/handler.d.ts.map +1 -1
  7. package/esm/cli/commands/generate/handler.js +2 -1
  8. package/esm/cli/commands/generate/integration-generator.js +4 -4
  9. package/esm/cli/commands/init/init-command.d.ts.map +1 -1
  10. package/esm/cli/commands/init/init-command.js +100 -1
  11. package/esm/cli/commands/mcp/command-help.js +1 -1
  12. package/esm/cli/commands/skills/command-help.js +1 -1
  13. package/esm/cli/commands/skills/command.d.ts +1 -1
  14. package/esm/cli/commands/skills/command.js +2 -2
  15. package/esm/cli/commands/skills/create.d.ts.map +1 -1
  16. package/esm/cli/commands/skills/create.js +14 -40
  17. package/esm/cli/commands/skills/handler.js +15 -16
  18. package/esm/cli/commands/skills/validate.d.ts +6 -0
  19. package/esm/cli/commands/skills/validate.d.ts.map +1 -1
  20. package/esm/cli/commands/skills/validate.js +18 -43
  21. package/esm/cli/mcp/server.js +4 -4
  22. package/esm/cli/mcp/standalone.js +4 -4
  23. package/esm/cli/mcp/tools/helpers.d.ts +0 -8
  24. package/esm/cli/mcp/tools/helpers.d.ts.map +1 -1
  25. package/esm/cli/mcp/tools/scaffold-tools.d.ts +2 -2
  26. package/esm/cli/mcp/tools/scaffold-tools.d.ts.map +1 -1
  27. package/esm/cli/mcp/tools/scaffold-tools.js +24 -193
  28. package/esm/cli/scaffold/engine.d.ts +33 -0
  29. package/esm/cli/scaffold/engine.d.ts.map +1 -0
  30. package/esm/cli/scaffold/engine.js +303 -0
  31. package/esm/cli/skills/core-skills.d.ts.map +1 -1
  32. package/esm/cli/skills/core-skills.js +23 -75
  33. package/esm/cli/skills/loader.d.ts +2 -2
  34. package/esm/cli/skills/loader.d.ts.map +1 -1
  35. package/esm/cli/skills/loader.js +14 -15
  36. package/esm/cli/skills/types.d.ts +2 -38
  37. package/esm/cli/skills/types.d.ts.map +1 -1
  38. package/esm/cli/skills/types.js +1 -27
  39. package/esm/cli/templates/index.d.ts +1 -0
  40. package/esm/cli/templates/index.d.ts.map +1 -1
  41. package/esm/cli/templates/index.js +4 -1
  42. package/esm/cli/templates/loader.d.ts +1 -0
  43. package/esm/cli/templates/loader.d.ts.map +1 -1
  44. package/esm/cli/templates/loader.js +6 -0
  45. package/esm/cli/templates/manifest.js +17 -17
  46. package/esm/deno.js +1 -1
  47. package/esm/src/agent/react/use-chat/types.d.ts +2 -2
  48. package/esm/src/agent/react/use-chat/types.d.ts.map +1 -1
  49. package/esm/src/agent/react/use-chat/use-chat.js +1 -1
  50. package/esm/src/agent/runtime/constants.d.ts.map +1 -1
  51. package/esm/src/agent/runtime/constants.js +0 -2
  52. package/esm/src/agent/runtime/model-resolution.d.ts.map +1 -1
  53. package/esm/src/agent/runtime/model-resolution.js +14 -4
  54. package/esm/src/agent/runtime/skill-metadata.d.ts.map +1 -1
  55. package/esm/src/agent/runtime/skill-metadata.js +2 -1
  56. package/esm/src/integrations/_data.js +1 -1
  57. package/esm/src/provider/veryfront-cloud/model-catalog.d.ts +1 -0
  58. package/esm/src/provider/veryfront-cloud/model-catalog.d.ts.map +1 -1
  59. package/esm/src/provider/veryfront-cloud/model-catalog.js +13 -14
  60. package/esm/src/provider/veryfront-cloud/shared.d.ts.map +1 -1
  61. package/esm/src/provider/veryfront-cloud/shared.js +8 -0
  62. package/esm/src/skill/parser.d.ts.map +1 -1
  63. package/esm/src/skill/parser.js +2 -1
  64. package/esm/src/utils/version-constant.d.ts +1 -1
  65. package/esm/src/utils/version-constant.js +1 -1
  66. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"command-help.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/generate/command-help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,YAAY,EAAE,WAkB1B,CAAC"}
1
+ {"version":3,"file":"command-help.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/generate/command-help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,YAAY,EAAE,WAuB1B,CAAC"}
@@ -8,12 +8,17 @@ export const generateHelp = {
8
8
  "veryfront generate page about",
9
9
  "veryfront generate layout admin",
10
10
  "veryfront generate api users/[id]",
11
- "veryfront generate provider auth",
11
+ "veryfront generate agent researcher",
12
+ "veryfront generate tool search-docs",
13
+ "veryfront generate workflow content-pipeline",
14
+ "veryfront generate task sync-data",
15
+ "veryfront generate resource docs",
16
+ "veryfront generate skill code-review",
12
17
  "veryfront generate integration # Interactive wizard",
13
18
  "veryfront generate integration twilio # With name preset",
14
19
  ],
15
20
  notes: [
16
- "Types: page, layout, provider, api, integration",
21
+ "Types: page, api, layout, component, tool, agent, prompt, workflow, task, resource, skill, integration",
17
22
  "Integration type launches interactive wizard if name not provided",
18
23
  ],
19
24
  };
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/generate/command.ts"],"names":[],"mappings":"AAwBA,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CA8Hf"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/generate/command.ts"],"names":[],"mappings":"AAsBA,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAkCf"}
@@ -1,124 +1,48 @@
1
- import { join } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
2
1
  import { getConfig } from "../../../src/config/index.js";
3
2
  import { cliLogger } from "../../utils/index.js";
4
3
  import { createError, toError } from "../../../src/errors/index.js";
5
- import { createFileSystem } from "../../../src/platform/index.js";
6
4
  import { generateIntegration } from "./integration-generator.js";
7
- import { ensureDir } from "../../utils/fs.js";
8
- import { toComponentName, toSlug } from "../../utils/string.js";
5
+ import { isScaffoldType, scaffoldProjectFile } from "../../scaffold/engine.js";
9
6
  async function getPreferredRouter(projectDir) {
10
7
  try {
11
8
  const { runtime } = await import("../../../src/platform/index.js");
12
9
  const adapter = await runtime.get();
13
10
  const cfg = await getConfig(projectDir, adapter);
14
11
  const pref = cfg?.generate?.preferredRouter ?? cfg?.router;
15
- if (pref === "app-router" || pref === "pages-router")
16
- return pref;
12
+ if (pref === "app-router" || pref === "app")
13
+ return "app-router";
14
+ if (pref === "pages-router" || pref === "pages")
15
+ return "pages-router";
17
16
  }
18
17
  catch {
19
18
  cliLogger.debug("Could not load config for generate command, using defaults");
20
19
  }
21
- return "pages-router";
20
+ return "app-router";
22
21
  }
23
22
  export async function generateCommand(projectDir, type, name) {
24
- const fs = createFileSystem();
25
23
  const preferred = await getPreferredRouter(projectDir);
26
- const slug = toSlug(name);
27
24
  if (type === "integration") {
28
25
  await generateIntegration(projectDir, { name: name || undefined });
29
26
  return;
30
27
  }
31
- switch (type) {
32
- case "rsc": {
33
- const dir = join(projectDir, "app", slug || "");
34
- await ensureDir(dir);
35
- const file = join(dir, "page.tsx");
36
- const title = slug.split("/").pop() || "RSC";
37
- const componentName = toComponentName(title);
38
- const content = `export default function ${componentName}(){
39
- return (
40
- <div>
41
- <h1>${title}</h1>
42
- <p>Open the experimental RSC shell for this route:</p>
43
- <a href="/_veryfront/rsc/page?name=${componentName}">RSC Shell</a>
44
- </div>
45
- );
46
- }
47
- `;
48
- await fs.writeTextFile(file, content);
49
- cliLogger.info(`Created ${file}`);
50
- return;
51
- }
52
- case "page": {
53
- if (preferred === "app-router") {
54
- const pageDir = join(projectDir, "app", slug || "");
55
- await ensureDir(pageDir);
56
- const file = join(pageDir, "page.tsx");
57
- const title = slug.split("/").pop() || "Page";
58
- const componentName = toComponentName(title);
59
- const content = `export default function ${componentName}(){ return <div>${title}</div>; }\n`;
60
- await fs.writeTextFile(file, content);
61
- cliLogger.info(`Created ${file}`);
62
- return;
63
- }
64
- const parts = slug.split("/");
65
- const subdir = slug.includes("/") ? parts.slice(0, -1).join("/") : "";
66
- const base = join(projectDir, "pages");
67
- const targetDir = subdir ? join(base, subdir) : base;
68
- await ensureDir(targetDir);
69
- const fname = `${parts.pop() || "index"}.mdx`;
70
- const file = join(targetDir, fname);
71
- const title = slug.split("/").pop() || "Page";
72
- const content = `---\ntitle: ${title}\n---\n\n# ${title}\n\nThis is a new page.\n`;
73
- await fs.writeTextFile(file, content);
74
- cliLogger.info(`Created ${file}`);
75
- return;
76
- }
77
- case "layout": {
78
- if (preferred === "app-router") {
79
- const dir = join(projectDir, "app", slug || "");
80
- await ensureDir(dir);
81
- const file = join(dir, "layout.tsx");
82
- const content = `export default function Layout({ children }: { children: React.ReactNode }){ return (<section>${slug || "root"}{children}</section>); }\n`;
83
- await fs.writeTextFile(file, content);
84
- cliLogger.info(`Created ${file}`);
85
- return;
86
- }
87
- const dir = join(projectDir, "layouts");
88
- await ensureDir(dir);
89
- const file = join(dir, `${slug}.mdx`);
90
- const componentName = toComponentName(slug);
91
- const content = `---\nisLayout: true\n---\n\nexport default function ${componentName}({ children }) {\n return (<div className="${slug}-layout"><main>{children}</main></div>);\n}\n`;
92
- await fs.writeTextFile(file, content);
93
- cliLogger.info(`Created ${file}`);
94
- return;
95
- }
96
- case "api": {
97
- if (preferred === "app-router") {
98
- const routeDir = join(projectDir, "app", slug || "");
99
- await ensureDir(routeDir);
100
- const file = join(routeDir, "route.ts");
101
- const content = `export const GET = (_req: Request) => Response.json({ ok: true });\n`;
102
- await fs.writeTextFile(file, content);
103
- cliLogger.info(`Created ${file}`);
104
- return;
105
- }
106
- const parts = slug.split("/");
107
- const subdir = slug.includes("/") ? parts.slice(0, -1).join("/") : "";
108
- const apiBase = join(projectDir, "pages", "api");
109
- const targetDir = subdir ? join(apiBase, subdir) : apiBase;
110
- await ensureDir(targetDir);
111
- const fname = `${parts.pop() || "index"}.ts`;
112
- const file = join(targetDir, fname);
113
- const content = `export function GET(_req: Request) {\n return new Response(JSON.stringify({ ok: true }), { headers: { 'content-type': 'application/json' } });\n}\n`;
114
- await fs.writeTextFile(file, content);
115
- cliLogger.info(`Created ${file}`);
116
- return;
117
- }
118
- default:
119
- throw toError(createError({
120
- type: "config",
121
- message: `Unknown generate type: ${type}`,
122
- }));
28
+ if (!isScaffoldType(type)) {
29
+ throw toError(createError({
30
+ type: "config",
31
+ message: `Unknown generate type: ${type}`,
32
+ }));
33
+ }
34
+ const result = await scaffoldProjectFile({
35
+ projectDir,
36
+ type,
37
+ name,
38
+ router: preferred,
39
+ });
40
+ if (!result.success) {
41
+ throw toError(createError({
42
+ type: "config",
43
+ message: result.message,
44
+ }));
123
45
  }
46
+ for (const file of result.files)
47
+ cliLogger.info(`Created ${file.path}`);
124
48
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import type { ParsedArgs } from "../../shared/types.js";
5
5
  export declare const parseGenerateArgs: (args: ParsedArgs) => import("../../shared/args.js").SafeParseResult<import("../../../src/extensions/schema/schema-validator.js").InferShape<{
6
- type: import("../../../src/internal-agents/schema.js").Schema<"page" | "api" | "layout" | "provider" | "integration" | undefined>;
6
+ type: import("../../../src/internal-agents/schema.js").Schema<"prompt" | "page" | "api" | "agent" | "layout" | "resource" | "component" | "task" | "tool" | "integration" | "skill" | "workflow" | undefined>;
7
7
  name: import("../../../src/internal-agents/schema.js").Schema<string | undefined>;
8
8
  }>>;
9
9
  export declare function handleGenerateCommand(args: ParsedArgs): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/generate/handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAcxD,eAAO,MAAM,iBAAiB;;;GAG5B,CAAC;AAEH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B3E"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/generate/handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAexD,eAAO,MAAM,iBAAiB;;;GAG5B,CAAC;AAEH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B3E"}
@@ -6,7 +6,8 @@ import { generateCommand } from "./index.js";
6
6
  import { showLogo } from "../../utils/index.js";
7
7
  import { createArgParser } from "../../shared/args.js";
8
8
  import { cwd } from "../../../src/platform/index.js";
9
- const VALID_TYPES = ["page", "layout", "provider", "api", "integration"];
9
+ import { SCAFFOLD_TYPES } from "../../scaffold/engine.js";
10
+ const VALID_TYPES = [...SCAFFOLD_TYPES, "integration"];
10
11
  const getGenerateArgsSchema = defineSchema((v) => v.object({
11
12
  type: v.enum(VALID_TYPES).optional(),
12
13
  name: v.string().optional(),
@@ -34,7 +34,7 @@ export async function generateIntegration(projectDir, options = {}) {
34
34
  console.log(green("Integration created successfully!"));
35
35
  console.log("");
36
36
  console.log("Files created:");
37
- console.log(` ${cyan("ai/integrations/" + config.name + "/")} - Integration directory`);
37
+ console.log(` ${cyan("integrations/" + config.name + "/")} - Integration directory`);
38
38
  console.log("");
39
39
  console.log("Next steps:");
40
40
  console.log(` 1. Add your ${config.envVarPrefix}_* environment variables to .env`);
@@ -42,7 +42,7 @@ export async function generateIntegration(projectDir, options = {}) {
42
42
  console.log(` 2. Configure OAuth app in ${config.displayName} developer portal`);
43
43
  console.log(` 3. Set callback URL to: /api/auth/${config.name}/callback`);
44
44
  }
45
- console.log(` 4. Customize the generated tools in ai/integrations/${config.name}/tools/`);
45
+ console.log(` 4. Customize the generated tools in integrations/${config.name}/tools/`);
46
46
  console.log("");
47
47
  }
48
48
  async function getInteractiveConfig(options) {
@@ -103,7 +103,7 @@ async function getInteractiveConfig(options) {
103
103
  };
104
104
  }
105
105
  async function createIntegrationFiles(projectDir, config) {
106
- const baseDir = join(projectDir, "ai", "integrations", config.name);
106
+ const baseDir = join(projectDir, "integrations", config.name);
107
107
  await ensureDir(baseDir);
108
108
  await ensureDir(join(baseDir, "lib"));
109
109
  await ensureDir(join(baseDir, "tools"));
@@ -381,7 +381,7 @@ export async function GET(): Promise<Response> {
381
381
  import {
382
382
  exchangeCodeForTokens,
383
383
  setTokens,
384
- } from "../../../../ai/integrations/${config.name}/lib/token-store.ts";
384
+ } from "../../../../integrations/${config.name}/lib/token-store.ts";
385
385
 
386
386
  const USE_PKCE = ${usePKCELiteral};
387
387
  const PKCE_COOKIE_NAME = ${JSON.stringify(pkceCookieName)};
@@ -1 +1 @@
1
- {"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/init-command.ts"],"names":[],"mappings":"AAAA;;;iCAGiC;AAWjC,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,YAAY,CAAC;AAiKzE;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8YrE"}
1
+ {"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/init-command.ts"],"names":[],"mappings":"AAAA;;;iCAGiC;AAWjC,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,YAAY,CAAC;AA6PzE;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA6arE"}
@@ -138,6 +138,80 @@ function dedupeEnvVars(envVars) {
138
138
  return true;
139
139
  });
140
140
  }
141
+ const STRUCTURE_ORDER = [
142
+ "app",
143
+ "pages",
144
+ "agents",
145
+ "tools",
146
+ "workflows",
147
+ "tasks",
148
+ "prompts",
149
+ "resources",
150
+ "skills",
151
+ "components",
152
+ "lib",
153
+ "content",
154
+ "AGENTS.md",
155
+ "README.md",
156
+ "package.json",
157
+ "deno.json",
158
+ "tsconfig.json",
159
+ ".env",
160
+ ".env.example",
161
+ ".gitignore",
162
+ ];
163
+ function structureRank(name) {
164
+ const index = STRUCTURE_ORDER.indexOf(name);
165
+ return index === -1 ? STRUCTURE_ORDER.length : index;
166
+ }
167
+ function sortStructureEntries([nameA, nodeA], [nameB, nodeB]) {
168
+ const rankDiff = structureRank(nameA) - structureRank(nameB);
169
+ if (rankDiff !== 0)
170
+ return rankDiff;
171
+ if (nodeA.file !== nodeB.file)
172
+ return nodeA.file ? 1 : -1;
173
+ return nameA.localeCompare(nameB);
174
+ }
175
+ function renderProjectStructure(rootName, paths, maxLines = 22) {
176
+ const root = { file: false, children: new Map() };
177
+ const normalizedPaths = [...new Set(paths)]
178
+ .filter((path) => path && !path.endsWith("/"))
179
+ .sort();
180
+ for (const path of normalizedPaths) {
181
+ const parts = path.split("/").filter(Boolean);
182
+ let current = root;
183
+ for (const [index, part] of parts.entries()) {
184
+ const isFile = index === parts.length - 1;
185
+ let child = current.children.get(part);
186
+ if (!child) {
187
+ child = { file: isFile, children: new Map() };
188
+ current.children.set(part, child);
189
+ }
190
+ if (isFile)
191
+ child.file = true;
192
+ current = child;
193
+ }
194
+ }
195
+ const lines = [`${rootName}/`];
196
+ let omitted = 0;
197
+ function walk(node, depth) {
198
+ const entries = [...node.children.entries()].sort(sortStructureEntries);
199
+ for (const [name, child] of entries) {
200
+ if (lines.length >= maxLines) {
201
+ omitted++;
202
+ continue;
203
+ }
204
+ lines.push(`${" ".repeat(depth)}${name}${child.file ? "" : "/"}`);
205
+ if (!child.file)
206
+ walk(child, depth + 1);
207
+ }
208
+ }
209
+ walk(root, 1);
210
+ if (omitted > 0) {
211
+ lines.push(`${" ".repeat(1)}... ${omitted} more ${omitted === 1 ? "entry" : "entries"}`);
212
+ }
213
+ return lines;
214
+ }
141
215
  /**
142
216
  * Initializes a new Veryfront project with the specified template
143
217
  */
@@ -204,7 +278,7 @@ export async function initCommand(options) {
204
278
  message: `Directory "${projectName}" already exists. Choose a different name or use --force to overwrite.`,
205
279
  }));
206
280
  }
207
- const { getTemplate, getTemplateConfig } = await import("../../templates/index.js");
281
+ const { getAiRuleTemplate, getTemplate, getTemplateConfig } = await import("../../templates/index.js");
208
282
  let templateFiles = await getTemplate(template);
209
283
  const templateConfig = getTemplateConfig(template);
210
284
  if (!templateFiles) {
@@ -213,6 +287,18 @@ export async function initCommand(options) {
213
287
  message: `Template ${template} not found`,
214
288
  }));
215
289
  }
290
+ const agentsGuide = getAiRuleTemplate("agents.md");
291
+ if (!agentsGuide) {
292
+ throw toError(createError({
293
+ type: "config",
294
+ message: "Project agent guide template not found",
295
+ }));
296
+ }
297
+ if (!templateFiles.some((file) => file.path === "AGENTS.md")) {
298
+ templateFiles = mergeFiles(templateFiles, [
299
+ { path: "AGENTS.md", content: agentsGuide },
300
+ ]);
301
+ }
216
302
  const allEnvVars = templateConfig?.envVars ? [...templateConfig.envVars] : [];
217
303
  const featureTips = [];
218
304
  let loadedIntegrations = [];
@@ -274,6 +360,7 @@ export async function initCommand(options) {
274
360
  await ensureDir(projectDir);
275
361
  // Create project files with progress spinner
276
362
  const filesSpinner = quiet ? null : createSpinner("Creating project files...");
363
+ const createdPaths = [];
277
364
  try {
278
365
  for (const file of templateFiles) {
279
366
  if (file.path === ".env" || file.path === ".env.example")
@@ -283,6 +370,7 @@ export async function initCommand(options) {
283
370
  if (fileDir !== projectDir)
284
371
  await ensureDir(fileDir);
285
372
  await fs.writeTextFile(filePath, file.content);
373
+ createdPaths.push(file.path);
286
374
  logger.debug(`Created file: ${file.path}`);
287
375
  }
288
376
  // Skip in quiet/TUI mode since local dev uses CDN and package.json can cause hydration issues
@@ -294,8 +382,10 @@ export async function initCommand(options) {
294
382
  npmDependencies: integration.config.npmDependencies,
295
383
  })),
296
384
  });
385
+ createdPaths.push("package.json");
297
386
  if (runtime === "deno") {
298
387
  await createDenoConfig(projectDir);
388
+ createdPaths.push("deno.json");
299
389
  }
300
390
  }
301
391
  if (allEnvVars.length) {
@@ -304,8 +394,10 @@ export async function initCommand(options) {
304
394
  prefilledValues: options.env,
305
395
  });
306
396
  await fs.writeTextFile(join(projectDir, ".env"), envResult.envContent);
397
+ createdPaths.push(".env");
307
398
  logger.debug("Created file: .env");
308
399
  await fs.writeTextFile(join(projectDir, ".env.example"), envResult.envExampleContent);
400
+ createdPaths.push(".env.example");
309
401
  logger.debug("Created file: .env.example");
310
402
  }
311
403
  const gitignorePath = join(projectDir, ".gitignore");
@@ -317,6 +409,7 @@ export async function initCommand(options) {
317
409
  existingGitignore = undefined;
318
410
  }
319
411
  await fs.writeTextFile(gitignorePath, generateGitignoreContent(existingGitignore));
412
+ createdPaths.push(".gitignore");
320
413
  logger.debug("Updated file: .gitignore");
321
414
  filesSpinner?.success("Project files created");
322
415
  }
@@ -422,9 +515,15 @@ export async function initCommand(options) {
422
515
  }
423
516
  localSteps.push(devCommand);
424
517
  const displayName = projectName ?? "Project";
518
+ const structureRoot = projectName ?? ".";
519
+ const structureLines = renderProjectStructure(structureRoot, createdPaths);
425
520
  const successContent = [
426
521
  `${green("✓")} ${displayName} ready!`,
427
522
  "",
523
+ `${brand("Project structure")}`,
524
+ ...structureLines,
525
+ "",
526
+ `${brand("Next steps")}`,
428
527
  ...localSteps,
429
528
  ];
430
529
  if (deployedSlug) {
@@ -26,7 +26,7 @@ export const mcpHelp = {
26
26
  " • vf_create_project - Create new project from template",
27
27
  " • vf_get_errors - Real-time compile/runtime errors",
28
28
  " • vf_preview_route - HTTP response without browser",
29
- " • vf_scaffold - Generate pages/APIs/components/tools",
29
+ " • vf_scaffold - Generate routes, components, and AI primitives",
30
30
  " • vf_list_routes - Structured route manifest",
31
31
  " • vf_trigger_hmr - Force browser refresh",
32
32
  ],
@@ -12,7 +12,7 @@ export const skillsHelp = {
12
12
  "veryfront skills info scaffold-app",
13
13
  "veryfront skills info deploy-safely --json",
14
14
  "veryfront skills create my-skill",
15
- "veryfront skills validate ./my-skill",
15
+ "veryfront skills validate ./skills/my-skill",
16
16
  ],
17
17
  notes: [
18
18
  "Subcommands: list (default), info, create, validate",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Skills command list and inspect agent skills
2
+ * Skills command, list and inspect agent skills
3
3
  *
4
4
  * @module cli/commands/skills
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Skills command list and inspect agent skills
2
+ * Skills command, list and inspect agent skills
3
3
  *
4
4
  * @module cli/commands/skills
5
5
  */
@@ -9,7 +9,7 @@ export async function listSkills() {
9
9
  }
10
10
  export async function getSkillInfo(name) {
11
11
  const skills = await listAllSkills();
12
- const found = skills.find((s) => s.manifest.name === name);
12
+ const found = skills.find((s) => s.metadata.name === name);
13
13
  if (found)
14
14
  return found;
15
15
  // Try loading directly by path
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/skills/create.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AA6CxD,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCjE"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/skills/create.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQxD,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCjE"}
@@ -1,43 +1,14 @@
1
1
  /**
2
- * Skills create command scaffold a new skill
2
+ * Skills create command, scaffold a new skill
3
3
  *
4
4
  * @module cli/commands/skills/create
5
5
  */
6
6
  import * as dntShim from "../../../_dnt.shims.js";
7
+ import { relative } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
7
8
  import { createSuccessEnvelope, isJsonMode, outputJson } from "../../shared/json-output.js";
8
9
  import { logSuccess } from "../../utils/index.js";
9
- import { createFileSystem } from "../../../src/platform/index.js";
10
+ import { scaffoldProjectFile } from "../../scaffold/engine.js";
10
11
  const VALID_SKILL_NAME = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
11
- const SKILL_JSON_TEMPLATE = (name) => JSON.stringify({
12
- name,
13
- version: "1.0.0",
14
- description: `${name} skill`,
15
- requires: {
16
- cli: [],
17
- mcp: [],
18
- },
19
- inputs: {},
20
- }, null, 2);
21
- const SKILL_MD_TEMPLATE = (name) => `# ${name}
22
-
23
- ## Overview
24
-
25
- Describe what this skill does.
26
-
27
- ## Steps
28
-
29
- 1. **Step 1** — Description
30
- \`\`\`bash
31
- veryfront <command> --json
32
- \`\`\`
33
-
34
- 2. **Step 2** — Description
35
-
36
- ## Error Recovery
37
-
38
- - If step 1 fails: ...
39
- - If step 2 fails: ...
40
- `;
41
12
  export async function createSkill(args) {
42
13
  const name = args._[2];
43
14
  if (!name) {
@@ -48,18 +19,21 @@ export async function createSkill(args) {
48
19
  console.error(`Invalid skill name "${name}". Use lowercase letters, numbers, and hyphens (e.g. "my-skill").`);
49
20
  dntShim.Deno.exit(1);
50
21
  }
51
- const fs = createFileSystem();
52
- const dir = name;
53
- await fs.mkdir(dir, { recursive: true });
54
- await fs.writeTextFile(`${dir}/skill.json`, SKILL_JSON_TEMPLATE(name));
55
- await fs.writeTextFile(`${dir}/SKILL.md`, SKILL_MD_TEMPLATE(name));
22
+ const projectDir = dntShim.Deno.cwd();
23
+ const result = await scaffoldProjectFile({
24
+ projectDir,
25
+ type: "skill",
26
+ name,
27
+ });
28
+ if (!result.success)
29
+ throw new Error(result.message);
56
30
  if (isJsonMode()) {
57
31
  await outputJson(createSuccessEnvelope("skills", {
58
32
  created: name,
59
- files: [`${dir}/skill.json`, `${dir}/SKILL.md`],
33
+ files: result.files.map((file) => relative(projectDir, file.path)),
60
34
  }));
61
35
  return;
62
36
  }
63
- logSuccess(`Created skill "${name}" at ./${dir}/`);
64
- console.log(` Files: skill.json, SKILL.md`);
37
+ logSuccess(`Created skill "${name}" at ./skills/${name}/`);
38
+ console.log(` Files: skills/${name}/SKILL.md`);
65
39
  }
@@ -20,10 +20,10 @@ async function handleSkillList() {
20
20
  const skills = await listSkills();
21
21
  if (isJsonMode()) {
22
22
  await outputJson(createSuccessEnvelope("skills", skills.map((s) => ({
23
- name: s.manifest.name,
24
- version: s.manifest.version,
25
- description: s.manifest.description,
26
- requires: s.manifest.requires,
23
+ name: s.metadata.name,
24
+ description: s.metadata.description,
25
+ allowedTools: s.metadata.allowedTools,
26
+ directory: s.directory,
27
27
  }))));
28
28
  return;
29
29
  }
@@ -34,8 +34,10 @@ async function handleSkillList() {
34
34
  }
35
35
  console.log(`\n ${bold("Available Skills")}\n`);
36
36
  for (const skill of skills) {
37
- console.log(` ${bold(skill.manifest.name)} ${dim(`v${skill.manifest.version}`)}`);
38
- console.log(` ${skill.manifest.description}`);
37
+ const version = skill.metadata.metadata?.version;
38
+ const suffix = version ? ` ${dim(`v${version}`)}` : "";
39
+ console.log(` ${bold(skill.metadata.name)}${suffix}`);
40
+ console.log(` ${skill.metadata.description}`);
39
41
  }
40
42
  console.log();
41
43
  }
@@ -52,21 +54,18 @@ async function handleSkillInfo(args) {
52
54
  }
53
55
  if (isJsonMode()) {
54
56
  await outputJson(createSuccessEnvelope("skills", {
55
- ...skill.manifest,
57
+ ...skill.metadata,
56
58
  content: skill.skillMd,
57
59
  directory: skill.directory,
58
60
  }));
59
61
  return;
60
62
  }
61
- console.log(`\n ${bold(skill.manifest.name)} ${dim(`v${skill.manifest.version}`)}`);
62
- console.log(` ${skill.manifest.description}\n`);
63
- if (skill.manifest.requires) {
64
- if (skill.manifest.requires.cli?.length) {
65
- console.log(` ${dim("CLI:")} ${skill.manifest.requires.cli.join(", ")}`);
66
- }
67
- if (skill.manifest.requires.mcp?.length) {
68
- console.log(` ${dim("MCP:")} ${skill.manifest.requires.mcp.join(", ")}`);
69
- }
63
+ const version = skill.metadata.metadata?.version;
64
+ const suffix = version ? ` ${dim(`v${version}`)}` : "";
65
+ console.log(`\n ${bold(skill.metadata.name)}${suffix}`);
66
+ console.log(` ${skill.metadata.description}\n`);
67
+ if (skill.metadata.allowedTools?.length) {
68
+ console.log(` ${dim("Allowed tools:")} ${skill.metadata.allowedTools.join(", ")}`);
70
69
  }
71
70
  if (skill.skillMd) {
72
71
  console.log(`\n${skill.skillMd}`);
@@ -1,3 +1,9 @@
1
1
  import type { ParsedArgs } from "../../shared/types.js";
2
+ interface ValidationIssue {
3
+ severity: "error" | "warning";
4
+ message: string;
5
+ }
2
6
  export declare function validateSkill(args: ParsedArgs): Promise<void>;
7
+ export declare function validateSkillDirectory(dir: string): Promise<ValidationIssue[]>;
8
+ export {};
3
9
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/skills/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAYxD,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDnE"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/skills/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAOxD,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnE;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAuBpF"}