@agentsky/sky 2.24.1 → 2.26.0

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.
@@ -3,7 +3,7 @@ import {
3
3
  apiBase,
4
4
  apiToken,
5
5
  currentUniverse
6
- } from "./chunk-S4YG3TXA.js";
6
+ } from "./chunk-UZ7KWRQH.js";
7
7
 
8
8
  // src/api.ts
9
9
  import { createWriteStream, writeFileSync } from "fs";
@@ -97,6 +97,9 @@ async function downloadFileTo(fileId, outPath) {
97
97
  headers: { "user-agent": USER_AGENT, ...authHeaders() }
98
98
  });
99
99
  if (!res.ok) await parseError(res);
100
+ return writeResponseFile(res, outPath);
101
+ }
102
+ async function writeResponseFile(res, outPath) {
100
103
  if (!res.body) {
101
104
  writeFileSync(outPath, new Uint8Array(0));
102
105
  return 0;
@@ -145,7 +148,7 @@ async function resolveSessionRef(ref) {
145
148
  return agent.defaultSessionId;
146
149
  }
147
150
  async function* streamEvents(sessionId, signal) {
148
- const { parseSseStream } = await import("./src-BMXKAMOB.js");
151
+ const { parseSseStream } = await import("./src-OBSBFTDB.js");
149
152
  const res = await fetch(
150
153
  `${apiBase()}/sessions/${encodeURIComponent(sessionId)}/stream`,
151
154
  {
@@ -189,6 +192,7 @@ export {
189
192
  uploadFile,
190
193
  apiForm,
191
194
  downloadFileTo,
195
+ writeResponseFile,
192
196
  apiBytes,
193
197
  resolveSessionRef,
194
198
  streamEvents,
@@ -38,7 +38,7 @@ function currentUniverse() {
38
38
  }
39
39
 
40
40
  // src/version.ts
41
- var CLI_VERSION = "2.24.1";
41
+ var CLI_VERSION = "2.26.0";
42
42
  var USER_AGENT = `sky-cli/${CLI_VERSION} (${process.platform}; node/${process.versions.node})`;
43
43
 
44
44
  export {
package/dist/index.js CHANGED
@@ -9,8 +9,9 @@ import {
9
9
  postEvents,
10
10
  resolveSessionRef,
11
11
  streamEvents,
12
- uploadFile
13
- } from "./chunk-KWLEADJQ.js";
12
+ uploadFile,
13
+ writeResponseFile
14
+ } from "./chunk-K3LB4K2C.js";
14
15
  import {
15
16
  CLI_VERSION,
16
17
  USER_AGENT,
@@ -21,7 +22,7 @@ import {
21
22
  currentUniverse,
22
23
  loadConfig,
23
24
  saveConfig
24
- } from "./chunk-S4YG3TXA.js";
25
+ } from "./chunk-UZ7KWRQH.js";
25
26
  import {
26
27
  AGENT_TYPES,
27
28
  MODEL_SUBSCRIPTION_PLAN_PHRASE,
@@ -43,11 +44,11 @@ import {
43
44
  skillRefSchema,
44
45
  splitMcpServers,
45
46
  supersededBy
46
- } from "./chunk-D3WG4BMK.js";
47
+ } from "./chunk-CJBZVPDF.js";
47
48
  import "./chunk-MLKGABMK.js";
48
49
 
49
50
  // src/index.ts
50
- import { existsSync as existsSync13, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "fs";
51
+ import { existsSync as existsSync13, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
51
52
  import { basename as basename9, resolve as resolve9 } from "path";
52
53
  import { createInterface as createInterface6 } from "readline";
53
54
  import { Command } from "commander";
@@ -2643,6 +2644,42 @@ it, and name its path in the brief.
2643
2644
  6. Tell the person what was done, which agent did which part, and what it cost
2644
2645
  (\`get_task\` reports the task's cost).
2645
2646
 
2647
+ ## Share an existing Library document
2648
+
2649
+ Use \`read_library_file_links\` with the document's exact \`ref\` to read its
2650
+ current revision, supported access and real available members. The reference
2651
+ can name a Drive file (including an uploaded meeting note), task file, memory
2652
+ note, skill file, agent user instructions (\`{kind:"agent_prompt",agentId}\`), saved artifact or platform artifact. Only the user-authored AGENTS.md is shared; system instructions and credentials are never included. \`workspace\` names the
2653
+ audience workspace, never a storage move or the connection's default.
2654
+ For a DesignSystem file, use \`platform_artifact\` with the exact full native
2655
+ manifest \`path\`: its actual \`root\` plus an \`editable_files\` path, or the
2656
+ native document reader's \`libraryRef\`. Do not guess a folder prefix or use
2657
+ an editor's relative transport path. Omitting \`path\` shares the entire
2658
+ artifact entry. A token reads only its original file; it cannot select a
2659
+ sibling with a query parameter. Editable DesignSystem files save through
2660
+ that system's versioned writer, including derived files and republishing.
2661
+ \`share_library_file\` changes only the requested workspace/member grants;
2662
+ \`publish_library_file\` enables or disables a public view-only link while
2663
+ preserving other grants. Both read first and merge against the current
2664
+ revision. \`revoke_library_file_links\` needs the explicit revision you reviewed.
2665
+ A conflict is an error: read the current state before intentionally retrying.
2666
+ These tools send no messages and start no sessions. CLI equivalents are
2667
+ \`sky library links show\`, \`share\`, \`publish\` and \`revoke\`; their help
2668
+ shows every reference shape. Existing artifact links and version pins keep
2669
+ using their existing controls and \`share_artifact\`.
2670
+
2671
+ When you receive a Library shared/public URL, \`read_shared_library_file\`
2672
+ accepts the 43-character token at its end; \`public: true\` chooses the public
2673
+ view-only reader. A recipient with a live edit grant can use
2674
+ \`save_shared_library_file\` with the opaque source revision from that read
2675
+ and exactly one native text/HTML/Office/restore field. Public links have no
2676
+ writer. The CLI equivalents are \`sky library links read --token \u2026\`
2677
+ (\`--output\` streams original bytes) and \`sky library links save --token \u2026
2678
+ --revision \u2026 --file \u2026\`; \`--data\` accepts the other native save fields.
2679
+ A 403 is not a saved result; a 409 requires reading current state before an
2680
+ intentional retry. This source revision is distinct from the integer revision
2681
+ of the sharing settings.
2682
+
2646
2683
  ## Build an agent that the person's own application runs
2647
2684
 
2648
2685
  When the person wants an agent their product starts for its customers, built
@@ -5261,6 +5298,83 @@ function renderThreadSummary(t) {
5261
5298
  return `${t.id.slice(0, 12)} ${flag}${t.title.slice(0, 40).padEnd(44)} [${agents}] ${status}`;
5262
5299
  }
5263
5300
 
5301
+ // src/library.ts
5302
+ import { readFileSync as readFileSync17 } from "fs";
5303
+
5304
+ // src/api-command.ts
5305
+ import { readFileSync as readFileSync16 } from "fs";
5306
+ var API_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
5307
+ function readData(data, stdin = () => readFileSync16(0, "utf8")) {
5308
+ if (data === void 0) return void 0;
5309
+ const raw = data === "-" ? stdin() : data.startsWith("@") ? readFileSync16(data.slice(1), "utf8") : data;
5310
+ try {
5311
+ JSON.parse(raw);
5312
+ } catch {
5313
+ throw new Error("--data must be JSON (inline, @file or - for stdin)");
5314
+ }
5315
+ return raw;
5316
+ }
5317
+ function requestPath(path, query = []) {
5318
+ if (!path.startsWith("/") || path.startsWith("//")) throw new Error("path must start with /, e.g. /threads");
5319
+ const clean = path.replace(/^\/v1(?=\/)/, "");
5320
+ const params = new URLSearchParams();
5321
+ for (const pair of query) {
5322
+ const at = pair.indexOf("=");
5323
+ if (at <= 0) throw new Error(`--query needs key=value, got "${pair}"`);
5324
+ params.append(pair.slice(0, at), pair.slice(at + 1));
5325
+ }
5326
+ const sep4 = clean.includes("?") ? "&" : "?";
5327
+ const encoded = params.toString();
5328
+ return encoded ? `${clean}${sep4}${encoded}` : clean;
5329
+ }
5330
+ function matchOperations(doc, words) {
5331
+ const needles = words.map((w) => w.toLowerCase());
5332
+ const out = [];
5333
+ for (const [path, item] of Object.entries(doc.paths ?? {})) {
5334
+ for (const [method, op] of Object.entries(item)) {
5335
+ if (!API_METHODS.includes(method.toUpperCase())) continue;
5336
+ const hay = `${method} ${path} ${op.summary ?? ""} ${op.operationId ?? ""}`.toLowerCase();
5337
+ if (needles.every((n) => hay.includes(n))) out.push({ method: method.toUpperCase(), path, summary: op.summary, operationId: op.operationId });
5338
+ }
5339
+ }
5340
+ return out.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
5341
+ }
5342
+ async function searchApi(words) {
5343
+ const res = await apiRaw("GET", "/openapi.json", { auth: false });
5344
+ if (!res.ok) throw new Error(`could not read the API reference (${res.status})`);
5345
+ const ops = matchOperations(await res.json(), words);
5346
+ if (!ops.length) {
5347
+ console.log("no operations match");
5348
+ return;
5349
+ }
5350
+ for (const op of ops) console.log(`${op.method.padEnd(6)} ${op.path}${op.summary ? ` \u2014 ${op.summary}` : ""}`);
5351
+ }
5352
+ async function callApi(method, path, opts) {
5353
+ const verb = method.toUpperCase();
5354
+ if (!API_METHODS.includes(verb)) throw new Error(`method must be one of ${API_METHODS.join(", ")} or "search"`);
5355
+ const body = readData(opts.data);
5356
+ if (body !== void 0 && verb === "GET") throw new Error("a GET takes no --data; use --query");
5357
+ const res = await apiRaw(verb, requestPath(path, opts.query), { body, idempotencyKey: opts.idempotencyKey, universe: opts.workspace });
5358
+ const type = res.headers.get("content-type") ?? "";
5359
+ if (opts.output) {
5360
+ await writeResponseFile(res, opts.output);
5361
+ console.error(`${res.status} \u2192 ${opts.output}`);
5362
+ } else if (/json/.test(type)) {
5363
+ const text = await res.text();
5364
+ let printed = text;
5365
+ try {
5366
+ printed = JSON.stringify(JSON.parse(text), null, 2);
5367
+ } catch {
5368
+ }
5369
+ (res.ok ? console.log : console.error)(printed);
5370
+ } else if (/^text\/|xml|csv|markdown/.test(type) || !type) {
5371
+ (res.ok ? console.log : console.error)(await res.text());
5372
+ } else {
5373
+ console.error(`${res.status}: ${type} body (${res.headers.get("content-length") ?? "?"} bytes); pass --output <file> to save it`);
5374
+ }
5375
+ if (!res.ok && res.status !== 304) process.exitCode = 1;
5376
+ }
5377
+
5264
5378
  // src/library.ts
5265
5379
  var artifactPath = (id) => `/library/artifacts/${encodeURIComponent(id)}`;
5266
5380
  async function listLibrary(query = {}) {
@@ -5295,9 +5409,139 @@ function renderLibraryArtifact(artifact2) {
5295
5409
  const version = artifact2.currentVersion ? `v${artifact2.currentVersion}` : "";
5296
5410
  return `${artifact2.id} ${artifact2.name} ${version}${artifact2.shared ? " shared" : ""}`;
5297
5411
  }
5412
+ var libraryFileRefSchema = external_exports.discriminatedUnion("kind", [
5413
+ external_exports.object({ kind: external_exports.literal("agent_prompt"), agentId: external_exports.string().min(1).max(200).regex(/^[a-zA-Z0-9_-]+$/) }).strict(),
5414
+ external_exports.object({ kind: external_exports.literal("file"), fileId: external_exports.string().min(1), sessionId: external_exports.string().min(1).optional() }).strict(),
5415
+ external_exports.object({ kind: external_exports.literal("task_file"), taskId: external_exports.string().min(1), path: external_exports.string().min(1) }).strict(),
5416
+ external_exports.object({ kind: external_exports.literal("memory_note"), storeId: external_exports.string().min(1), memoryId: external_exports.string().min(1) }).strict(),
5417
+ external_exports.object({ kind: external_exports.literal("skill_file"), skillId: external_exports.string().min(1), path: external_exports.string().min(1) }).strict(),
5418
+ external_exports.object({ kind: external_exports.literal("artifact"), artifactId: external_exports.string().min(1) }).strict(),
5419
+ external_exports.object({ kind: external_exports.literal("platform_artifact"), artifactId: external_exports.string().min(1), path: external_exports.string().min(1).optional() }).strict()
5420
+ ]);
5421
+ var linkAccessSchema = external_exports.enum(["none", "view", "edit"]);
5422
+ var linkMemberSchema = external_exports.object({ userId: external_exports.string().min(1), access: external_exports.enum(["view", "edit"]) });
5423
+ var linkRevisionSchema = external_exports.number().int().nonnegative();
5424
+ var libraryLinksSchema = external_exports.object({
5425
+ link: external_exports.object({
5426
+ id: external_exports.string().nullable(),
5427
+ ref: libraryFileRefSchema,
5428
+ workspace: external_exports.string().nullable(),
5429
+ revision: linkRevisionSchema,
5430
+ editable: external_exports.boolean(),
5431
+ workspaceAccess: linkAccessSchema,
5432
+ members: external_exports.array(linkMemberSchema),
5433
+ publicEnabled: external_exports.boolean(),
5434
+ sharedUrl: external_exports.string().nullable(),
5435
+ publicUrl: external_exports.string().nullable()
5436
+ }),
5437
+ availableMembers: external_exports.array(external_exports.object({ userId: external_exports.string(), name: external_exports.string().nullable(), email: external_exports.string().nullable() }))
5438
+ });
5439
+ function parseLibraryFileRef(value) {
5440
+ return libraryFileRefSchema.parse(JSON.parse(value));
5441
+ }
5442
+ async function getLibraryLinks(ref, workspace2) {
5443
+ const params = new URLSearchParams({ ref: JSON.stringify(libraryFileRefSchema.parse(ref)), ...workspace2 ? { workspace: workspace2 } : {} });
5444
+ const result = libraryLinksSchema.parse(await api("GET", `/library/links?${params}`));
5445
+ if (JSON.stringify(result.link.ref) !== JSON.stringify(libraryFileRefSchema.parse(ref)) || workspace2 !== void 0 && result.link.workspace !== workspace2) throw new Error("The API returned sharing for a different source. No access was changed.");
5446
+ return result;
5447
+ }
5448
+ async function updateLibraryLinks(ref, change) {
5449
+ const current = await getLibraryLinks(ref, change.workspace);
5450
+ if (change.revision !== void 0 && linkRevisionSchema.parse(change.revision) !== current.link.revision) throw new Error("Sharing changed since that revision. Read the current links and retry.");
5451
+ const members = new Map(current.link.members.map((member) => [member.userId, member]));
5452
+ for (const member of change.memberChanges ?? []) {
5453
+ const userId = external_exports.string().min(1).parse(member.userId);
5454
+ const access = linkAccessSchema.parse(member.access);
5455
+ if (access === "none") members.delete(userId);
5456
+ else members.set(userId, { userId, access });
5457
+ }
5458
+ return libraryLinksSchema.parse(await api("PUT", "/library/links", {
5459
+ ref,
5460
+ workspace: current.link.workspace,
5461
+ revision: current.link.revision,
5462
+ workspaceAccess: change.workspaceAccess === void 0 ? current.link.workspaceAccess : linkAccessSchema.parse(change.workspaceAccess),
5463
+ members: [...members.values()],
5464
+ publicEnabled: change.publicEnabled === void 0 ? current.link.publicEnabled : external_exports.boolean().parse(change.publicEnabled)
5465
+ }));
5466
+ }
5467
+ async function revokeLibraryLinks(ref, revision, workspace2) {
5468
+ return libraryLinksSchema.parse(await api("DELETE", "/library/links", {
5469
+ ref: libraryFileRefSchema.parse(ref),
5470
+ revision: linkRevisionSchema.parse(revision),
5471
+ ...workspace2 ? { workspace: workspace2 } : {}
5472
+ }));
5473
+ }
5474
+ var sharedLibraryToken = external_exports.string().length(43).regex(/^[A-Za-z0-9_-]{43}$/, "use the 43-character token from the Library shared or public URL");
5475
+ var sharedLibrarySource = external_exports.object({
5476
+ name: external_exports.string(),
5477
+ format: external_exports.enum(["file", "site"]),
5478
+ mediaType: external_exports.string(),
5479
+ revision: external_exports.string(),
5480
+ editable: external_exports.boolean(),
5481
+ url: external_exports.string(),
5482
+ maxBytes: external_exports.number(),
5483
+ history: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown()))
5484
+ }).passthrough();
5485
+ var sharedLibrarySaved = external_exports.object({ url: external_exports.string(), revision: external_exports.string().min(1), publishedAt: external_exports.string().datetime({ offset: true }), text: external_exports.string().nullable().optional(), historyRevision: external_exports.string().optional() });
5486
+ var sharedLibrarySaveSchema = external_exports.object({
5487
+ revision: external_exports.string().min(1),
5488
+ text: external_exports.string().optional(),
5489
+ html: external_exports.string().optional(),
5490
+ office: external_exports.string().optional(),
5491
+ docx: external_exports.string().optional(),
5492
+ restoreRevision: external_exports.string().min(1).optional(),
5493
+ requestId: external_exports.string().uuid().optional()
5494
+ }).strict().refine((body) => [body.text, body.html, body.office, body.docx, body.restoreRevision].filter((field) => field !== void 0).length === 1, "provide exactly one of text, html, office, docx or restoreRevision");
5495
+ async function readSharedLibraryFile(token, options = {}) {
5496
+ const path = `/library/${options.public ? "public" : "shared"}/${sharedLibraryToken.parse(token)}`;
5497
+ if (!options.output) return sharedLibrarySource.parse(await api("GET", path, void 0, { auth: options.public !== true }));
5498
+ const response = await apiRaw("GET", `${path}?raw=1`, { auth: options.public !== true });
5499
+ if (!response.ok) {
5500
+ const body = await response.json().catch(() => null);
5501
+ throw new ApiError(response.status, body?.error?.code ?? "http_error", body?.error?.message ?? `Download failed (${response.status}).`);
5502
+ }
5503
+ return { output: options.output, bytes: await writeResponseFile(response, options.output) };
5504
+ }
5505
+ async function saveSharedLibraryFile(token, body) {
5506
+ return sharedLibrarySaved.parse(await api("PUT", `/library/shared/${sharedLibraryToken.parse(token)}`, sharedLibrarySaveSchema.parse(body)));
5507
+ }
5508
+ function registerLibraryLinkCommands(library2) {
5509
+ const libraryLinks = library2.command("links").description("share or publish any Library file; --workspace selects the sharing audience without moving the file");
5510
+ libraryLinks.command("read").description("read a shared native document snapshot; --public reads a public view-only link").requiredOption("--token <token>", "43-character token from a Library shared or public URL").option("--public", "use the public reader without sending your API key").option("--output <file>", "stream the original bytes to this file instead of printing the JSON snapshot").action(async (opts) => {
5511
+ console.log(JSON.stringify(await readSharedLibraryFile(opts.token, opts), null, 2));
5512
+ });
5513
+ libraryLinks.command("save").description("save through a live recipient edit grant; --revision is the opaque source revision from links read").requiredOption("--token <token>", "43-character token from the authenticated shared URL (public URLs have no writer)").requiredOption("--revision <revision>", "native source revision from links read; stale revisions fail without retry").option("--file <path>", "UTF-8 text file to save").option("--data <json>", "instead of --file, JSON/ @file / - containing exactly one text/html/office/docx/restoreRevision and optional requestId").action(async (opts) => {
5514
+ if (opts.file !== void 0 === (opts.data !== void 0)) throw new Error("Choose exactly one of --file or --data.");
5515
+ const body = opts.file !== void 0 ? { text: new TextDecoder("utf-8", { fatal: true }).decode(readFileSync17(opts.file)) } : JSON.parse(readData(opts.data));
5516
+ if (!body || typeof body !== "object" || Array.isArray(body)) throw new Error("--data must be a JSON object with one native save field.");
5517
+ if ("revision" in body && body.revision !== opts.revision) throw new Error("--data revision must match --revision.");
5518
+ console.log(JSON.stringify(await saveSharedLibraryFile(opts.token, sharedLibrarySaveSchema.parse({ ...body, revision: opts.revision })), null, 2));
5519
+ });
5520
+ const linkRefOption = (command) => command.requiredOption("--ref <json>", 'file reference JSON, e.g. {"kind":"file","fileId":"file_\u2026"}').option("--workspace <slug>", "the team audience for this link (omit for private/public-only sharing)");
5521
+ const linkRevision = (value) => value === void 0 ? void 0 : linkRevisionSchema.parse(Number(external_exports.string().regex(/^\d+$/, "revision must be a nonnegative integer").parse(value)));
5522
+ const printLibraryLinks = (value) => console.log(JSON.stringify(value, null, 2));
5523
+ linkRefOption(libraryLinks.command("show").description("read sharing, real workspace members and the current revision without creating a link")).action(async (opts) => printLibraryLinks(await getLibraryLinks(parseLibraryFileRef(opts.ref), opts.workspace)));
5524
+ linkRefOption(libraryLinks.command("share").description("change workspace or specific members' access while preserving every unmentioned grant")).option("--workspace-access <access>", "none, view or edit (edit requires an editable source)").option("--member <user:access>", "grant a member view or edit; repeat to update several members", (value, previous) => [...previous, value], []).option("--remove-member <user>", "clear a member override; workspace access still applies", (value, previous) => [...previous, value], []).option("--revision <n>", "refuse if sharing changed since this reviewed revision").action(async (opts) => {
5525
+ if (opts.workspaceAccess === void 0 && !opts.member?.length && !opts.removeMember?.length) throw new Error("Choose --workspace-access, --member or --remove-member; links show reads without changing access.");
5526
+ const memberChanges = (opts.member ?? []).map((value) => {
5527
+ const colon = value.lastIndexOf(":");
5528
+ if (colon < 1) throw new Error("--member must be a user id followed by :view or :edit");
5529
+ return { userId: value.slice(0, colon), access: external_exports.enum(["view", "edit"]).parse(value.slice(colon + 1)) };
5530
+ });
5531
+ memberChanges.push(...(opts.removeMember ?? []).map((userId) => ({ userId, access: "none" })));
5532
+ printLibraryLinks(await updateLibraryLinks(parseLibraryFileRef(opts.ref), {
5533
+ workspace: opts.workspace,
5534
+ revision: linkRevision(opts.revision),
5535
+ memberChanges,
5536
+ workspaceAccess: opts.workspaceAccess === void 0 ? void 0 : external_exports.enum(["none", "view", "edit"]).parse(opts.workspaceAccess)
5537
+ }));
5538
+ });
5539
+ linkRefOption(libraryLinks.command("publish").description("create a public view-only link; --disable revokes only public access and keeps other grants")).option("--disable", "turn off public viewing").option("--revision <n>", "refuse if sharing changed since this reviewed revision").action(async (opts) => printLibraryLinks(await updateLibraryLinks(parseLibraryFileRef(opts.ref), { workspace: opts.workspace, revision: linkRevision(opts.revision), publicEnabled: !opts.disable })));
5540
+ linkRefOption(libraryLinks.command("revoke").description("stop all sharing at an explicitly reviewed revision")).requiredOption("--revision <n>", "current revision from links show; stale revisions fail without retry").action(async (opts) => printLibraryLinks(await revokeLibraryLinks(parseLibraryFileRef(opts.ref), linkRevision(opts.revision), opts.workspace)));
5541
+ }
5298
5542
 
5299
5543
  // src/design-systems.ts
5300
- import { readdirSync as readdirSync8, readFileSync as readFileSync16, statSync as statSync9 } from "fs";
5544
+ import { readdirSync as readdirSync8, readFileSync as readFileSync18, statSync as statSync9 } from "fs";
5301
5545
  import { join as join18, relative as relative5, sep as sep3 } from "path";
5302
5546
  var TEXT2 = /\.(mdx?|markdown|txt|json|m?js|cjs|jsx|tsx?|css|html?|svg|xml|csv|ya?ml|toml)$/i;
5303
5547
  var MEDIA = {
@@ -5330,6 +5574,13 @@ async function saveDesignTokens(id, baseVersion, tokens, note) {
5330
5574
  ...note ? { note } : {}
5331
5575
  })).artifact;
5332
5576
  }
5577
+ async function saveDesignSystemFile(id, path, baseVersion, change, note) {
5578
+ return (await api("PUT", `/artifacts/${encodeURIComponent(id)}/design-system/files/${path.split("/").map(encodeURIComponent).join("/")}`, {
5579
+ base_version: baseVersion,
5580
+ ...change,
5581
+ ...note ? { note } : {}
5582
+ })).artifact;
5583
+ }
5333
5584
  function fileTableFrom(dir) {
5334
5585
  const files2 = {};
5335
5586
  const walk = (current) => {
@@ -5341,7 +5592,7 @@ function fileTableFrom(dir) {
5341
5592
  continue;
5342
5593
  }
5343
5594
  const key = relative5(dir, path).split(sep3).join("/");
5344
- const bytes = readFileSync16(path);
5595
+ const bytes = readFileSync18(path);
5345
5596
  files2[key] = TEXT2.test(name) ? bytes.toString("utf8") : `data:${MEDIA[name.split(".").pop()?.toLowerCase() ?? ""] ?? "application/octet-stream"};base64,${bytes.toString("base64")}`;
5346
5597
  }
5347
5598
  };
@@ -5364,80 +5615,6 @@ async function designComments(id, input) {
5364
5615
  return api(input ? "POST" : "GET", `/artifacts/${encodeURIComponent(id)}/design-system/comments`, input);
5365
5616
  }
5366
5617
 
5367
- // src/api-command.ts
5368
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
5369
- var API_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
5370
- function readData(data, stdin = () => readFileSync17(0, "utf8")) {
5371
- if (data === void 0) return void 0;
5372
- const raw = data === "-" ? stdin() : data.startsWith("@") ? readFileSync17(data.slice(1), "utf8") : data;
5373
- try {
5374
- JSON.parse(raw);
5375
- } catch {
5376
- throw new Error("--data must be JSON (inline, @file or - for stdin)");
5377
- }
5378
- return raw;
5379
- }
5380
- function requestPath(path, query = []) {
5381
- if (!path.startsWith("/") || path.startsWith("//")) throw new Error("path must start with /, e.g. /threads");
5382
- const clean = path.replace(/^\/v1(?=\/)/, "");
5383
- const params = new URLSearchParams();
5384
- for (const pair of query) {
5385
- const at = pair.indexOf("=");
5386
- if (at <= 0) throw new Error(`--query needs key=value, got "${pair}"`);
5387
- params.append(pair.slice(0, at), pair.slice(at + 1));
5388
- }
5389
- const sep4 = clean.includes("?") ? "&" : "?";
5390
- const encoded = params.toString();
5391
- return encoded ? `${clean}${sep4}${encoded}` : clean;
5392
- }
5393
- function matchOperations(doc, words) {
5394
- const needles = words.map((w) => w.toLowerCase());
5395
- const out = [];
5396
- for (const [path, item] of Object.entries(doc.paths ?? {})) {
5397
- for (const [method, op] of Object.entries(item)) {
5398
- if (!API_METHODS.includes(method.toUpperCase())) continue;
5399
- const hay = `${method} ${path} ${op.summary ?? ""} ${op.operationId ?? ""}`.toLowerCase();
5400
- if (needles.every((n) => hay.includes(n))) out.push({ method: method.toUpperCase(), path, summary: op.summary, operationId: op.operationId });
5401
- }
5402
- }
5403
- return out.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
5404
- }
5405
- async function searchApi(words) {
5406
- const res = await apiRaw("GET", "/openapi.json", { auth: false });
5407
- if (!res.ok) throw new Error(`could not read the API reference (${res.status})`);
5408
- const ops = matchOperations(await res.json(), words);
5409
- if (!ops.length) {
5410
- console.log("no operations match");
5411
- return;
5412
- }
5413
- for (const op of ops) console.log(`${op.method.padEnd(6)} ${op.path}${op.summary ? ` \u2014 ${op.summary}` : ""}`);
5414
- }
5415
- async function callApi(method, path, opts) {
5416
- const verb = method.toUpperCase();
5417
- if (!API_METHODS.includes(verb)) throw new Error(`method must be one of ${API_METHODS.join(", ")} or "search"`);
5418
- const body = readData(opts.data);
5419
- if (body !== void 0 && verb === "GET") throw new Error("a GET takes no --data; use --query");
5420
- const res = await apiRaw(verb, requestPath(path, opts.query), { body, idempotencyKey: opts.idempotencyKey, universe: opts.workspace });
5421
- const type = res.headers.get("content-type") ?? "";
5422
- if (opts.output) {
5423
- writeFileSync9(opts.output, new Uint8Array(await res.arrayBuffer()));
5424
- console.error(`${res.status} \u2192 ${opts.output}`);
5425
- } else if (/json/.test(type)) {
5426
- const text = await res.text();
5427
- let printed = text;
5428
- try {
5429
- printed = JSON.stringify(JSON.parse(text), null, 2);
5430
- } catch {
5431
- }
5432
- (res.ok ? console.log : console.error)(printed);
5433
- } else if (/^text\/|xml|csv|markdown/.test(type) || !type) {
5434
- (res.ok ? console.log : console.error)(await res.text());
5435
- } else {
5436
- console.error(`${res.status}: ${type} body (${res.headers.get("content-length") ?? "?"} bytes); pass --output <file> to save it`);
5437
- }
5438
- if (!res.ok && res.status !== 304) process.exitCode = 1;
5439
- }
5440
-
5441
5618
  // src/billing-plans.ts
5442
5619
  var readCodingPlan = () => api("GET", "/billing/coding-plan");
5443
5620
  function joinCodingPlan(dollars2, requestId) {
@@ -5524,7 +5701,7 @@ function workspaceFlagIsCommands(argv, commandPath) {
5524
5701
  }
5525
5702
 
5526
5703
  // src/harness.ts
5527
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
5704
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "fs";
5528
5705
  import { dirname as dirname9, join as join19, resolve as resolve8 } from "path";
5529
5706
  var HARNESS_FILE = "harness.json";
5530
5707
  function harnessFilePath(dir) {
@@ -5536,7 +5713,7 @@ function readHarnessFile(dir) {
5536
5713
  throw new Error(`no ${HARNESS_FILE} found in ${resolve8(dir)} \u2014 run \`sky harness init\` first`);
5537
5714
  }
5538
5715
  try {
5539
- return JSON.parse(readFileSync18(path, "utf8"));
5716
+ return JSON.parse(readFileSync19(path, "utf8"));
5540
5717
  } catch (err) {
5541
5718
  throw new Error(`could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`);
5542
5719
  }
@@ -5567,7 +5744,7 @@ function harnessInit(dir) {
5567
5744
  throw new Error(`${path} already exists \u2014 delete it to re-init`);
5568
5745
  }
5569
5746
  mkdirSync6(dirname9(path), { recursive: true });
5570
- writeFileSync10(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
5747
+ writeFileSync9(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
5571
5748
  `);
5572
5749
  console.log(`Created ${path}`);
5573
5750
  console.log(INIT_COMMENT);
@@ -6306,7 +6483,7 @@ sessionWorkspace.command("cat <ref> <path>").description("print a file (up to 1
6306
6483
  run(async (ref, path, opts) => {
6307
6484
  const bytes = await readFile(await resolveSessionRef(ref), path);
6308
6485
  if (opts.out) {
6309
- writeFileSync11(opts.out, bytes);
6486
+ writeFileSync10(opts.out, bytes);
6310
6487
  console.error(`saved ${bytes.length} bytes to ${opts.out}`);
6311
6488
  } else process.stdout.write(bytes);
6312
6489
  })
@@ -6323,7 +6500,7 @@ sessionWorkspace.command("patch <ref> [repo]").description("the work in a reposi
6323
6500
  console.error(`${meta.repo}: ${meta.commits.length} commit${meta.commits.length === 1 ? "" : "s"} since ${meta.base_branch || "the imported copy"} (${meta.base_commit.slice(0, 12)})`);
6324
6501
  if (!patch.length) console.error("nothing changed");
6325
6502
  else if (opts.out) {
6326
- writeFileSync11(opts.out, patch);
6503
+ writeFileSync10(opts.out, patch);
6327
6504
  console.error(`wrote ${opts.out} \u2014 apply with: git apply ${opts.out}`);
6328
6505
  } else process.stdout.write(patch);
6329
6506
  })
@@ -6828,14 +7005,14 @@ task.command("get <task> <path>").description("read one task file; prints it, or
6828
7005
  run(async (taskId, path, opts) => {
6829
7006
  const bytes = await readTaskFile(taskId, path);
6830
7007
  if (opts.out) {
6831
- writeFileSync11(opts.out, bytes);
7008
+ writeFileSync10(opts.out, bytes);
6832
7009
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
6833
7010
  } else process.stdout.write(bytes);
6834
7011
  })
6835
7012
  );
6836
7013
  task.command("put <task> <path> <local>").description("write a local file to <path> in the task's files (every session of the task sees it)").action(
6837
7014
  run(async (taskId, path, local) => {
6838
- const { file, conflict } = await writeTaskFile(taskId, path, readFileSync19(local), mediaTypeFor(local));
7015
+ const { file, conflict } = await writeTaskFile(taskId, path, readFileSync20(local), mediaTypeFor(local));
6839
7016
  console.log(`${renderTaskFile(file)}${conflict ? " (replaced a version you had not seen)" : ""}`);
6840
7017
  })
6841
7018
  );
@@ -6908,6 +7085,80 @@ task.command("verdict <task> <did-the-job>").description("record whether the tas
6908
7085
  console.log(`Recorded verdict on task ${updated.id}: did_the_job=${value === "yes"}`);
6909
7086
  })
6910
7087
  );
7088
+ var plugins = program.command("plugins").description("Claude Code plugins in the workspace: install from GitHub, list, remove");
7089
+ plugins.command("list").description("the workspace's installed plugins and the skills each one installed").option("--json", "print the list as JSON").action(
7090
+ run(async (opts) => {
7091
+ const { plugins: list } = await api("GET", "/plugins");
7092
+ if (opts.json) return void console.log(JSON.stringify(list));
7093
+ if (list.length === 0) return void console.log("No plugins. `sky plugins install github:owner/repo[/path][@ref]`");
7094
+ for (const p of list) console.log(`${p.name} ${p.skills.length} skill${p.skills.length === 1 ? "" : "s"}: ${p.skills.map((s) => s.displayName.split("/").pop()).join(", ")}`);
7095
+ })
7096
+ );
7097
+ plugins.command("install <source>").description("install or update a plugin: github:owner/repo[/path][@ref] or a github.com URL").option("--mcp-token <server=token...>", "a bearer token for one of the plugin's remote MCP servers (repeatable)").option("--json", "print the result as JSON").action(
7098
+ run(async (source, opts) => {
7099
+ const mcp_tokens = Object.fromEntries((opts.mcpToken ?? []).map((pair) => [pair.slice(0, pair.indexOf("=")), pair.slice(pair.indexOf("=") + 1)]).filter(([k, v]) => k && v));
7100
+ const result = await api("POST", "/plugins", { source, ...Object.keys(mcp_tokens).length ? { mcp_tokens } : {} });
7101
+ if (opts.json) return void console.log(JSON.stringify(result));
7102
+ console.log(`Installed ${result.plugin.name}${result.plugin.version ? ` ${result.plugin.version}` : ""} from ${result.plugin.source}: ${result.skills.length} skill(s), on for every new session.`);
7103
+ for (const c of result.connectors) {
7104
+ const state = c.app === null ? "no AgentSky connector for it yet" : c.connected ? `uses your ${c.app} connection` : `connect ${c.app}: ${c.connect_url}`;
7105
+ console.log(` connector ${c.server}: ${state}`);
7106
+ }
7107
+ for (const s of result.skipped) console.log(` skipped ${s.part}: ${s.reason}`);
7108
+ for (const r of result.removed) console.log(` ${r.part}: ${r.result.replace("_", " ")} (no longer in the plugin)`);
7109
+ })
7110
+ );
7111
+ plugins.command("rm <name>").description("remove a plugin's skills (a skill a session still holds is switched off)").action(
7112
+ run(async (name) => {
7113
+ const result = await api("DELETE", `/plugins/${encodeURIComponent(name)}`);
7114
+ console.log(`Removed ${result.name}: ${result.parts.map((p) => `${p.part} ${p.result.replace("_", " ")}`).join(", ")}`);
7115
+ })
7116
+ );
7117
+ for (const [verb, enabled] of [["enable", true], ["disable", false]]) {
7118
+ plugins.command(`${verb} <name>`).description(enabled ? "switch a plugin back on: its skills attach to new sessions again" : "switch a plugin off: its skills stop attaching to new sessions and plugin sessions refuse to start").action(
7119
+ run(async (name) => {
7120
+ await api("PATCH", `/plugins/${encodeURIComponent(name)}`, { enabled });
7121
+ console.log(`${name} is ${enabled ? "on" : "off"}.`);
7122
+ })
7123
+ );
7124
+ }
7125
+ plugins.command("run <name> <message>").description("start a plugin session: only that plugin's skills and MCP servers, and connected apps limited to the ones it declared").option("--agent <id>", "the agent to run (default: the workspace's Sky)").option("--json", "print the created session as JSON").action(
7126
+ run(async (name, message2, opts) => {
7127
+ const session2 = await api("POST", `/plugins/${encodeURIComponent(name)}/sessions`, { message: message2, ...opts.agent ? { agent: opts.agent } : {} });
7128
+ if (opts.json) return void console.log(JSON.stringify(session2));
7129
+ console.log(`Started ${session2.id} for ${name}. Follow it: sky session read ${session2.id} --wait`);
7130
+ })
7131
+ );
7132
+ plugins.command("policy <name> <policy>").description("workspace owners and admins: recommended | default | blocked | none (default installs it now)").option("--source <source>", "where a default plugin installs from (github:owner/repo[/path][@ref])").action(
7133
+ run(async (name, policy2, opts) => {
7134
+ const value = policy2 === "none" ? null : policy2;
7135
+ const result = await api("PUT", `/plugins/${encodeURIComponent(name)}/policy`, { policy: value, ...opts.source ? { source: opts.source } : {} });
7136
+ console.log(`${result.name}: ${result.policy ?? "no policy"}${result.installed ? " (installed)" : ""}`);
7137
+ })
7138
+ );
7139
+ var market = plugins.command("market").description("Claude Code marketplaces the workspace lists plugins from");
7140
+ market.command("list").description("every plugin the workspace's marketplaces list, with its install source, policy and whether it is installed").option("--json", "print the marketplaces as JSON").action(
7141
+ run(async (opts) => {
7142
+ const { marketplaces } = await api("GET", "/plugins/marketplaces");
7143
+ if (opts.json) return void console.log(JSON.stringify(marketplaces));
7144
+ for (const m of marketplaces) {
7145
+ console.log(`${m.name} (${m.source})${m.error ? `: ${m.error}` : ""}`);
7146
+ for (const p of m.plugins) console.log(` ${p.installed ? "\u25CF" : "\u25CB"} ${p.name}${p.policy ? ` [${p.policy}]` : ""} ${p.source ?? "(not on GitHub)"} ${p.description.slice(0, 80)}`);
7147
+ }
7148
+ })
7149
+ );
7150
+ market.command("add <source>").description("workspace owners and admins: list plugins from a folder holding .claude-plugin/marketplace.json").action(
7151
+ run(async (source) => {
7152
+ const m = await api("POST", "/plugins/marketplaces", { source });
7153
+ console.log(`Added ${m.name} (${m.source}): ${m.plugins.length} plugins.`);
7154
+ })
7155
+ );
7156
+ market.command("rm <source>").description("workspace owners and admins: stop listing a marketplace (installed plugins stay)").action(
7157
+ run(async (source) => {
7158
+ await api("DELETE", `/plugins/marketplaces?source=${encodeURIComponent(source)}`);
7159
+ console.log(`Removed ${source}.`);
7160
+ })
7161
+ );
6911
7162
  var skills = program.command("skills").description("the workspace's skill store: upload a skill, then attach it to an agent (sky skills attach, or [[skills]] in agent.toml)");
6912
7163
  skills.command("upload <dir>").description("upload a skill directory (SKILL.md at its root) as a new skill").option("--name <name>", "display name (default: the directory's name)").option("--json", "print the stored skill as JSON").action(
6913
7164
  run(async (dir, opts) => {
@@ -6999,7 +7250,7 @@ library.command("list").description("your Library, newest first").option("--sear
6999
7250
  );
7000
7251
  library.command("upload <path>").description("save a file from this computer to your Library").option("--workspace <key>", "place it in this workspace").action(
7001
7252
  run(async (path, opts) => {
7002
- const bytes = readFileSync19(path);
7253
+ const bytes = readFileSync20(path);
7003
7254
  const { artifact: artifact2 } = await uploadToLibrary({ bytes, name: basename9(path), mediaType: "application/octet-stream" }, `sky-upload-${crypto.randomUUID()}`, opts.workspace);
7004
7255
  console.log(renderLibraryArtifact(artifact2));
7005
7256
  })
@@ -7030,10 +7281,11 @@ library.command("place <id> <workspace>").description('place your artifact in a
7030
7281
  library.command("download <id> <out>").description("save one version's bytes to a file").option("--version <n>", "a saved version (the current one when omitted)").action(
7031
7282
  run(async (id, out, opts) => {
7032
7283
  const { bytes } = await downloadLibraryArtifact(id, opts.version ? Number(opts.version) : void 0);
7033
- writeFileSync11(out, bytes);
7284
+ writeFileSync10(out, bytes);
7034
7285
  console.log(`wrote ${bytes.length} bytes to ${out}`);
7035
7286
  })
7036
7287
  );
7288
+ registerLibraryLinkCommands(library);
7037
7289
  var artifact = program.command("artifact").description("artifacts: publish a task's files as a named, shareable result");
7038
7290
  artifact.command("list").description("the workspace's artifacts, or one task's with --task").option("--task <task>", "only this task's artifacts").action(
7039
7291
  run(async (opts) => {
@@ -7051,7 +7303,7 @@ artifact.command("get <id> <path>").description("read one file of an artifact; p
7051
7303
  run(async (id, path, opts) => {
7052
7304
  const bytes = await readArtifactFile(id, path);
7053
7305
  if (opts.out) {
7054
- writeFileSync11(opts.out, bytes);
7306
+ writeFileSync10(opts.out, bytes);
7055
7307
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
7056
7308
  } else process.stdout.write(bytes);
7057
7309
  })
@@ -7089,10 +7341,17 @@ designSystem.command("import <task> <folder>").description("import a local desig
7089
7341
  );
7090
7342
  designSystem.command("tokens <id> <file>").description("save a tokens.json file as the system's next version; --base is the version you edited").requiredOption("--base <version>", "the version the file was edited from", (value) => Number(value)).option("--note <note>", "one line saying what changed").action(
7091
7343
  run(async (id, file, opts) => {
7092
- const tokens = JSON.parse(readFileSync19(resolve9(file), "utf8"));
7344
+ const tokens = JSON.parse(readFileSync20(resolve9(file), "utf8"));
7093
7345
  console.log(renderArtifact(await saveDesignTokens(id, opts.base, tokens, opts.note)));
7094
7346
  })
7095
7347
  );
7348
+ designSystem.command("write <id> <path> [file]").description("save one of the system's editable files (path such as project/README.md) from a local file as its next version, or put back an earlier version's copy with --restore").requiredOption("--base <version>", "the version the file was edited from", (value) => Number(value)).option("--restore <version>", "restore the file as it was in this version instead of reading [file]", (value) => Number(value)).option("--note <note>", "one line saying what changed").action(
7349
+ run(async (id, path, file, opts) => {
7350
+ if (file === void 0 === (opts.restore === void 0)) throw Error("Give a local [file] to save, or --restore <version>.");
7351
+ const change = opts.restore === void 0 ? { content: readFileSync20(resolve9(file), "utf8") } : { restore_version: opts.restore };
7352
+ console.log(renderArtifact(await saveDesignSystemFile(id, path, opts.base, change, opts.note)));
7353
+ })
7354
+ );
7096
7355
  designSystem.command("comments <id>").description("read design-system comments, or add one with --text and --base").option("--text <text>", "comment to add").option("--target <target>", "overview, color:<name> or component:<name>", "overview").option("--base <version>", "the version you viewed", Number).action(run(async (id, opts) => {
7097
7356
  if (opts.text !== void 0 && (!Number.isInteger(opts.base) || opts.base < 1)) throw Error("Adding a comment requires --base <version>.");
7098
7357
  console.log(JSON.stringify(await designComments(id, opts.text === void 0 ? void 0 : { text: opts.text, target: opts.target, base_version: opts.base }), null, 2));
@@ -7402,7 +7661,7 @@ usageOptions(
7402
7661
  run(async (opts) => {
7403
7662
  const { bytes } = await apiBytes("GET", `/billing/usage/export${usageQuery(opts)}`);
7404
7663
  if (opts.out) {
7405
- writeFileSync11(opts.out, bytes);
7664
+ writeFileSync10(opts.out, bytes);
7406
7665
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
7407
7666
  } else {
7408
7667
  process.stdout.write(bytes);
@@ -7481,7 +7740,7 @@ memory.command("edit <index> <text...>").description("replace entry <index>").ac
7481
7740
  memory.command("rm <index>").description("remove entry <index>").action(run(async (index) => writeMemory({ op: "remove", index: memoryIndex(index) })));
7482
7741
  memory.command("clear").description("remove every entry").action(run(async () => writeMemory({ op: "clear" })));
7483
7742
  var context = program.command("context").description("search everything you can open in the workspace, and read a hit");
7484
- context.command("search <words...>").description('plain words, "exact phrase" or /regex/ (every matching line, like grep); follow --cursor for more').option("--scope <folder>", "memory/, chats, traces, outputs/, files/, meetings/, skills/<name>/, agents/ or docs/ (default everything)").option("--limit <n>", "hits per page (default 20)").option("--cursor <cursor>", "continue a previous search").option("--since <iso>", "inclusive lower time bound").option("--until <iso>", "exclusive upper time bound").option("--json", "print the API's answer as JSON").action(
7743
+ context.command("search <words...>").description('plain words, "exact phrase" or /regex/ (every matching line, like grep); follow --cursor for more').option("--scope <folder>", "memory/, chats, traces, artifacts/, files/, meetings/, skills/<name>/, agents/ or docs/ (default everything)").option("--limit <n>", "hits per page (default 20)").option("--cursor <cursor>", "continue a previous search").option("--since <iso>", "inclusive lower time bound").option("--until <iso>", "exclusive upper time bound").option("--json", "print the API's answer as JSON").action(
7485
7744
  run(async (words, opts) => {
7486
7745
  const page = await searchContext(words.join(" "), opts);
7487
7746
  console.log(opts.json ? JSON.stringify(page, null, 2) : renderContextPage(page));
@@ -8014,7 +8273,7 @@ notes.command("read <storeId> <noteId>").description("print one note").action(
8014
8273
  notes.command("save <storeId> <file>").description("write a note from a local file: --path creates one, --note saves a new version of one").option("--path <path>", "path of a new note, e.g. /projects/launch.md").option("--note <noteId>", "the note to update").action(
8015
8274
  run(async (storeId, file, opts) => {
8016
8275
  if (!opts.path === !opts.note) throw new Error("pass exactly one of --path (new note) or --note (update)");
8017
- const content = readFileSync19(file, "utf8");
8276
+ const content = readFileSync20(file, "utf8");
8018
8277
  const target = `/memory_stores/${encodeURIComponent(storeId)}/memories${opts.note ? `/${encodeURIComponent(opts.note)}` : ""}`;
8019
8278
  const { memory: memory2 } = await api("POST", target, { content, ...opts.path ? { path: opts.path } : {} });
8020
8279
  console.log(`Saved ${memory2.path} (${memory2.id})`);
@@ -8114,7 +8373,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
8114
8373
  }));
8115
8374
  var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
8116
8375
  traceCmd.command("start").description("start a trace: a grant for this machine, a root span, and the spool the hooks write to").option("--name <name>", "a name for the task").option("--source <source>", "how this machine reports itself", "claude-code").option("--hooks [settings]", "also install the Claude Code hooks (default: ./.claude/settings.local.json)").option("--capture <scopes>", "also send content, redacted on this machine first: any of prompts,tool_output,files").option("--file <path>", "a file the files scope may send (repeatable)", collect).option("--dir <path>", "a folder whose files the files scope may send when a file tool touches them (repeatable)", collect).action(run(async (opts) => {
8117
- const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-WLTD4C22.js");
8376
+ const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-OPRHOP2E.js");
8118
8377
  if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
8119
8378
  const scopes = parseContentScopes(opts.capture);
8120
8379
  const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
@@ -8149,7 +8408,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
8149
8408
  }));
8150
8409
  traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
8151
8410
  try {
8152
- const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-WLTD4C22.js");
8411
+ const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-OPRHOP2E.js");
8153
8412
  const chunks = [];
8154
8413
  for await (const chunk of process.stdin) chunks.push(chunk);
8155
8414
  const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
@@ -8162,14 +8421,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
8162
8421
  }
8163
8422
  });
8164
8423
  traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
8165
- const { readState, flush, grantSender } = await import("./trace-WLTD4C22.js");
8424
+ const { readState, flush, grantSender } = await import("./trace-OPRHOP2E.js");
8166
8425
  const state = readState();
8167
8426
  if (!state) throw new Error("no trace is running here");
8168
8427
  const outcome = await flush(grantSender(state), { attempts: 4 });
8169
8428
  console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
8170
8429
  }));
8171
8430
  traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
8172
- const { readState, spoolStatus } = await import("./trace-WLTD4C22.js");
8431
+ const { readState, spoolStatus } = await import("./trace-OPRHOP2E.js");
8173
8432
  const state = readState();
8174
8433
  if (!state) {
8175
8434
  console.log("No trace is running here.");
@@ -8179,7 +8438,7 @@ traceCmd.command("status").description("the running trace and its spool").action
8179
8438
  console.log(`${state.trace_id} as ${state.source}: ${spool.pending} pending, ${spool.dropped_full} dropped (spool full), ${spool.dropped_expired} given up, ${spool.refused} refused`);
8180
8439
  }));
8181
8440
  traceCmd.command("show [id]").description("the trace bundle: spans, the sessions they reach, cost counted once per session").option("--json", "print the bundle as JSON").action(run(async (id, opts) => {
8182
- const { readState } = await import("./trace-WLTD4C22.js");
8441
+ const { readState } = await import("./trace-OPRHOP2E.js");
8183
8442
  const ref = id ?? readState()?.trace_id;
8184
8443
  if (!ref) throw new Error("name a trace, or start one here");
8185
8444
  const bundle = await api("GET", `/traces/${ref}`);
@@ -8206,7 +8465,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
8206
8465
  for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
8207
8466
  }));
8208
8467
  traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
8209
- const { readState, record, flush, grantSender, clearState } = await import("./trace-WLTD4C22.js");
8468
+ const { readState, record, flush, grantSender, clearState } = await import("./trace-OPRHOP2E.js");
8210
8469
  const state = readState();
8211
8470
  if (!state) throw new Error("no trace is running here");
8212
8471
  if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
@@ -8216,7 +8475,7 @@ traceCmd.command("stop").description("end the root span, send what is left, and
8216
8475
  console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
8217
8476
  }));
8218
8477
  traceCmd.command("sync [payload]").description("upload this machine's agent sessions (Claude Code, Codex, Cursor, Gemini CLI and every other agent `--agents` lists) to the matching workspace's trace library, redacted here first").option("--enable", "turn sync on for this machine").option("--disable", "turn sync off; nothing more is uploaded").option("--route <match=workspace>", "send sessions whose folder path contains <match> to <workspace> (repeatable; replaces the saved rules)", collect).option("--default <workspace>", "where a session no rule matches goes").option("--keep-local", "keep sessions no rule matches on this machine (the default)").option("--session <ref>", "only this session: its id or transcript path (repeatable)", collect).option("--import <export>", "add a downloaded cloud export (claude.ai, ChatGPT, Gemini, Grok, DeepSeek \u2026: its .zip, folder or file) so sync uploads it (repeatable)", collect).option("--agents", "list the agents sync reads and which are on this machine").option("--full", "re-read every session, not only files that changed").option("--limit <n>", "at most this many changed sessions this run", (v) => Number.parseInt(v, 10)).option("--dry-run", "show what would be uploaded without uploading").option("--hook", "run from a Claude Code SessionEnd hook or Codex notify: upload that session in the background and return at once").option("--install-schedule", "also sweep every 15 minutes (macOS launchd)").option("--status", "what sync has done on this machine").option("--quiet", "print only failures").action(async (payload, opts) => {
8219
- const lib = await import("./trace-library-YMAVLH4Y.js");
8478
+ const lib = await import("./trace-library-SB7QYAU5.js");
8220
8479
  if (opts.hook) {
8221
8480
  try {
8222
8481
  let raw = payload ?? "";
@@ -8288,11 +8547,11 @@ traceCmd.command("sync [payload]").description("upload this machine's agent sess
8288
8547
  console.log(`Sweeping every 15 minutes (${plist}); a full re-read runs weekly. Log: ${log}`);
8289
8548
  }
8290
8549
  if (opts.status) {
8291
- const { readFileSync: readFileSync20 } = await import("fs");
8550
+ const { readFileSync: readFileSync21 } = await import("fs");
8292
8551
  const { join: join20 } = await import("path");
8293
8552
  let state = { sessions: {} };
8294
8553
  try {
8295
- state = JSON.parse(readFileSync20(join20(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
8554
+ state = JSON.parse(readFileSync21(join20(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
8296
8555
  } catch {
8297
8556
  }
8298
8557
  const counts = /* @__PURE__ */ new Map();
@@ -8331,7 +8590,7 @@ traceCmd.command("search <query...>").description("search every session in a wor
8331
8590
  console.log(opts.json ? JSON.stringify(page, null, 2) : renderContextPage(page));
8332
8591
  }));
8333
8592
  traceCmd.command("library").description("list the sessions in a workspace's trace library, most recently updated first").option("--workspace <slug>", "the workspace (default: the current one)").option("--limit <n>", "how many", (v) => Number.parseInt(v, 10), 20).option("--json", "print the page as JSON").action(run(async (opts) => {
8334
- const { libraryRequest } = await import("./trace-library-YMAVLH4Y.js");
8593
+ const { libraryRequest } = await import("./trace-library-SB7QYAU5.js");
8335
8594
  const workspace2 = opts.workspace ?? currentUniverse();
8336
8595
  if (!workspace2) throw new Error("name a workspace with --workspace");
8337
8596
  const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);
@@ -2,7 +2,7 @@ import {
2
2
  admittedInputScopeSchema,
3
3
  external_exports,
4
4
  messagePartSchema
5
- } from "./chunk-D3WG4BMK.js";
5
+ } from "./chunk-CJBZVPDF.js";
6
6
  import "./chunk-MLKGABMK.js";
7
7
 
8
8
  // ../../packages/chat/src/stream.ts
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  USER_AGENT,
3
3
  configPath
4
- } from "./chunk-S4YG3TXA.js";
4
+ } from "./chunk-UZ7KWRQH.js";
5
5
  import {
6
6
  TRACE_CONTENT_SCOPES,
7
7
  redactTraceText
8
- } from "./chunk-D3WG4BMK.js";
8
+ } from "./chunk-CJBZVPDF.js";
9
9
  import "./chunk-MLKGABMK.js";
10
10
 
11
11
  // src/trace.ts
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  ApiError
3
- } from "./chunk-KWLEADJQ.js";
3
+ } from "./chunk-K3LB4K2C.js";
4
4
  import {
5
5
  USER_AGENT,
6
6
  apiBase,
7
7
  apiToken
8
- } from "./chunk-S4YG3TXA.js";
8
+ } from "./chunk-UZ7KWRQH.js";
9
9
  import {
10
10
  SessionSourceCollector,
11
11
  publicRemote,
12
12
  redactTraceText
13
- } from "./chunk-D3WG4BMK.js";
13
+ } from "./chunk-CJBZVPDF.js";
14
14
  import "./chunk-MLKGABMK.js";
15
15
 
16
16
  // src/trace-library.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsky/sky",
3
- "version": "2.24.1",
3
+ "version": "2.26.0",
4
4
  "description": "sky \u2014 the AgentSky developer CLI: launch and talk to long-lived agents from your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
File without changes