skydive-cli 0.5.0-beta.33 → 0.5.0-beta.36

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.
@@ -1,6 +1,108 @@
1
1
  #!/usr/bin/env node
2
2
  import { WebSocket } from "ws";
3
3
 
4
+ //#region ../sandbox-stream-protocol/src/fs.ts
5
+ /** fs frame type bytes. Disjoint from FRAME.* in ./index.ts. */
6
+ const FS_FRAME = {
7
+ REQ: 32,
8
+ RES: 33
9
+ };
10
+ /** Filesystem operations the channel supports. One byte on the wire. */
11
+ const FS_OP = {
12
+ LIST: 1,
13
+ STAT: 2,
14
+ READ: 3,
15
+ WRITE: 4,
16
+ MKDIR: 5,
17
+ RENAME: 6,
18
+ REMOVE: 7,
19
+ EXISTS: 8
20
+ };
21
+ /** Reply status. OK carries a result; ERR carries a message in `json.message`. */
22
+ const FS_STATUS = {
23
+ OK: 0,
24
+ ERR: 1
25
+ };
26
+ const FS_MAX_BLOB_BYTES = 8 * 1024 * 1024;
27
+ const OP_TO_CODE = {
28
+ list: FS_OP.LIST,
29
+ stat: FS_OP.STAT,
30
+ read: FS_OP.READ,
31
+ write: FS_OP.WRITE,
32
+ mkdir: FS_OP.MKDIR,
33
+ rename: FS_OP.RENAME,
34
+ remove: FS_OP.REMOVE,
35
+ exists: FS_OP.EXISTS
36
+ };
37
+ const CODE_TO_OP = new Map(Object.entries(OP_TO_CODE).map(([op, code]) => [code, op]));
38
+ const textEncoder = new TextEncoder();
39
+ const textDecoder = new TextDecoder();
40
+ function frame(type, reqId, byte2, json, blob) {
41
+ const jsonBytes = textEncoder.encode(JSON.stringify(json ?? {}));
42
+ const out = new Uint8Array(10 + jsonBytes.length + blob.length);
43
+ const dv = new DataView(out.buffer);
44
+ out[0] = type;
45
+ dv.setUint32(1, reqId >>> 0);
46
+ out[5] = byte2;
47
+ dv.setUint32(6, jsonBytes.length);
48
+ out.set(jsonBytes, 10);
49
+ out.set(blob, 10 + jsonBytes.length);
50
+ return out;
51
+ }
52
+ const EMPTY = new Uint8Array(0);
53
+ /** client → server: encode an fs request. `blob` is the write payload, or null. */
54
+ function encodeFsRequest(reqId, req, blob) {
55
+ return frame(FS_FRAME.REQ, reqId, OP_TO_CODE[req.op], req, blob ?? EMPTY);
56
+ }
57
+ /**
58
+ * Decode a server fs reply frame. Returns null for a malformed frame so a peer
59
+ * on a newer protocol can't crash the client.
60
+ */
61
+ function decodeFsResponse(frameBytes) {
62
+ const parsed = parseFrame(FS_FRAME.RES, frameBytes);
63
+ if (!parsed) return null;
64
+ if (parsed.byte2 === FS_STATUS.ERR) {
65
+ const message = typeof parsed.json.message === "string" ? parsed.json.message : "fs operation failed";
66
+ return {
67
+ reqId: parsed.reqId,
68
+ status: "error",
69
+ message
70
+ };
71
+ }
72
+ return {
73
+ reqId: parsed.reqId,
74
+ status: "ok",
75
+ result: parsed.json,
76
+ blob: parsed.blob
77
+ };
78
+ }
79
+ function parseFrame(expectedType, frameBytes) {
80
+ if (frameBytes.length < 10) return null;
81
+ if (frameBytes[0] !== expectedType) return null;
82
+ const dv = new DataView(frameBytes.buffer, frameBytes.byteOffset, frameBytes.byteLength);
83
+ const reqId = dv.getUint32(1);
84
+ const byte2 = frameBytes[5] ?? 0;
85
+ const jsonLen = dv.getUint32(6);
86
+ const jsonStart = 10;
87
+ const jsonEnd = jsonStart + jsonLen;
88
+ if (jsonEnd > frameBytes.length) return null;
89
+ let json;
90
+ try {
91
+ const parsed = jsonLen ? JSON.parse(textDecoder.decode(frameBytes.subarray(jsonStart, jsonEnd))) : {};
92
+ if (typeof parsed !== "object" || parsed === null) return null;
93
+ json = parsed;
94
+ } catch {
95
+ return null;
96
+ }
97
+ return {
98
+ reqId,
99
+ byte2,
100
+ json,
101
+ blob: frameBytes.subarray(jsonEnd)
102
+ };
103
+ }
104
+
105
+ //#endregion
4
106
  //#region ../sandbox-stream-protocol/src/index.ts
