@vectorasystems/cli 0.2.0 → 0.2.2

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.
package/bin/vectora.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectorasystems/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Vectora CLI — AI-powered project orchestration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -101,10 +101,22 @@ export async function download(id, opts) {
101
101
  }
102
102
 
103
103
  // Get presigned URL + suggested filename from API
104
- const { url, filename } = await getArtifactDownloadUrl(id);
104
+ const { url, filename, inlineBase64 } = await getArtifactDownloadUrl(id);
105
105
 
106
106
  const outPath = resolve(opts.out ?? filename);
107
107
 
108
+ // Local-storage fallback: API returns the file bytes inline when no
109
+ // presigned URL backend is configured.
110
+ if (inlineBase64) {
111
+ const buffer = Buffer.from(inlineBase64, 'base64');
112
+ await writeFile(outPath, buffer);
113
+ success(`Saved to ${chalk.bold(outPath)} ${chalk.dim(`(${(buffer.length / 1024).toFixed(1)} KB)`)}`);
114
+ return;
115
+ }
116
+ if (!url) {
117
+ throw new Error('Artifact download URL was not provided by the API');
118
+ }
119
+
108
120
  // Fetch directly from R2 via presigned URL
109
121
  const res = await fetch(url, { signal: AbortSignal.timeout(60_000) });
110
122
  if (!res.ok) {
@@ -48,15 +48,34 @@ export async function* parseSseStream(body) {
48
48
  * @yields {{ event: string, data: object }}
49
49
  */
50
50
  export async function* streamPhaseProgress(baseUrl, jobId, token) {
51
- const res = await fetch(`${baseUrl}/v1/phases/${jobId}?token=${token}`, {
52
- signal: AbortSignal.timeout(5 * 60 * 1000), // 5 min
53
- });
51
+ while (true) {
52
+ const res = await fetch(`${baseUrl}/v1/phases/${jobId}?token=${token}`);
54
53
 
55
- if (!res.ok || !res.body) {
56
- throw new Error(`Phase SSE failed: HTTP ${res.status}`);
57
- }
54
+ if (!res.ok || !res.body) {
55
+ throw new Error(`Phase SSE failed: HTTP ${res.status}`);
56
+ }
58
57
 
59
- yield* parseSseStream(res.body);
58
+ let reconnect = false;
59
+
60
+ for await (const frame of parseSseStream(res.body)) {
61
+ if (frame.event === 'job:timeout') {
62
+ reconnect = true;
63
+ break;
64
+ }
65
+
66
+ yield frame;
67
+
68
+ if (frame.event === 'job:completed' || frame.event === 'job:failed') {
69
+ return;
70
+ }
71
+ }
72
+
73
+ if (!reconnect) {
74
+ return;
75
+ }
76
+
77
+ await new Promise((resolve) => setTimeout(resolve, 1000));
78
+ }
60
79
  }
61
80
 
62
81
  /**
@@ -43,11 +43,23 @@ export function ArtifactBrowser({ projectId, onBack }) {
43
43
  setSavedPath(null);
44
44
  setError(null);
45
45
  try {
46
- const { url, filename } = await getArtifactDownloadUrl(item.value);
46
+ const { url, filename, inlineBase64 } = await getArtifactDownloadUrl(item.value);
47
+ const outPath = resolve(filename);
48
+
49
+ // Local-storage fallback: the API can return inline bytes when no
50
+ // presigned URL backend is available.
51
+ if (inlineBase64) {
52
+ const buffer = Buffer.from(inlineBase64, 'base64');
53
+ await writeFile(outPath, buffer);
54
+ setSavedPath(outPath);
55
+ return;
56
+ }
57
+
58
+ if (!url) throw new Error('Artifact download URL was not provided by the API');
59
+
47
60
  const res = await fetch(url, { signal: AbortSignal.timeout(60_000) });
48
61
  if (!res.ok) throw new Error(`Download failed: HTTP ${res.status}`);
49
62
  const buffer = Buffer.from(await res.arrayBuffer());
50
- const outPath = resolve(filename);
51
63
  await writeFile(outPath, buffer);
52
64
  setSavedPath(outPath);
53
65
  } catch (err) {