veryfront 0.1.71 → 0.1.73

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 (110) hide show
  1. package/esm/cli/commands/files/command-help.d.ts +3 -0
  2. package/esm/cli/commands/files/command-help.d.ts.map +1 -0
  3. package/esm/cli/commands/files/command-help.js +38 -0
  4. package/esm/cli/commands/files/command.d.ts +105 -0
  5. package/esm/cli/commands/files/command.d.ts.map +1 -0
  6. package/esm/cli/commands/files/command.js +250 -0
  7. package/esm/cli/commands/files/handler.d.ts +3 -0
  8. package/esm/cli/commands/files/handler.d.ts.map +1 -0
  9. package/esm/cli/commands/files/handler.js +4 -0
  10. package/esm/cli/commands/files/index.d.ts +4 -0
  11. package/esm/cli/commands/files/index.d.ts.map +1 -0
  12. package/esm/cli/commands/files/index.js +2 -0
  13. package/esm/cli/commands/knowledge/command-help.d.ts +3 -0
  14. package/esm/cli/commands/knowledge/command-help.d.ts.map +1 -0
  15. package/esm/cli/commands/knowledge/command-help.js +38 -0
  16. package/esm/cli/commands/knowledge/command.d.ts +122 -0
  17. package/esm/cli/commands/knowledge/command.d.ts.map +1 -0
  18. package/esm/cli/commands/knowledge/command.js +382 -0
  19. package/esm/cli/commands/knowledge/handler.d.ts +3 -0
  20. package/esm/cli/commands/knowledge/handler.d.ts.map +1 -0
  21. package/esm/cli/commands/knowledge/handler.js +4 -0
  22. package/esm/cli/commands/knowledge/index.d.ts +3 -0
  23. package/esm/cli/commands/knowledge/index.d.ts.map +1 -0
  24. package/esm/cli/commands/knowledge/index.js +2 -0
  25. package/esm/cli/commands/knowledge/parser-source.d.ts +2 -0
  26. package/esm/cli/commands/knowledge/parser-source.d.ts.map +1 -0
  27. package/esm/cli/commands/knowledge/parser-source.js +415 -0
  28. package/esm/cli/commands/uploads/command-help.d.ts +3 -0
  29. package/esm/cli/commands/uploads/command-help.d.ts.map +1 -0
  30. package/esm/cli/commands/uploads/command-help.js +43 -0
  31. package/esm/cli/commands/uploads/command.d.ts +140 -0
  32. package/esm/cli/commands/uploads/command.d.ts.map +1 -0
  33. package/esm/cli/commands/uploads/command.js +323 -0
  34. package/esm/cli/commands/uploads/handler.d.ts +3 -0
  35. package/esm/cli/commands/uploads/handler.d.ts.map +1 -0
  36. package/esm/cli/commands/uploads/handler.js +4 -0
  37. package/esm/cli/commands/uploads/index.d.ts +4 -0
  38. package/esm/cli/commands/uploads/index.d.ts.map +1 -0
  39. package/esm/cli/commands/uploads/index.js +2 -0
  40. package/esm/cli/help/command-definitions.d.ts.map +1 -1
  41. package/esm/cli/help/command-definitions.js +6 -0
  42. package/esm/cli/router.d.ts.map +1 -1
  43. package/esm/cli/router.js +6 -0
  44. package/esm/deno.js +1 -1
  45. package/esm/src/errors/error-registry.d.ts +2 -0
  46. package/esm/src/errors/error-registry.d.ts.map +1 -1
  47. package/esm/src/errors/error-registry.js +8 -0
  48. package/esm/src/errors/index.d.ts +1 -1
  49. package/esm/src/errors/index.d.ts.map +1 -1
  50. package/esm/src/errors/index.js +1 -1
  51. package/esm/src/html/html-shell-generator.d.ts.map +1 -1
  52. package/esm/src/html/html-shell-generator.js +6 -0
  53. package/esm/src/platform/compat/media-types.d.ts +5 -0
  54. package/esm/src/platform/compat/media-types.d.ts.map +1 -0
  55. package/esm/src/platform/compat/media-types.js +19 -0
  56. package/esm/src/platform/index.d.ts +1 -0
  57. package/esm/src/platform/index.d.ts.map +1 -1
  58. package/esm/src/platform/index.js +2 -0
  59. package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
  60. package/esm/src/rendering/orchestrator/pipeline.js +116 -105
  61. package/esm/src/server/bootstrap.js +5 -1
  62. package/esm/src/server/dev-server/error-overlay/error-formatter.d.ts +4 -0
  63. package/esm/src/server/dev-server/error-overlay/error-formatter.d.ts.map +1 -1
  64. package/esm/src/server/dev-server/error-overlay/error-formatter.js +15 -0
  65. package/esm/src/server/dev-server/error-overlay/html-template.d.ts +1 -1
  66. package/esm/src/server/dev-server/error-overlay/html-template.d.ts.map +1 -1
  67. package/esm/src/server/dev-server/error-overlay/html-template.js +131 -8
  68. package/esm/src/server/dev-server/error-overlay/index.d.ts +1 -1
  69. package/esm/src/server/dev-server/error-overlay/index.d.ts.map +1 -1
  70. package/esm/src/server/dev-server/error-overlay/index.js +1 -1
  71. package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts +1 -1
  72. package/esm/src/server/dev-server/error-overlay/overlay-renderer.d.ts.map +1 -1
  73. package/esm/src/server/dev-server/error-overlay/overlay-renderer.js +2 -2
  74. package/esm/src/server/dev-server/request-handler.d.ts.map +1 -1
  75. package/esm/src/server/dev-server/request-handler.js +6 -2
  76. package/esm/src/server/services/rendering/ssr.service.d.ts.map +1 -1
  77. package/esm/src/server/services/rendering/ssr.service.js +9 -2
  78. package/esm/src/server/utils/error-html.d.ts.map +1 -1
  79. package/esm/src/server/utils/error-html.js +26 -6
  80. package/package.json +2 -1
  81. package/src/cli/commands/files/command-help.ts +40 -0
  82. package/src/cli/commands/files/command.ts +328 -0
  83. package/src/cli/commands/files/handler.ts +6 -0
  84. package/src/cli/commands/files/index.ts +19 -0
  85. package/src/cli/commands/knowledge/command-help.ts +40 -0
  86. package/src/cli/commands/knowledge/command.ts +513 -0
  87. package/src/cli/commands/knowledge/handler.ts +6 -0
  88. package/src/cli/commands/knowledge/index.ts +2 -0
  89. package/src/cli/commands/knowledge/parser-source.ts +415 -0
  90. package/src/cli/commands/uploads/command-help.ts +45 -0
  91. package/src/cli/commands/uploads/command.ts +465 -0
  92. package/src/cli/commands/uploads/handler.ts +6 -0
  93. package/src/cli/commands/uploads/index.ts +23 -0
  94. package/src/cli/help/command-definitions.ts +6 -0
  95. package/src/cli/router.ts +6 -0
  96. package/src/deno.js +1 -1
  97. package/src/src/errors/error-registry.ts +9 -0
  98. package/src/src/errors/index.ts +1 -0
  99. package/src/src/html/html-shell-generator.ts +9 -0
  100. package/src/src/platform/compat/media-types.ts +23 -0
  101. package/src/src/platform/index.ts +3 -0
  102. package/src/src/rendering/orchestrator/pipeline.ts +186 -172
  103. package/src/src/server/bootstrap.ts +6 -1
  104. package/src/src/server/dev-server/error-overlay/error-formatter.ts +21 -0
  105. package/src/src/server/dev-server/error-overlay/html-template.ts +139 -8
  106. package/src/src/server/dev-server/error-overlay/index.ts +1 -0
  107. package/src/src/server/dev-server/error-overlay/overlay-renderer.ts +2 -1
  108. package/src/src/server/dev-server/request-handler.ts +6 -2
  109. package/src/src/server/services/rendering/ssr.service.ts +9 -2
  110. package/src/src/server/utils/error-html.ts +29 -6