5
107
  const SANDBOX_STREAM_PATH = "/api/v1/sandbox/stream";
6
108
  const FRAME = {
@@ -19,11 +121,15 @@ function streamSpecToQuery(spec) {
19
121
  cols: String(spec.cols),
20
122
  rows: String(spec.rows)
21
123
  };
22
- return {
124
+ if (spec.mode === "exec") return {
23
125
  agentId: spec.agentId,
24
126
  mode: "exec",
25
127
  command: spec.command
26
128
  };
129
+ return {
130
+ agentId: spec.agentId,
131
+ mode: "fs"
132
+ };
27
133
  }
28
134
  function withType(type, payload) {
29
135
  const frame = new Uint8Array(1 + payload.length);
@@ -166,4 +272,4 @@ function toBuffer(data) {
166
272
  }
167
273
 
168
274
  //#endregion
169
- export { SandboxStream as t };
275
+ export { encodeFsRequest as a, decodeFsResponse as i, SANDBOX_STREAM_PATH as n, streamSpecToQuery as r, SandboxStream as t };
@@ -21,7 +21,7 @@ import { access, appendFile, mkdir, readFile, unlink, writeFile } from "node:fs/
21
21
  * the commit time of the built tree is one monotonic clock they share.
22
22
  */
23
23
  function portalDaemonBuild() {
24
- return "1786769616";
24
+ return "1786860400";
25
25
  }
26
26
  /**
27
27
  * Whether a client carrying `mine` should replace a running daemon carrying
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import "./client-d6K9qm6B.mjs";
3
- import { a as runPortalDaemon, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-BPGZufS1.mjs";
3
+ import { a as runPortalDaemon, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-CH95gDij.mjs";
4
4
  import "./tls-cert-CV-pwxVN.mjs";
5
5
  import "./api-DQCaztBg.mjs";
6
6
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { c as LOCAL_PROTOCOL_VERSION, d as encodeLine, f as makeLineParser, n as ensureDaemonRunning, p as parseDaemonMessage, u as daemonPaths } from "./daemon-BPGZufS1.mjs";
2
+ import { c as LOCAL_PROTOCOL_VERSION, d as encodeLine, f as makeLineParser, n as ensureDaemonRunning, p as parseDaemonMessage, u as daemonPaths } from "./daemon-CH95gDij.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { connect } from "node:net";
5
5
 
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import "./client-d6K9qm6B.mjs";
3
+ import "./daemon-CH95gDij.mjs";
4
+ import "./tls-cert-CV-pwxVN.mjs";
5
+ import "./api-DQCaztBg.mjs";
6
+ import { t as PortalDaemonClient } from "./daemon-client-BNDnEGw6.mjs";
7
+
8
+ export { PortalDaemonClient };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as getConfigPath } from "./print-Clgq46GU.mjs";
2
+ import { C as getConfigPath } from "./print-h22UbIfZ.mjs";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { err, ok } from "neverthrow";
@@ -8,7 +8,7 @@ import fs from "node:fs";
8
8
 
9
9
  //#region package.json
10
10
  var name = "skydive-cli";
11
- var version$1 = "0.5.0-beta.33";
11
+ var version$1 = "0.5.0-beta.36";
12
12
 
13
13
  //#endregion
14
14
  //#region src/auth/organization.ts
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ //#region src/launcher.ts
8
+ const PLATFORM_PACKAGES = {
9
+ "darwin-arm64": "skydive-cli-darwin-arm64",
10
+ "darwin-x64": "skydive-cli-darwin-x64",
11
+ "linux-x64": "skydive-cli-linux-x64",
12
+ "linux-arm64": "skydive-cli-linux-arm64"
13
+ };
14
+ const require = createRequire(import.meta.url);
15
+ /** The compiled per-platform binary, or null if none is installed/available. */
16
+ function resolveBinaryPath() {
17
+ const pkg = PLATFORM_PACKAGES[`${process.platform}-${process.arch}`];
18
+ if (!pkg) return null;
19
+ try {
20
+ return require.resolve(`${pkg}/bin`);
21
+ } catch (_error) {
22
+ return null;
23
+ }
24
+ }
25
+ /** The JS bundle sibling of this launcher (`dist/js/bin.mjs`). */
26
+ function jsBundlePath() {
27
+ return path.join(path.dirname(fileURLToPath(import.meta.url)), "bin.mjs");
28
+ }
29
+ const args = process.argv.slice(2);
30
+ const binaryPath = resolveBinaryPath();
31
+ let child;
32
+ if (binaryPath) {
33
+ const env = { ...process.env };
34
+ if (env["SKYDIVE_CLI_INSTALL_SOURCE"] === void 0) env["SKYDIVE_CLI_INSTALL_SOURCE"] = "package-manager";
35
+ child = spawnSync(binaryPath, args, {
36
+ stdio: "inherit",
37
+ env
38
+ });
39
+ } else child = spawnSync(process.execPath, [jsBundlePath(), ...args], { stdio: "inherit" });
40
+ if (child.error) {
41
+ const what = binaryPath ? `the platform binary (${binaryPath})` : `the CLI under Node (${process.execPath})`;
42
+ process.stderr.write(`skydive: failed to launch ${what}: ${child.error.message}\n`);
43
+ process.exit(1);
44
+ }
45
+ if (child.signal) process.kill(process.pid, child.signal);
46
+ else process.exit(child.status ?? 0);
47
+
48
+ //#endregion
49
+ export { };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-Clgq46GU.mjs";
3
- import "./rest-C6E4mS2A.mjs";
2
+ import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-h22UbIfZ.mjs";
3
+ import "./rest-ClVPZquN.mjs";
4
4
  import "./billing-blocked-D3l5kJlX.mjs";
5
5
 
6
6
  export { messageGet, readStdin, resolveAgent, runPrint };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
3
- import { a as isRecord, i as errorMessage, r as sendErrorMessage, t as createRestClient } from "./rest-C6E4mS2A.mjs";
3
+ import { a as isRecord, i as errorMessage, r as sendErrorMessage, t as createRestClient } from "./rest-ClVPZquN.mjs";
4
4
  import { i as billingBlockedOutcomeFromSendResponse, n as BillingBlockedError } from "./billing-blocked-D3l5kJlX.mjs";
5
5
  import path from "node:path";
6
6
  import Conf from "conf";
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import "./client-Btq6bMzX.mjs";
3
+ import { t as runRawPtyPassthrough } from "./raw-pty-D5PhKZSl.mjs";
4
+
5
+ export { runRawPtyPassthrough };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as SandboxStream } from "./client-BTQ1fwzM.mjs";
2
+ import { t as SandboxStream } from "./client-Btq6bMzX.mjs";
3
3
 
4
4
  //#region src/chat/sandbox/raw-pty.ts
5
5
  /**
@@ -124,6 +124,13 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
124
124
  if (!res.ok) throw new HttpError(res.status, await res.text().catch(() => ""));
125
125
  return schema.parse(await res.json());
126
126
  }
127
+ /**
128
+ * The agent PATCH is a merge: only the keys present are written, so each
129
+ * caller sends exactly the settings it means to change.
130
+ */
131
+ function patchAgent(agentId, body) {
132
+ return post(`/api/v1/agents/${encodeURIComponent(agentId)}`, body, updateAgentResponseSchema, "PATCH");
133
+ }
127
134
  async function del(path) {
128
135
  const res = await fetch(`${appUrl}${path}`, {
129
136
  method: "DELETE",
@@ -243,9 +250,31 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
243
250
  const { models } = await get("/api/v1/models", listModelsResponseSchema);
244
251
  return models;
245
252
  },
246
- updateAgentModel: async ({ agentId, model }) => {
247
- const { agent } = await post(`/api/v1/agents/${encodeURIComponent(agentId)}`, { model }, updateAgentResponseSchema, "PATCH");
248
- return { model: agent.model ?? null };
253
+ listModelEfforts: async () => {
254
+ const { modelConfigOverrides } = await get("/api/v1/models/preferred", modelEffortPreferencesResponseSchema);
255
+ const efforts = {};
256
+ for (const [modelId, config] of Object.entries(modelConfigOverrides ?? {})) if (config.thinkingLevel) efforts[modelId] = config.thinkingLevel;
257
+ return efforts;
258
+ },
259
+ setModelEffort: async ({ modelId, thinkingLevel }) => {
260
+ await post("/api/v1/models/config", {
261
+ modelId,
262
+ config: { thinkingLevel }
263
+ }, z.unknown(), "PATCH");
264
+ },
265
+ updateAgentModel: async ({ agentId, model, thinkingLevel }) => {
266
+ const { agent } = await patchAgent(agentId, {
267
+ model,
268
+ thinkingLevel
269
+ });
270
+ return {
271
+ model: agent.model ?? null,
272
+ thinkingLevel: agent.thinkingLevel ?? null
273
+ };
274
+ },
275
+ updateAgentEffort: async ({ agentId, thinkingLevel }) => {
276
+ const { agent } = await patchAgent(agentId, { thinkingLevel });
277
+ return { thinkingLevel: agent.thinkingLevel ?? null };
249
278
  },
250
279
  listConversations: async ({ agentId, limit, channels, archived, query, onPage }) => {
251
280
  const trimmedQuery = query?.trim();
@@ -299,8 +328,8 @@ function createRestClient({ appUrl, sessionToken, workspaceId }) {
299
328
  const { result } = await get(`/api/v1/trpc/v2.subagentTasks.list?input=${encodeURIComponent(JSON.stringify({ conversationId }))}`, subagentTasksResponseSchema);
300
329
  return new Map(result.data.subagentTasks.map((task) => [task.id, task]));
301
330
  },
302
- computeLiveStats: async () => {
303
- const { stats } = await get("/api/v1/compute/live-stats", liveStatsResponseSchema);
331
+ computeLiveStats: async (agentId) => {
332
+ const { stats } = await get(`/api/v1/compute/live-stats?agentId=${encodeURIComponent(agentId)}`, liveStatsResponseSchema);
304
333
  return stats;
305
334
  },
306
335
  uploadAttachment: async ({ agentId, fileName, mediaType, data }) => {
@@ -452,17 +481,24 @@ const agentSummarySchema = z.object({
452
481
  createdAt: z.string(),
453
482
  creatorName: z.string().nullable().optional(),
454
483
  model: z.string().nullable().optional(),
455
- modelLocked: z.boolean().optional()
484
+ modelLocked: z.boolean().optional(),
485
+ thinkingLevel: z.string().nullable().optional()
456
486
  });
457
487
  const platformModelSchema = z.object({
458
488
  id: z.string(),
459
489
  displayName: z.string(),
460
490
  providerDisplay: z.string().optional(),
461
491
  reasoning: z.boolean().optional(),
462
- compliant: z.boolean().optional()
492
+ compliant: z.boolean().optional(),
493
+ thinkingLevels: z.array(z.string()).optional(),
494
+ thinkingLevelLabels: z.record(z.string(), z.string()).optional()
463
495
  }).passthrough();
464
496
  const listModelsResponseSchema = z.object({ models: z.array(platformModelSchema) });
465
- const updateAgentResponseSchema = z.object({ agent: z.object({ model: z.string().nullable().optional() }).passthrough() });
497
+ const modelEffortPreferencesResponseSchema = z.object({ modelConfigOverrides: z.record(z.string(), z.object({ thinkingLevel: z.string().optional() })).optional() });
498
+ const updateAgentResponseSchema = z.object({ agent: z.object({
499
+ model: z.string().nullable().optional(),
500
+ thinkingLevel: z.string().nullable().optional()
501
+ }).passthrough() });
466
502
  const listAgentsResponseSchema = z.object({
467
503
  agents: z.array(agentSummarySchema),
468
504
  nextCursor: z.string().nullable().optional(),
@@ -617,7 +653,8 @@ const conversationStreamEventSchema = z.discriminatedUnion("kind", [
617
653
  kind: z.literal("agent"),
618
654
  id: z.string(),
619
655
  model: z.string().nullable(),
620
- modelLocked: z.boolean()
656
+ modelLocked: z.boolean(),
657
+ thinkingLevel: z.string().nullish()
621
658
  }),
622
659
  z.object({
623
660
  kind: z.literal("run"),
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as HttpError } from "./http-error-UHH3mVBF.mjs";
3
- import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-C6E4mS2A.mjs";
3
+ import { n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-ClVPZquN.mjs";
4
4
  import "./billing-blocked-D3l5kJlX.mjs";
5
5
 
6
6
  export { createRestClient };
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.5.0-beta.33",
3
+ "version": "0.5.0-beta.36",
4
4
  "description": "Skydive CLI — cloud agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",
7
7
  "bin": {
8
- "skydive": "./dist/js/bin.mjs"
8
+ "skydive": "./dist/js/launcher.mjs"
9
9
  },
10
10
  "files": [
11
11
  "dist"
12
12
  ],
13
13
  "type": "module",
14
14
  "exports": {
15
- "./bin": "./dist/js/bin.mjs"
15
+ "./bin": "./dist/js/bin.mjs",
16
+ "./launcher": "./dist/js/launcher.mjs"
16
17
  },
17
18
  "publishConfig": {
18
19
  "access": "public",
@@ -41,7 +42,6 @@
41
42
  "react-devtools-core": "^7.0.1",
42
43
  "safe-stable-stringify": "^2.3.1",
43
44
  "semver": "^7.7.4",
44
- "shell-quote": "1.9.0",
45
45
  "web-tree-sitter": "0.25.10",
46
46
  "ws": "^8.21.0",
47
47
  "yargs": "^17.7.2",
@@ -66,5 +66,12 @@
66
66
  "engines": {
67
67
  "bun": ">=1.3.14",
68
68
  "node": ">=20.0.0"
69
+ },
70
+ "//optionalDependencies": "The per-platform binary packages (skydive-cli-<os>-<arch>) are INTENTIONALLY not committed here. They are published by release-skydive-cli-binaries.yml and injected — pinned to the exact version being published — into the published launcher's optionalDependencies at release time (scripts/prepare-platform-packages.mjs --pin-version, run in release-skydive-cli.yml). Committing them would make `yarn install` try to resolve versions that only exist post-publish, breaking local dev and CI. npm installs of a published skydive-cli still get them (os/cpu-gated); the launcher (src/launcher.ts) resolves and execs the matching one. Local dev never needs them: it runs the JS bundle or `build:binary` directly.",
71
+ "optionalDependencies": {
72
+ "skydive-cli-darwin-arm64": "0.5.0-beta.36",
73
+ "skydive-cli-darwin-x64": "0.5.0-beta.36",
74
+ "skydive-cli-linux-x64": "0.5.0-beta.36",
75
+ "skydive-cli-linux-arm64": "0.5.0-beta.36"
69
76
  }
70
77
  }
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-d6K9qm6B.mjs";
3
- import "./daemon-BPGZufS1.mjs";
4
- import "./tls-cert-CV-pwxVN.mjs";
5
- import "./api-DQCaztBg.mjs";
6
- import { t as PortalDaemonClient } from "./daemon-client-MpAGVkqP.mjs";
7
-
8
- export { PortalDaemonClient };
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./client-BTQ1fwzM.mjs";
3
- import { t as runRawPtyPassthrough } from "./raw-pty-B9Bue8gg.mjs";
4
-
5
- export { runRawPtyPassthrough };