@vibecodr/cli 0.2.8 → 0.2.9
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/dist/commands/call.js +4 -4
- package/dist/commands/upload.js +23 -7
- package/dist/core/mcp-client.js +4 -4
- package/docs/commands.md +4 -2
- package/package.json +1 -1
package/dist/commands/call.js
CHANGED
|
@@ -42,12 +42,12 @@ async function readStdin() {
|
|
|
42
42
|
}
|
|
43
43
|
return Buffer.concat(chunks).toString("utf8");
|
|
44
44
|
}
|
|
45
|
-
export async function callToolWithRetry(context, toolName, input, allowLogin) {
|
|
45
|
+
export async function callToolWithRetry(context, toolName, input, allowLogin, options) {
|
|
46
46
|
const { profileName, serverUrl } = await context.tokenManager.resolveProfile(context.globalOptions);
|
|
47
47
|
const existingSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
48
48
|
try {
|
|
49
49
|
return {
|
|
50
|
-
result: await context.runtimeClient.callTool(serverUrl, existingSession?.accessToken, toolName, input),
|
|
50
|
+
result: await context.runtimeClient.callTool(serverUrl, existingSession?.accessToken, toolName, input, options),
|
|
51
51
|
...(existingSession ? { session: existingSession } : {})
|
|
52
52
|
};
|
|
53
53
|
}
|
|
@@ -57,7 +57,7 @@ export async function callToolWithRetry(context, toolName, input, allowLogin) {
|
|
|
57
57
|
if (error.machineCode === "auth.required" && existingSession?.refreshToken) {
|
|
58
58
|
const refreshed = await context.tokenManager.refresh(profileName, existingSession);
|
|
59
59
|
return {
|
|
60
|
-
result: await context.runtimeClient.callTool(serverUrl, refreshed.session.accessToken, toolName, input),
|
|
60
|
+
result: await context.runtimeClient.callTool(serverUrl, refreshed.session.accessToken, toolName, input, options),
|
|
61
61
|
session: refreshed.session
|
|
62
62
|
};
|
|
63
63
|
}
|
|
@@ -68,7 +68,7 @@ export async function callToolWithRetry(context, toolName, input, allowLogin) {
|
|
|
68
68
|
});
|
|
69
69
|
const nextSession = await context.tokenManager.getSession(profileName, serverUrl);
|
|
70
70
|
return {
|
|
71
|
-
result: await context.runtimeClient.callTool(serverUrl, nextSession?.accessToken, toolName, input),
|
|
71
|
+
result: await context.runtimeClient.callTool(serverUrl, nextSession?.accessToken, toolName, input, options),
|
|
72
72
|
...(nextSession ? { session: nextSession } : {})
|
|
73
73
|
};
|
|
74
74
|
}
|
package/dist/commands/upload.js
CHANGED
|
@@ -10,6 +10,7 @@ const CREATE_STAGED_UPLOAD_TOOL_NAME = "create_staged_upload";
|
|
|
10
10
|
const COMPLETE_STAGED_UPLOAD_TOOL_NAME = "complete_staged_upload";
|
|
11
11
|
const ABORT_STAGED_UPLOAD_TOOL_NAME = "abort_staged_upload";
|
|
12
12
|
const SOURCE_ZIP_CONTENT_TYPE = "application/zip";
|
|
13
|
+
const DEFAULT_STAGED_UPLOAD_TIMEOUT_SECONDS = 600;
|
|
13
14
|
const SOURCE_ZIP_CONTENT_TYPES = new Set(["application/zip", "application/x-zip-compressed"]);
|
|
14
15
|
const COVER_IMAGE_CONTENT_TYPES = new Set(["image/png", "image/jpeg", "image/webp", "image/avif"]);
|
|
15
16
|
const AVATAR_IMAGE_CONTENT_TYPES = new Set(["image/png", "image/jpeg", "image/webp", "image/gif"]);
|
|
@@ -79,7 +80,7 @@ function readCompleteResult(result, fallbackUploadId) {
|
|
|
79
80
|
}
|
|
80
81
|
function parseUploadArgs(args) {
|
|
81
82
|
const { flags, positionals } = parseFlags(args, {
|
|
82
|
-
valueFlags: ["zip", "image", "file", "kind", "content-type", "idempotency-key", "root-hint", "entry-hint"],
|
|
83
|
+
valueFlags: ["zip", "image", "file", "kind", "content-type", "idempotency-key", "root-hint", "entry-hint", "timeout-sec"],
|
|
83
84
|
booleanFlags: ["no-login"]
|
|
84
85
|
});
|
|
85
86
|
const zipPath = readString(flags["zip"]);
|
|
@@ -98,6 +99,7 @@ function parseUploadArgs(args) {
|
|
|
98
99
|
const rootHint = readString(flags["root-hint"]);
|
|
99
100
|
const entryHint = readString(flags["entry-hint"]);
|
|
100
101
|
const contentType = readString(flags["content-type"]);
|
|
102
|
+
const timeoutSeconds = parseUploadTimeoutSeconds(flags["timeout-sec"]);
|
|
101
103
|
const rawKind = readString(flags["kind"]);
|
|
102
104
|
let kind = imagePath ? "cover_image" : "source_zip";
|
|
103
105
|
if (rawKind) {
|
|
@@ -116,9 +118,22 @@ function parseUploadArgs(args) {
|
|
|
116
118
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
117
119
|
...(rootHint ? { rootHint } : {}),
|
|
118
120
|
...(entryHint ? { entryHint } : {}),
|
|
121
|
+
timeoutSeconds,
|
|
119
122
|
allowLogin: flags["no-login"] !== true,
|
|
120
123
|
};
|
|
121
124
|
}
|
|
125
|
+
function parseUploadTimeoutSeconds(value) {
|
|
126
|
+
if (value === undefined)
|
|
127
|
+
return DEFAULT_STAGED_UPLOAD_TIMEOUT_SECONDS;
|
|
128
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
129
|
+
throw new CliError("usage.upload_timeout_invalid", "--timeout-sec must be a positive number of seconds.", EXIT_CODES.usage);
|
|
130
|
+
}
|
|
131
|
+
const parsed = Number(value);
|
|
132
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
133
|
+
throw new CliError("usage.upload_timeout_invalid", "--timeout-sec must be a positive number of seconds.", EXIT_CODES.usage);
|
|
134
|
+
}
|
|
135
|
+
return parsed;
|
|
136
|
+
}
|
|
122
137
|
function sha256Hex(bytes) {
|
|
123
138
|
return createHash("sha256").update(bytes).digest("hex");
|
|
124
139
|
}
|
|
@@ -158,9 +173,9 @@ function toBlob(bytes, contentType) {
|
|
|
158
173
|
new Uint8Array(buffer).set(bytes);
|
|
159
174
|
return new Blob([buffer], { type: contentType });
|
|
160
175
|
}
|
|
161
|
-
async function abortBestEffort(context, uploadId, allowLogin) {
|
|
176
|
+
async function abortBestEffort(context, uploadId, allowLogin, timeoutSeconds) {
|
|
162
177
|
try {
|
|
163
|
-
await callToolWithRetry(context, ABORT_STAGED_UPLOAD_TOOL_NAME, { uploadId }, allowLogin);
|
|
178
|
+
await callToolWithRetry(context, ABORT_STAGED_UPLOAD_TOOL_NAME, { uploadId }, allowLogin, { timeoutSeconds });
|
|
164
179
|
}
|
|
165
180
|
catch {
|
|
166
181
|
// Best-effort cleanup only. Preserve the upload failure as the surfaced error.
|
|
@@ -177,7 +192,7 @@ async function putBytesToStagedUpload(input) {
|
|
|
177
192
|
}
|
|
178
193
|
}
|
|
179
194
|
export async function runUploadCommand(args, context) {
|
|
180
|
-
if (showHelpIfRequested(args, context, "Usage: vibecodr upload --zip <path> [--idempotency-key <key>] [--root-hint <path>] [--entry-hint <path>] [--no-login]\n vibecodr upload --image <path> [--kind cover_image|avatar_image] [--content-type <mime>] [--no-login]"))
|
|
195
|
+
if (showHelpIfRequested(args, context, "Usage: vibecodr upload --zip <path> [--idempotency-key <key>] [--root-hint <path>] [--entry-hint <path>] [--timeout-sec <n>] [--no-login]\n vibecodr upload --image <path> [--kind cover_image|avatar_image] [--content-type <mime>] [--timeout-sec <n>] [--no-login]"))
|
|
181
196
|
return;
|
|
182
197
|
const input = parseUploadArgs(args);
|
|
183
198
|
const fileInfo = await stat(input.filePath).catch((error) => {
|
|
@@ -193,6 +208,7 @@ export async function runUploadCommand(args, context) {
|
|
|
193
208
|
const fileName = basename(input.filePath) || (input.kind === "source_zip" ? "source.zip" : "image");
|
|
194
209
|
const contentType = inferContentType(input.kind, fileName, input.contentType);
|
|
195
210
|
const hash = sha256Hex(bytes);
|
|
211
|
+
const mcpRequestOptions = { timeoutSeconds: input.timeoutSeconds };
|
|
196
212
|
const { result: createResult } = await callToolWithRetry(context, CREATE_STAGED_UPLOAD_TOOL_NAME, {
|
|
197
213
|
kind: input.kind,
|
|
198
214
|
fileName,
|
|
@@ -201,7 +217,7 @@ export async function runUploadCommand(args, context) {
|
|
|
201
217
|
sha256: hash,
|
|
202
218
|
createdBySurface: input.kind === "source_zip" ? "cli.upload.zip" : "cli.upload.image",
|
|
203
219
|
...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
|
|
204
|
-
}, input.allowLogin);
|
|
220
|
+
}, input.allowLogin, mcpRequestOptions);
|
|
205
221
|
const created = readCreateResult(createResult);
|
|
206
222
|
try {
|
|
207
223
|
await putBytesToStagedUpload({
|
|
@@ -214,7 +230,7 @@ export async function runUploadCommand(args, context) {
|
|
|
214
230
|
uploadId: created.uploadId,
|
|
215
231
|
sizeBytes: bytes.byteLength,
|
|
216
232
|
sha256: hash,
|
|
217
|
-
}, input.allowLogin);
|
|
233
|
+
}, input.allowLogin, mcpRequestOptions);
|
|
218
234
|
const completed = readCompleteResult(completeResult, created.uploadId);
|
|
219
235
|
const quickPublishPayload = {
|
|
220
236
|
...(input.kind === "source_zip"
|
|
@@ -264,7 +280,7 @@ export async function runUploadCommand(args, context) {
|
|
|
264
280
|
]);
|
|
265
281
|
}
|
|
266
282
|
catch (error) {
|
|
267
|
-
await abortBestEffort(context, created.uploadId, input.allowLogin);
|
|
283
|
+
await abortBestEffort(context, created.uploadId, input.allowLogin, input.timeoutSeconds);
|
|
268
284
|
throw error;
|
|
269
285
|
}
|
|
270
286
|
}
|
package/dist/core/mcp-client.js
CHANGED
|
@@ -13,8 +13,8 @@ export const CLIENT_INFO = {
|
|
|
13
13
|
name: "vibecodr-mcp",
|
|
14
14
|
version: packageVersion
|
|
15
15
|
};
|
|
16
|
-
export function resolveToolRequestTimeoutMs(args) {
|
|
17
|
-
const raw = args["timeoutSeconds"];
|
|
16
|
+
export function resolveToolRequestTimeoutMs(args, options) {
|
|
17
|
+
const raw = options?.timeoutSeconds ?? args["timeoutSeconds"];
|
|
18
18
|
if (raw === undefined)
|
|
19
19
|
return undefined;
|
|
20
20
|
if (typeof raw !== "number" || !Number.isFinite(raw))
|
|
@@ -32,9 +32,9 @@ export class McpRuntimeClient {
|
|
|
32
32
|
return result.tools;
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
-
async callTool(serverUrl, accessToken, name, args) {
|
|
35
|
+
async callTool(serverUrl, accessToken, name, args, options) {
|
|
36
36
|
return await this.withClient(serverUrl, accessToken, async (client) => {
|
|
37
|
-
const timeout = resolveToolRequestTimeoutMs(args);
|
|
37
|
+
const timeout = resolveToolRequestTimeoutMs(args, options);
|
|
38
38
|
return await client.callTool({
|
|
39
39
|
name,
|
|
40
40
|
arguments: args
|
package/docs/commands.md
CHANGED
|
@@ -70,9 +70,9 @@ Known mutating tools require explicit confirmation through `--confirm`. The CLI
|
|
|
70
70
|
|
|
71
71
|
Syntax:
|
|
72
72
|
|
|
73
|
-
`vibecodr upload --zip <path> [--idempotency-key <key>] [--root-hint <path>] [--entry-hint <path>] [--no-login]`
|
|
73
|
+
`vibecodr upload --zip <path> [--idempotency-key <key>] [--root-hint <path>] [--entry-hint <path>] [--timeout-sec <n>] [--no-login]`
|
|
74
74
|
|
|
75
|
-
`vibecodr upload --image <path> [--kind cover_image|avatar_image] [--content-type <mime>] [--no-login]`
|
|
75
|
+
`vibecodr upload --image <path> [--kind cover_image|avatar_image] [--content-type <mime>] [--timeout-sec <n>] [--no-login]`
|
|
76
76
|
|
|
77
77
|
Stages a local ZIP or image through Vibecodr's API-owned upload session flow. The CLI asks the MCP gateway for a short-lived direct R2 PUT URL, uploads the bytes directly to R2, completes server-side verification, and prints safe identifiers only.
|
|
78
78
|
|
|
@@ -80,6 +80,8 @@ ZIP uploads print a `quickPublishPayload` snippet using `payload.importMode: "st
|
|
|
80
80
|
|
|
81
81
|
Cover images support PNG, JPEG, WebP, and AVIF. Avatar images support PNG, JPEG, WebP, and GIF.
|
|
82
82
|
|
|
83
|
+
Staged upload MCP setup and completion calls use a longer client-side wait by default so large ZIP verification does not fail only because the local CLI stopped waiting. Use `--timeout-sec <n>` only when a slower network needs a different local wait; this value is transport behavior and is not forwarded as a server tool argument.
|
|
84
|
+
|
|
83
85
|
The presigned URL is a bearer credential and is never printed in command output. Legacy `zip_import` / `fileBase64` remains a compatibility path for small payloads, not the preferred CLI path for whole repos or launch images.
|
|
84
86
|
|
|
85
87
|
### `pulse-setup`
|