@@ -1 +1 @@
1
- {"version":3,"file":"error-html.d.ts","sourceRoot":"","sources":["../../../../src/src/server/utils/error-html.ts"],"names":[],"mappings":"AAAA,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAQnE;AAuFD,eAAO,MAAM,UAAU;wBACD,MAAM,GAAG,MAAM;0BAUb,MAAM,GAAG,MAAM;kBAQvB,MAAM;sBAQF,MAAM;CAOzB,CAAC"}
1
+ {"version":3,"file":"error-html.d.ts","sourceRoot":"","sources":["../../../../src/src/server/utils/error-html.ts"],"names":[],"mappings":"AAEA,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAQnE;AA4GD,eAAO,MAAM,UAAU;wBACD,MAAM,GAAG,MAAM;0BAUb,MAAM,GAAG,MAAM;kBAQvB,MAAM;sBAQF,MAAM;CAOzB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { escapeHTML } from "../../html/html-escape.js";
1
2
  export function generateErrorHtml(options) {
2
3
  const { statusCode, title, message, pathname, minimal } = options;
3
4
  if (minimal) {
@@ -6,13 +7,16 @@ export function generateErrorHtml(options) {
6
7
  return generateStyledErrorHtml(statusCode, title, message);
7
8
  }
8
9
  function generateStyledErrorHtml(statusCode, title, message) {
10
+ const errorMessage = title === "Not Found" ? `Page not found: ${message}` : message;
11
+ // 4xx = warning (routing/config issue), 5xx = error (something broke)
12
+ const errorType = statusCode >= 500 ? "error" : "warning";
9
13
  return `<!DOCTYPE html>
10
14
  <html lang="en">
11
15
  <head>
12
16
  <meta charset="utf-8">
13
17
  <meta name="viewport" content="width=device-width">
14
18
  <link rel="icon" type="image/png" href="https://cdn.veryfront.com/images/veryfront-favicon.png">
15
- <title>${statusCode} ${title} — Veryfront</title>
19
+ <title>${statusCode} ${escapeHTML(title)} — Veryfront</title>
16
20
  <style>
17
21
  :root {
18
22
  --bg: #ffffff;
@@ -61,9 +65,25 @@ function generateStyledErrorHtml(statusCode, title, message) {
61
65
  </head>
62
66
  <body>
63
67
  <div class="container">
64
- <h1 class="title">${title}</h1>
65
- <p class="message">${message}</p>
68
+ <h1 class="title">${escapeHTML(title)}</h1>
69
+ <p class="message">${escapeHTML(message)}</p>
66
70
  </div>
71
+ <script>
72
+ if (window.parent !== window) {
73
+ try {
74
+ window.parent.postMessage({
75
+ action: 'appUpdated',
76
+ isInitialLoad: true,
77
+ hasError: true,
78
+ url: window.location.href,
79
+ errors: [{
80
+ type: '${errorType}',
81
+ message: ${JSON.stringify(errorMessage).replace(/</g, "\\u003c")}
82
+ }]
83
+ }, '*');
84
+ } catch (e) { /* postMessage may fail in cross-origin iframes */ }
85
+ }
86
+ </script>
67
87
  </body>
68
88
  </html>`;
69
89
  }
@@ -74,11 +94,11 @@ function generateMinimalErrorHtml(statusCode, title, message, pathname) {
74
94
  <head>
75
95
  <meta charset="utf-8"/>
76
96
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
77
- <title>${statusCode} ${title}</title>
97
+ <title>${statusCode} ${escapeHTML(title)}</title>
78
98
  </head>
79
99
  <body>
80
- <h1>${statusCode} ${title}</h1>
81
- <p>${fullMessage}</p>
100
+ <h1>${statusCode} ${escapeHTML(title)}</h1>
101
+ <p>${escapeHTML(fullMessage)}</p>
82
102
  </body>
83
103
  </html>`;
84
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -147,6 +147,7 @@
147
147
  "github-slugger": "2.0.0",
148
148
  "gray-matter": "4.0.3",
149
149
  "mdast-util-to-string": "4.0.0",
150
+ "mime-types": "2.1.35",
150
151
  "react": "19.1.1",
151
152
  "react-dom": "19.1.1",
152
153
  "redis": "4.6.13",
@@ -0,0 +1,40 @@
1
+ import type { CommandHelp } from "../../help/types.js";
2
+
3
+ export const filesHelp: CommandHelp = {
4
+ name: "files",
5
+ description: "List, read, write, and delete project files",
6
+ usage: "veryfront files <command> [options]",
7
+ options: [
8
+ {
9
+ flag: "--project, -p <slug>",
10
+ description: "Project slug override (otherwise inferred from env/config)",
11
+ },
12
+ {
13
+ flag: "--path <prefix>",
14
+ description: "Prefix filter for files list",
15
+ },
16
+ {
17
+ flag: "--from <path>",
18
+ description: "Local file to upload with files put",
19
+ },
20
+ {
21
+ flag: "--output, -o <path>",
22
+ description: "Write files get output to a local file instead of stdout",
23
+ },
24
+ {
25
+ flag: "--json, -j",
26
+ description: "Output machine-readable JSON",
27
+ },
28
+ ],
29
+ examples: [
30
+ "veryfront files list --path knowledge/ --json",
31
+ "veryfront files get knowledge/q1-report.md",
32
+ "veryfront files put knowledge/q1-report.md --from /workspace/knowledge/q1-report.md",
33
+ "veryfront files delete knowledge/q1-report.md",
34
+ ],
35
+ notes: [
36
+ "Subcommands: list, get, put, delete",
37
+ "Uses the project files API, not the uploads store",
38
+ "Designed for precise sandbox writes where `veryfront push` would be too broad",
39
+ ],
40
+ };
@@ -0,0 +1,328 @@
1
+ import { z } from "zod";
2
+ import { createFileSystem } from "../../../src/platform/index.js";
3
+ import { dirname, normalize } from "../../../src/platform/compat/path/index.js";
4
+ import { withSpan } from "../../../src/observability/tracing/otlp-setup.js";
5
+ import { cliLogger } from "../../utils/index.js";
6
+ import { type ApiClient, createApiClient, resolveConfigWithAuth } from "../../shared/config.js";
7
+ import type { ParsedArgs } from "../../shared/types.js";
8
+ import { getFileContent, listAllFiles } from "../pull/command.js";
9
+
10
+ const MAIN_SOURCE = { type: "main" } as const;
11
+
12
+ type RemoteFileEntry = Awaited<ReturnType<typeof listAllFiles>>[number];
13
+
14
+ const FilesListArgsSchema = z.object({
15
+ projectSlug: z.string().optional(),
16
+ projectDir: z.string().optional(),
17
+ path: z.string().optional(),
18
+ json: z.boolean().default(false),
19
+ quiet: z.boolean().default(false),
20
+ });
21
+
22
+ const FilesGetArgsSchema = z.object({
23
+ projectSlug: z.string().optional(),
24
+ projectDir: z.string().optional(),
25
+ remotePath: z.string().min(1),
26
+ output: z.string().optional(),
27
+ json: z.boolean().default(false),
28
+ quiet: z.boolean().default(false),
29
+ });
30
+
31
+ const FilesPutArgsSchema = z.object({
32
+ projectSlug: z.string().optional(),
33
+ projectDir: z.string().optional(),
34
+ remotePath: z.string().min(1),
35
+ from: z.string().min(1),
36
+ json: z.boolean().default(false),
37
+ quiet: z.boolean().default(false),
38
+ });
39
+
40
+ const FilesDeleteArgsSchema = z.object({
41
+ projectSlug: z.string().optional(),
42
+ projectDir: z.string().optional(),
43
+ remotePath: z.string().min(1),
44
+ json: z.boolean().default(false),
45
+ quiet: z.boolean().default(false),
46
+ });
47
+
48
+ export type FilesListOptions = z.infer<typeof FilesListArgsSchema>;
49
+ export type FilesGetOptions = z.infer<typeof FilesGetArgsSchema>;
50
+ export type FilesPutOptions = z.infer<typeof FilesPutArgsSchema>;
51
+ export type FilesDeleteOptions = z.infer<typeof FilesDeleteArgsSchema>;
52
+
53
+ function getStringArg(args: ParsedArgs, ...keys: string[]): string | undefined {
54
+ for (const key of keys) {
55
+ const value = args[key];
56
+ if (typeof value === "string" && value) return value;
57
+ }
58
+ return undefined;
59
+ }
60
+
61
+ function getBooleanArg(args: ParsedArgs, ...keys: string[]): boolean {
62
+ return keys.some((key) => Boolean(args[key]));
63
+ }
64
+
65
+ function printJson(value: unknown): void {
66
+ console.log(JSON.stringify(value, null, 2));
67
+ }
68
+
69
+ function showFilesUsage(): void {
70
+ console.log(`
71
+ Veryfront Files
72
+
73
+ Usage:
74
+ veryfront files list [options]
75
+ veryfront files get <remote-path> [--output <local-file>] [options]
76
+ veryfront files put <remote-path> --from <local-file> [options]
77
+ veryfront files delete <remote-path> [options]
78
+
79
+ Subcommands:
80
+ list List project files
81
+ get Read a remote project file
82
+ put Upload a local file into the project files tree
83
+ delete Delete a remote project file
84
+ `);
85
+ }
86
+
87
+ function normalizeProjectFilePath(remotePath: string): string {
88
+ const normalizedPath = normalize(remotePath).replace(/^\/+/, "");
89
+ if (!normalizedPath || normalizedPath.startsWith("..") || normalizedPath.startsWith("/")) {
90
+ throw new Error(`Invalid remote file path: ${remotePath}`);
91
+ }
92
+ return normalizedPath;
93
+ }
94
+
95
+ export function parseFilesListArgs(
96
+ args: ParsedArgs,
97
+ ): z.SafeParseReturnType<unknown, FilesListOptions> {
98
+ return FilesListArgsSchema.safeParse({
99
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
100
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
101
+ path: getStringArg(args, "path"),
102
+ json: getBooleanArg(args, "json", "j"),
103
+ quiet: getBooleanArg(args, "quiet", "q"),
104
+ });
105
+ }
106
+
107
+ export function parseFilesGetArgs(
108
+ args: ParsedArgs,
109
+ ): z.SafeParseReturnType<unknown, FilesGetOptions> {
110
+ return FilesGetArgsSchema.safeParse({
111
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
112
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
113
+ remotePath: typeof args._[2] === "string" ? args._[2] : "",
114
+ output: getStringArg(args, "output", "o"),
115
+ json: getBooleanArg(args, "json", "j"),
116
+ quiet: getBooleanArg(args, "quiet", "q"),
117
+ });
118
+ }
119
+
120
+ export function parseFilesPutArgs(
121
+ args: ParsedArgs,
122
+ ): z.SafeParseReturnType<unknown, FilesPutOptions> {
123
+ return FilesPutArgsSchema.safeParse({
124
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
125
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
126
+ remotePath: typeof args._[2] === "string" ? args._[2] : "",
127
+ from: getStringArg(args, "from") ?? "",
128
+ json: getBooleanArg(args, "json", "j"),
129
+ quiet: getBooleanArg(args, "quiet", "q"),
130
+ });
131
+ }
132
+
133
+ export function parseFilesDeleteArgs(
134
+ args: ParsedArgs,
135
+ ): z.SafeParseReturnType<unknown, FilesDeleteOptions> {
136
+ return FilesDeleteArgsSchema.safeParse({
137
+ projectSlug: getStringArg(args, "project", "p", "project-slug"),
138
+ projectDir: getStringArg(args, "project-dir", "dir", "d"),
139
+ remotePath: typeof args._[2] === "string" ? args._[2] : "",
140
+ json: getBooleanArg(args, "json", "j"),
141
+ quiet: getBooleanArg(args, "quiet", "q"),
142
+ });
143
+ }
144
+
145
+ export function buildRemoteFileUrl(projectSlug: string, remotePath: string): string {
146
+ const normalizedPath = normalizeProjectFilePath(remotePath);
147
+ return `/projects/${projectSlug}/files/${encodeURIComponent(normalizedPath)}`;
148
+ }
149
+
150
+ export async function listRemoteFiles(
151
+ client: ApiClient,
152
+ projectSlug: string,
153
+ options: Pick<FilesListOptions, "path"> = {},
154
+ ): Promise<RemoteFileEntry[]> {
155
+ const files = await listAllFiles(client, projectSlug, MAIN_SOURCE);
156
+ if (!options.path) return files;
157
+ return files.filter((file) => file.path.startsWith(options.path!));
158
+ }
159
+
160
+ export async function getRemoteFile(
161
+ client: ApiClient,
162
+ projectSlug: string,
163
+ remotePath: string,
164
+ ): Promise<string> {
165
+ return getFileContent(client, projectSlug, normalizeProjectFilePath(remotePath), MAIN_SOURCE);
166
+ }
167
+
168
+ export async function putRemoteFileFromLocal(
169
+ client: ApiClient,
170
+ projectSlug: string,
171
+ remotePath: string,
172
+ localPath: string,
173
+ ): Promise<{ path: string }> {
174
+ const fs = createFileSystem();
175
+ const content = await fs.readTextFile(localPath);
176
+ const result = await client.put<{ path: string }>(buildRemoteFileUrl(projectSlug, remotePath), {
177
+ content,
178
+ });
179
+ return { path: result.path ?? normalizeProjectFilePath(remotePath) };
180
+ }
181
+
182
+ export async function deleteRemoteFile(
183
+ client: ApiClient,
184
+ projectSlug: string,
185
+ remotePath: string,
186
+ ): Promise<void> {
187
+ await client.delete(buildRemoteFileUrl(projectSlug, remotePath));
188
+ }
189
+
190
+ export async function filesCommand(args: ParsedArgs): Promise<void> {
191
+ const subcommand = typeof args._[1] === "string" ? args._[1] : undefined;
192
+
193
+ if (!subcommand || subcommand === "help") {
194
+ showFilesUsage();
195
+ return;
196
+ }
197
+
198
+ await withSpan("cli.command.files", async () => {
199
+ switch (subcommand) {
200
+ case "list": {
201
+ const parsed = parseFilesListArgs(args);
202
+ if (!parsed.success) {
203
+ throw new Error(`Invalid files list arguments: ${parsed.error.message}`);
204
+ }
205
+
206
+ const options = parsed.data;
207
+ let config = await resolveConfigWithAuth(options.projectDir);
208
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
209
+
210
+ const client = createApiClient(config);
211
+ const files = await listRemoteFiles(client, config.projectSlug, options);
212
+
213
+ if (options.json) {
214
+ printJson(files);
215
+ return;
216
+ }
217
+
218
+ if (!files.length) {
219
+ cliLogger.info("No files found.");
220
+ return;
221
+ }
222
+
223
+ for (const file of files) {
224
+ console.log(file.path);
225
+ }
226
+ return;
227
+ }
228
+
229
+ case "get": {
230
+ const parsed = parseFilesGetArgs(args);
231
+ if (!parsed.success) {
232
+ throw new Error(`Invalid files get arguments: ${parsed.error.message}`);
233
+ }
234
+
235
+ const options = parsed.data;
236
+ let config = await resolveConfigWithAuth(options.projectDir);
237
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
238
+
239
+ const client = createApiClient(config);
240
+ const content = await getRemoteFile(client, config.projectSlug, options.remotePath);
241
+
242
+ if (options.output) {
243
+ const fs = createFileSystem();
244
+ await fs.mkdir(dirname(options.output), { recursive: true });
245
+ await fs.writeTextFile(options.output, content);
246
+ if (options.json) {
247
+ printJson({
248
+ path: normalizeProjectFilePath(options.remotePath),
249
+ output: options.output,
250
+ });
251
+ return;
252
+ }
253
+ if (!options.quiet) {
254
+ cliLogger.info(
255
+ `Downloaded ${normalizeProjectFilePath(options.remotePath)} -> ${options.output}`,
256
+ );
257
+ }
258
+ return;
259
+ }
260
+
261
+ if (options.json) {
262
+ printJson({ path: normalizeProjectFilePath(options.remotePath), content });
263
+ return;
264
+ }
265
+
266
+ console.log(content);
267
+ return;
268
+ }
269
+
270
+ case "put": {
271
+ const parsed = parseFilesPutArgs(args);
272
+ if (!parsed.success) {
273
+ throw new Error(`Invalid files put arguments: ${parsed.error.message}`);
274
+ }
275
+
276
+ const options = parsed.data;
277
+ let config = await resolveConfigWithAuth(options.projectDir);
278
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
279
+
280
+ const client = createApiClient(config);
281
+ const result = await putRemoteFileFromLocal(
282
+ client,
283
+ config.projectSlug,
284
+ options.remotePath,
285
+ options.from,
286
+ );
287
+
288
+ if (options.json) {
289
+ printJson(result);
290
+ return;
291
+ }
292
+
293
+ if (!options.quiet) {
294
+ cliLogger.info(`Uploaded ${options.from} -> ${result.path}`);
295
+ }
296
+ return;
297
+ }
298
+
299
+ case "delete":
300
+ case "rm": {
301
+ const parsed = parseFilesDeleteArgs(args);
302
+ if (!parsed.success) {
303
+ throw new Error(`Invalid files delete arguments: ${parsed.error.message}`);
304
+ }
305
+
306
+ const options = parsed.data;
307
+ let config = await resolveConfigWithAuth(options.projectDir);
308
+ if (options.projectSlug) config = { ...config, projectSlug: options.projectSlug };
309
+
310
+ const client = createApiClient(config);
311
+ await deleteRemoteFile(client, config.projectSlug, options.remotePath);
312
+
313
+ if (options.json) {
314
+ printJson({ success: true, path: normalizeProjectFilePath(options.remotePath) });
315
+ return;
316
+ }
317
+
318
+ if (!options.quiet) {
319
+ cliLogger.info(`Deleted ${normalizeProjectFilePath(options.remotePath)}`);
320
+ }
321
+ return;
322
+ }
323
+
324
+ default:
325
+ showFilesUsage();
326
+ }
327
+ });
328
+ }
@@ -0,0 +1,6 @@
1
+ import type { ParsedArgs } from "../../shared/types.js";
2
+ import { filesCommand } from "./command.js";
3
+
4
+ export async function handleFilesCommand(args: ParsedArgs): Promise<void> {
5
+ await filesCommand(args);
6
+ }
@@ -0,0 +1,19 @@
1
+ export {
2
+ buildRemoteFileUrl,
3
+ deleteRemoteFile,
4
+ filesCommand,
5
+ getRemoteFile,
6
+ listRemoteFiles,
7
+ parseFilesDeleteArgs,
8
+ parseFilesGetArgs,
9
+ parseFilesListArgs,
10
+ parseFilesPutArgs,
11
+ putRemoteFileFromLocal,
12
+ } from "./command.js";
13
+ export type {
14
+ FilesDeleteOptions,
15
+ FilesGetOptions,
16
+ FilesListOptions,
17
+ FilesPutOptions,
18
+ } from "./command.js";
19
+ export { handleFilesCommand } from "./handler.js";
@@ -0,0 +1,40 @@
1
+ import type { CommandHelp } from "../../help/types.js";
2
+
3
+ export const knowledgeHelp: CommandHelp = {
4
+ name: "knowledge",
5
+ description: "Ingest documents into the project knowledge base",
6
+ usage: "veryfront knowledge ingest <source> [options]",
7
+ options: [
8
+ {
9
+ flag: "--project, -p <slug>",
10
+ description: "Project slug override (otherwise inferred from env/config)",
11
+ },
12
+ {
13
+ flag: "--path <prefix>",
14
+ description: "Upload prefix or local directory used with --all",
15
+ },
16
+ {
17
+ flag: "--all",
18
+ description: "Ingest all files under the given --path prefix or directory",
19
+ },
20
+ {
21
+ flag: "--recursive",
22
+ description: "Recurse into subdirectories for local directory ingestion",
23
+ },
24
+ {
25
+ flag: "--json, -j",
26
+ description: "Output machine-readable JSON",
27
+ },
28
+ ],
29
+ examples: [
30
+ "veryfront knowledge ingest uploads/contracts/q1.pdf --json",
31
+ "veryfront knowledge ingest /workspace/uploads/q1.pdf --json",
32
+ "veryfront knowledge ingest --path uploads/ --all --json",
33
+ ],
34
+ notes: [
35
+ "Primary subcommand: ingest",
36
+ "`uploads/...` means a remote project upload; use `./uploads/...` or `/workspace/uploads/...` to force a local file",
37
+ "`ingest` orchestrates upload resolution, parsing, and project file writes",
38
+ "Requires python3; non-text formats also require the supported parser packages unless you run inside the Veryfront sandbox",
39
+ ],
40
+ };