@agentsky/sky 2.28.0 → 2.30.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.
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  streamEvents,
12
12
  uploadFile,
13
13
  writeResponseFile
14
- } from "./chunk-5OBCA2MM.js";
14
+ } from "./chunk-TIFRDEFP.js";
15
15
  import {
16
16
  CLI_VERSION,
17
17
  USER_AGENT,
@@ -22,7 +22,7 @@ import {
22
22
  currentUniverse,
23
23
  loadConfig,
24
24
  saveConfig
25
- } from "./chunk-ABDGMJYV.js";
25
+ } from "./chunk-KNGZR3CX.js";
26
26
  import {
27
27
  AGENT_TYPES,
28
28
  MODEL_SUBSCRIPTION_PLAN_PHRASE,
@@ -44,11 +44,11 @@ import {
44
44
  skillRefSchema,
45
45
  splitMcpServers,
46
46
  supersededBy
47
- } from "./chunk-OFH52W34.js";
47
+ } from "./chunk-JOLDBZV3.js";
48
48
  import "./chunk-MLKGABMK.js";
49
49
 
50
50
  // src/index.ts
51
- import { existsSync as existsSync13, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
51
+ import { existsSync as existsSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync11 } from "fs";
52
52
  import { basename as basename9, resolve as resolve9 } from "path";
53
53
  import { createInterface as createInterface6 } from "readline";
54
54
  import { Command } from "commander";
@@ -3440,8 +3440,10 @@ async function triggerRequest(id, resource, change) {
3440
3440
  // src/session-workspace.ts
3441
3441
  import { spawnSync as spawnSync4 } from "child_process";
3442
3442
  import { createHash as createHash5, randomUUID } from "crypto";
3443
- import { readdirSync as readdirSync5, statSync as statSync6 } from "fs";
3444
- import { basename as basename7, join as join12, relative as relative3, resolve as resolve5 } from "path";
3443
+ import { existsSync as existsSync10, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync12, renameSync, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
3444
+ import { homedir as homedir8, hostname as hostname2, tmpdir as tmpdir2 } from "os";
3445
+ import { basename as basename7, dirname as dirname6, join as join12, relative as relative3, resolve as resolve5 } from "path";
3446
+ import { inflateRawSync } from "zlib";
3445
3447
  var SINGLE_IMPORT_MAX = 25 * 1024 * 1024;
3446
3448
  var PART_SIZE = 8 * 1024 * 1024;
3447
3449
  var SKIPPED2 = /* @__PURE__ */ new Set([".git", "node_modules"]);
@@ -3561,6 +3563,97 @@ async function handoff(id, targetAgent, opts = {}) {
3561
3563
  }
3562
3564
  return h;
3563
3565
  }
3566
+ function zipEntries(archive) {
3567
+ let end = archive.length - 22;
3568
+ while (end >= 0 && archive.readUInt32LE(end) !== 101010256) end -= 1;
3569
+ if (end < 0) throw new ApiError(422, "checkpoint_invalid", "the downloaded conversation is not a readable archive");
3570
+ const entries = /* @__PURE__ */ new Map();
3571
+ let at = archive.readUInt32LE(end + 16);
3572
+ for (let index = archive.readUInt16LE(end + 10); index > 0; index -= 1) {
3573
+ const method = archive.readUInt16LE(at + 10);
3574
+ const size = archive.readUInt32LE(at + 20);
3575
+ const nameLength = archive.readUInt16LE(at + 28);
3576
+ const local = archive.readUInt32LE(at + 42);
3577
+ const start = local + 30 + archive.readUInt16LE(local + 26) + archive.readUInt16LE(local + 28);
3578
+ const packed = archive.subarray(start, start + size);
3579
+ if (method !== 0 && method !== 8) throw new ApiError(422, "checkpoint_invalid", "the downloaded conversation uses an unsupported compression");
3580
+ entries.set(archive.subarray(at + 46, at + 46 + nameLength).toString("utf8"), method === 8 ? inflateRawSync(packed) : Buffer.from(packed));
3581
+ at += 46 + nameLength + archive.readUInt16LE(at + 30) + archive.readUInt16LE(at + 32);
3582
+ }
3583
+ return entries;
3584
+ }
3585
+ function conversationFiles(archive, harness2) {
3586
+ const entries = zipEntries(archive);
3587
+ const manifest = JSON.parse(entries.get("manifest.json")?.toString("utf8") ?? "null");
3588
+ const nativeId = manifest?.metadata?.native_session_id ?? "";
3589
+ if (manifest?.format !== "asteroids.native-checkpoint" || manifest.source_harness !== harness2 || !Array.isArray(manifest.files) || !/^[A-Za-z0-9_-]{1,200}$/.test(nativeId)) {
3590
+ throw new ApiError(422, "checkpoint_invalid", "the downloaded conversation is not one this computer can continue");
3591
+ }
3592
+ const ours = (path) => {
3593
+ const parts = path.split("/");
3594
+ if (parts.some((part) => !part || part === "." || part === "..")) return false;
3595
+ if (harness2 === "claude_code") return parts[0] === "projects" && parts.length >= 3 && (parts[2] === `${nativeId}.jsonl` || parts[2] === nativeId);
3596
+ return parts[0] === "sessions" && parts.at(-1).startsWith("rollout-") && parts.at(-1).endsWith(`${nativeId}.jsonl`);
3597
+ };
3598
+ const files2 = manifest.files.filter((file) => ours(file.path)).map((file) => {
3599
+ const data = entries.get(`files/${file.path}`);
3600
+ if (!data || data.length !== file.size || createHash5("sha256").update(data).digest("hex") !== file.sha256) {
3601
+ throw new ApiError(422, "checkpoint_invalid", "the downloaded conversation is incomplete; try again");
3602
+ }
3603
+ return { path: file.path, data };
3604
+ });
3605
+ if (!files2.length) throw new ApiError(422, "checkpoint_invalid", "the downloaded conversation has no transcript");
3606
+ return { nativeId, files: files2 };
3607
+ }
3608
+ async function verifiedDownload(path) {
3609
+ const res = await apiRaw("GET", path);
3610
+ if (!res.ok) {
3611
+ const body = await res.json().catch(() => null);
3612
+ throw new ApiError(res.status, body?.error?.code ?? "request_failed", body?.error?.message ?? `AgentSky answered ${res.status}`);
3613
+ }
3614
+ const bytes = Buffer.from(await res.arrayBuffer());
3615
+ const expected = res.headers.get("x-content-sha256");
3616
+ if (expected && createHash5("sha256").update(bytes).digest("hex") !== expected) throw new ApiError(502, "download_corrupt", "the download was damaged; try again");
3617
+ return bytes;
3618
+ }
3619
+ async function continueHere(id, dir, opts = {}) {
3620
+ const session2 = (await api("GET", `/sessions/${encodeURIComponent(id)}`)).session;
3621
+ const harness2 = session2.agentType;
3622
+ if (harness2 !== "claude_code" && harness2 !== "codex") throw new ApiError(409, "harness_unsupported", "only Claude Code and Codex sessions can continue on a computer");
3623
+ let { handoff: h } = await api("POST", `/sessions/${encodeURIComponent(id)}/local-handoff`, { machine: hostname2().slice(0, 120) }, { idempotencyKey: opts.idempotencyKey ?? randomUUID() });
3624
+ opts.onStatus?.(h);
3625
+ while (!TERMINAL.has(h.status)) {
3626
+ await new Promise((r) => setTimeout(r, opts.pollMs ?? 2e3));
3627
+ const next = (await api("GET", `/session-handoffs/${encodeURIComponent(h.id)}`)).handoff;
3628
+ if (next.status !== h.status) opts.onStatus?.(next);
3629
+ h = next;
3630
+ }
3631
+ if (h.status !== "completed") throw new ApiError(422, h.error?.code ?? "handoff_failed", h.error?.message ?? "the session could not be moved; it stays in the cloud");
3632
+ const { nativeId, files: files2 } = conversationFiles(await verifiedDownload(`/session-handoffs/${encodeURIComponent(h.id)}/checkpoint`), harness2);
3633
+ const root = harness2 === "codex" ? process.env.CODEX_HOME || join12(homedir8(), ".codex") : process.env.CLAUDE_CONFIG_DIR || join12(homedir8(), ".claude");
3634
+ const stamp = Date.now();
3635
+ for (const file of files2) {
3636
+ const target = join12(root, file.path);
3637
+ mkdirSync4(dirname6(target), { recursive: true });
3638
+ if (existsSync10(target)) {
3639
+ if (!lstatSync2(target).isFile()) throw new ApiError(409, "restore_blocked", `something other than a file is in the way at ${target}`);
3640
+ if (readFileSync12(target).equals(file.data)) continue;
3641
+ renameSync(target, `${target}.before-agentsky-${stamp}`);
3642
+ }
3643
+ writeFileSync7(target, file.data, { mode: 384 });
3644
+ }
3645
+ const folder = resolve5(dir);
3646
+ mkdirSync4(folder, { recursive: true });
3647
+ const carried = h.workspace_carried === true;
3648
+ if (carried) {
3649
+ const archive = join12(tmpdir2(), `agentsky-workspace-${h.id}.tar.gz`);
3650
+ writeFileSync7(archive, await verifiedDownload(`/session-handoffs/${encodeURIComponent(h.id)}/workspace`), { mode: 384 });
3651
+ const tar = spawnSync4("tar", ["-xzf", archive, "-C", folder]);
3652
+ if (tar.status !== 0) throw new ApiError(422, "workspace_unpack_failed", `tar failed: ${tar.stderr.toString().trim()}`);
3653
+ }
3654
+ const resume = harness2 === "codex" ? `cd ${JSON.stringify(folder)} && codex resume ${nativeId}` : `cd ${JSON.stringify(folder)} && claude --resume ${nativeId}`;
3655
+ return { harness: harness2, nativeId, folder, workspaceCarried: carried, resume };
3656
+ }
3564
3657
 
3565
3658
  // src/render.ts
3566
3659
  var dim = (s) => `\x1B[2m${s}\x1B[0m`;
@@ -3682,15 +3775,15 @@ async function readTurn(sessionId, opts = {}) {
3682
3775
  }
3683
3776
 
3684
3777
  // src/setup.ts
3685
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
3686
- import { dirname as dirname7, join as join15 } from "path";
3778
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
3779
+ import { dirname as dirname8, join as join15 } from "path";
3687
3780
  import { createInterface as createInterface3 } from "readline";
3688
3781
 
3689
3782
  // src/setup-local.ts
3690
3783
  import { isUtf8 as isUtf83 } from "buffer";
3691
- import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync12, statSync as statSync7 } from "fs";
3692
- import { homedir as homedir8 } from "os";
3693
- import { dirname as dirname6, isAbsolute as isAbsolute2, join as join13, resolve as resolve6 } from "path";
3784
+ import { existsSync as existsSync11, readdirSync as readdirSync6, readFileSync as readFileSync13, statSync as statSync7 } from "fs";
3785
+ import { homedir as homedir9 } from "os";
3786
+ import { dirname as dirname7, isAbsolute as isAbsolute2, join as join13, resolve as resolve6 } from "path";
3694
3787
  import { parse as parseToml4 } from "smol-toml";
3695
3788
  var MAX_SKILL_FILE_BYTES = 1024 * 1024;
3696
3789
  var MAX_IMPORT_DEPTH = 5;
@@ -3719,7 +3812,7 @@ function skillFiles2(root, prefix) {
3719
3812
  if (entry2.isDirectory()) {
3720
3813
  if (!SKIPPED_DIRS.has(entry2.name)) files2.push(...skillFiles2(path, `${prefix}/${entry2.name}`));
3721
3814
  } else if (entry2.isFile() && !sensitive(entry2.name) && statSync7(path).size <= MAX_SKILL_FILE_BYTES) {
3722
- const bytes = redacted(readFileSync12(path));
3815
+ const bytes = redacted(readFileSync13(path));
3723
3816
  if (bytes) files2.push({ path: `${prefix}/${entry2.name}`, bytes });
3724
3817
  }
3725
3818
  }
@@ -3729,7 +3822,7 @@ function readLocalSkills(agents) {
3729
3822
  const skills2 = [];
3730
3823
  const ignored = [];
3731
3824
  for (const agent2 of agents) {
3732
- if (!existsSync10(agent2.skillsDir)) continue;
3825
+ if (!existsSync11(agent2.skillsDir)) continue;
3733
3826
  for (const entry2 of readdirSync6(agent2.skillsDir, { withFileTypes: true })) {
3734
3827
  const dir = join13(agent2.skillsDir, entry2.name);
3735
3828
  let isDir2 = entry2.isDirectory();
@@ -3740,8 +3833,8 @@ function readLocalSkills(agents) {
3740
3833
  isDir2 = false;
3741
3834
  }
3742
3835
  }
3743
- if (!isDir2 || !existsSync10(join13(dir, "SKILL.md")) || isInstalledSkill(dir)) continue;
3744
- const name = frontmatterName(readFileSync12(join13(dir, "SKILL.md"), "utf8"));
3836
+ if (!isDir2 || !existsSync11(join13(dir, "SKILL.md")) || isInstalledSkill(dir)) continue;
3837
+ const name = frontmatterName(readFileSync13(join13(dir, "SKILL.md"), "utf8"));
3745
3838
  if (!name) {
3746
3839
  ignored.push({ agent: agent2.id, dir, reason: "SKILL.md has no name" });
3747
3840
  continue;
@@ -3769,11 +3862,11 @@ function inlineImports(content, from, home, depth, seen) {
3769
3862
  }
3770
3863
  const target = fence ? void 0 : line.match(/^@(\S+\.(?:md|markdown|txt))$/i)?.[1];
3771
3864
  if (!target || depth >= MAX_IMPORT_DEPTH) return line;
3772
- const path = target.startsWith("~/") ? join13(home, target.slice(2)) : isAbsolute2(target) ? target : resolve6(dirname6(from), target);
3865
+ const path = target.startsWith("~/") ? join13(home, target.slice(2)) : isAbsolute2(target) ? target : resolve6(dirname7(from), target);
3773
3866
  if (seen.includes(path)) return "";
3774
3867
  let imported;
3775
3868
  try {
3776
- imported = readFileSync12(path, "utf8");
3869
+ imported = readFileSync13(path, "utf8");
3777
3870
  } catch {
3778
3871
  return line;
3779
3872
  }
@@ -3781,7 +3874,7 @@ function inlineImports(content, from, home, depth, seen) {
3781
3874
  return inlineImports(imported, path, home, depth + 1, seen).trim();
3782
3875
  }).join("\n");
3783
3876
  }
3784
- function readGlobalInstructions(agents, home = homedir8()) {
3877
+ function readGlobalInstructions(agents, home = homedir9()) {
3785
3878
  const found = [];
3786
3879
  for (const agent2 of agents) {
3787
3880
  const file = INSTRUCTION_FILES2[agent2.id];
@@ -3789,7 +3882,7 @@ function readGlobalInstructions(agents, home = homedir8()) {
3789
3882
  const path = join13(agent2.root, file);
3790
3883
  let raw;
3791
3884
  try {
3792
- raw = readFileSync12(path, "utf8");
3885
+ raw = readFileSync13(path, "utf8");
3793
3886
  } catch {
3794
3887
  continue;
3795
3888
  }
@@ -3808,7 +3901,7 @@ ${item.content.trim()}`).join("\n\n");
3808
3901
  }
3809
3902
  function readJson3(path) {
3810
3903
  try {
3811
- return JSON.parse(readFileSync12(path, "utf8"));
3904
+ return JSON.parse(readFileSync13(path, "utf8"));
3812
3905
  } catch {
3813
3906
  return void 0;
3814
3907
  }
@@ -3825,12 +3918,12 @@ function serversOf(agent2, home) {
3825
3918
  if (agent2.id === "claude_code") return readJson3(join13(home, ".claude.json"))?.mcpServers ?? {};
3826
3919
  if (agent2.id === "cursor") return readJson3(join13(agent2.root, "mcp.json"))?.mcpServers ?? {};
3827
3920
  try {
3828
- return parseToml4(readFileSync12(join13(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
3921
+ return parseToml4(readFileSync13(join13(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
3829
3922
  } catch {
3830
3923
  return {};
3831
3924
  }
3832
3925
  }
3833
- function findLocalSecrets(agents, home = homedir8()) {
3926
+ function findLocalSecrets(agents, home = homedir9()) {
3834
3927
  const secrets2 = [];
3835
3928
  for (const agent2 of agents) {
3836
3929
  for (const [name, def] of Object.entries(serversOf(agent2, home))) {
@@ -3847,8 +3940,8 @@ function findLocalSecrets(agents, home = homedir8()) {
3847
3940
 
3848
3941
  // src/subscriptions.ts
3849
3942
  import { spawn as spawn3 } from "child_process";
3850
- import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
3851
- import { homedir as homedir9 } from "os";
3943
+ import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
3944
+ import { homedir as homedir10 } from "os";
3852
3945
  import { join as join14 } from "path";
3853
3946
  import { createInterface as createInterface2 } from "readline";
3854
3947
  var ALIASES = {
@@ -3944,12 +4037,12 @@ async function connectClaude() {
3944
4037
  const expiry = sub.expiresAt ? ` (expires ~${sub.expiresAt.slice(0, 10)})` : "";
3945
4038
  console.log(`Connected Claude subscription${expiry}. Powers new eligible agents.`);
3946
4039
  }
3947
- function codexSignIn(env = process.env, home = homedir9()) {
4040
+ function codexSignIn(env = process.env, home = homedir10()) {
3948
4041
  const path = join14(env.CODEX_HOME || join14(home, ".codex"), "auth.json");
3949
- if (!existsSync11(path)) {
4042
+ if (!existsSync12(path)) {
3950
4043
  throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
3951
4044
  }
3952
- const raw = readFileSync13(path, "utf8");
4045
+ const raw = readFileSync14(path, "utf8");
3953
4046
  try {
3954
4047
  const parsed = JSON.parse(raw);
3955
4048
  return { path, raw, account: parsed.tokens?.account_id };
@@ -3957,12 +4050,12 @@ function codexSignIn(env = process.env, home = homedir9()) {
3957
4050
  throw new ApiError(400, "invalid_codex_auth", `${path} isn't valid JSON \u2014 re-run \`codex login\``);
3958
4051
  }
3959
4052
  }
3960
- function cursorSignIn(env = process.env, home = homedir9()) {
4053
+ function cursorSignIn(env = process.env, home = homedir10()) {
3961
4054
  const path = join14(env.XDG_CONFIG_HOME || join14(home, ".config"), "cursor", "auth.json");
3962
- if (!existsSync11(path)) {
4055
+ if (!existsSync12(path)) {
3963
4056
  throw new ApiError(404, "no_cursor_auth", `no ${path} \u2014 run \`cursor-agent login\` first`);
3964
4057
  }
3965
- const raw = readFileSync13(path, "utf8");
4058
+ const raw = readFileSync14(path, "utf8");
3966
4059
  try {
3967
4060
  const parsed = JSON.parse(raw);
3968
4061
  if (typeof parsed.accessToken !== "string" || typeof parsed.refreshToken !== "string") throw new Error("shape");
@@ -4123,11 +4216,11 @@ function planProviders(names2) {
4123
4216
  }));
4124
4217
  }
4125
4218
  function reportPath() {
4126
- return join15(dirname7(configPath()), "setup.json");
4219
+ return join15(dirname8(configPath()), "setup.json");
4127
4220
  }
4128
4221
  function loadReport() {
4129
4222
  try {
4130
- const saved = JSON.parse(readFileSync14(reportPath(), "utf8"));
4223
+ const saved = JSON.parse(readFileSync15(reportPath(), "utf8"));
4131
4224
  return { agents: saved.agents ?? [], plans: saved.plans ?? [], ...saved.secrets ? { secrets: saved.secrets } : {} };
4132
4225
  } catch {
4133
4226
  return { agents: [], plans: [] };
@@ -4140,8 +4233,8 @@ function mergeReport(base, next) {
4140
4233
  return { agents, plans, ...secrets2 ? { secrets: secrets2 } : {} };
4141
4234
  }
4142
4235
  function saveReport(report) {
4143
- mkdirSync4(dirname7(reportPath()), { recursive: true });
4144
- writeFileSync7(reportPath(), `${JSON.stringify(report, null, 2)}
4236
+ mkdirSync5(dirname8(reportPath()), { recursive: true });
4237
+ writeFileSync8(reportPath(), `${JSON.stringify(report, null, 2)}
4145
4238
  `, { mode: 384 });
4146
4239
  }
4147
4240
  function confirm3(question) {
@@ -4512,7 +4605,7 @@ function renderArtifact(artifact2) {
4512
4605
  }
4513
4606
 
4514
4607
  // src/skills-store.ts
4515
- import { readdirSync as readdirSync7, readFileSync as readFileSync15, statSync as statSync8 } from "fs";
4608
+ import { readdirSync as readdirSync7, readFileSync as readFileSync16, statSync as statSync8 } from "fs";
4516
4609
  import { basename as basename8, join as join16, relative as relative4, resolve as resolve7 } from "path";
4517
4610
  function skillBundle(dir) {
4518
4611
  const root = resolve7(dir);
@@ -4522,7 +4615,7 @@ function skillBundle(dir) {
4522
4615
  for (const name of readdirSync7(path).sort()) {
4523
4616
  const full = join16(path, name);
4524
4617
  if (statSync8(full).isDirectory()) walk(full);
4525
- else files2.push({ path: `${top}/${relative4(root, full)}`, bytes: readFileSync15(full) });
4618
+ else files2.push({ path: `${top}/${relative4(root, full)}`, bytes: readFileSync16(full) });
4526
4619
  }
4527
4620
  };
4528
4621
  walk(root);
@@ -4574,8 +4667,8 @@ async function setAgentSkill(agentId, skillId, verb) {
4574
4667
 
4575
4668
  // src/task-export.ts
4576
4669
  import { createHash as createHash6 } from "crypto";
4577
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "fs";
4578
- import { dirname as dirname8, join as join17 } from "path";
4670
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync9 } from "fs";
4671
+ import { dirname as dirname9, join as join17 } from "path";
4579
4672
  import { stringify as stringifyToml } from "smol-toml";
4580
4673
  var TEXT_MAX = 2e4;
4581
4674
  function scrub(text, names2) {
@@ -4866,8 +4959,8 @@ async function exportTaskHarbor(taskRef, outDir, opts) {
4866
4959
  const written2 = [];
4867
4960
  for (const [path, content] of files2) {
4868
4961
  const target = join17(outDir, path);
4869
- mkdirSync5(dirname8(target), { recursive: true });
4870
- writeFileSync8(target, content, typeof content === "string" ? { mode: path.endsWith(".sh") || path.endsWith(".py") ? 493 : 420 } : void 0);
4962
+ mkdirSync6(dirname9(target), { recursive: true });
4963
+ writeFileSync9(target, content, typeof content === "string" ? { mode: path.endsWith(".sh") || path.endsWith(".py") ? 493 : 420 } : void 0);
4871
4964
  written2.push(path);
4872
4965
  }
4873
4966
  return { written: written2, record };
@@ -5219,6 +5312,66 @@ function renderReachRequest(request) {
5219
5312
  return `${request.id} ${request.status}${request.error ? ` ${request.error.code}: ${request.error.message}` : ""}`;
5220
5313
  }
5221
5314
 
5315
+ // ../../packages/uikit-components/src/capabilities-overview.ts
5316
+ var CAPABILITY_KINDS = [
5317
+ { kind: "connector", title: "Connected apps", manage: "connectors" },
5318
+ { kind: "tool", title: "Tools", manage: "tools" },
5319
+ { kind: "plugin", title: "Plugins", manage: "plugins" },
5320
+ { kind: "mcp_server", title: "MCP servers", manage: "vaults" },
5321
+ { kind: "vault", title: "Secrets", manage: "vaults" },
5322
+ { kind: "browser", title: "Browser logins", manage: "browser-logins" },
5323
+ { kind: "mac", title: "Lent by your Macs", manage: "mac" },
5324
+ { kind: "plan", title: "Your plans", manage: "plans" }
5325
+ ];
5326
+ var CAPABILITY_WHERE_LABEL = { cloud: "Cloud", mac: "Mac", both: "Cloud and Mac" };
5327
+ var CAPABILITY_STATUS_LABEL = {
5328
+ on: "On",
5329
+ connected: "Connected",
5330
+ needs_signin: "Needs sign-in",
5331
+ needs_permission: "Needs permission",
5332
+ off: "Off"
5333
+ };
5334
+ var CAPABILITY_COST_LABEL = { free: "Free", credits: "Credits", plan: "Your plan", provider: "Provider pricing" };
5335
+ function sharerLabel(sharer) {
5336
+ if (sharer.type === "me") return "You";
5337
+ if (sharer.type === "workspace") return "Workspace";
5338
+ return sharer.name;
5339
+ }
5340
+ function needsAttention(item) {
5341
+ return item.status === "needs_signin" || item.status === "needs_permission";
5342
+ }
5343
+ function capabilityLine(item) {
5344
+ const where = item.kind === "mac" && item.machine ? item.machine.name : CAPABILITY_WHERE_LABEL[item.where];
5345
+ return [where, sharerLabel(item.shared_by), CAPABILITY_COST_LABEL[item.cost]].join(" \xB7 ");
5346
+ }
5347
+ var attentionFirst = (a, b) => Number(needsAttention(b)) - Number(needsAttention(a));
5348
+ function capabilityGroups(items) {
5349
+ return CAPABILITY_KINDS.flatMap(({ kind, title, manage }) => {
5350
+ const rows = items.filter((item) => item.kind === kind).sort(attentionFirst);
5351
+ if (rows.length === 0) return [];
5352
+ return [{ kind, title, manage, items: rows, attention: rows.filter(needsAttention).length }];
5353
+ });
5354
+ }
5355
+
5356
+ // src/capabilities.ts
5357
+ async function listCapabilities() {
5358
+ return api("GET", "/capabilities");
5359
+ }
5360
+ function renderCapabilities(overview, options = {}) {
5361
+ const rows = options.attention ? overview.data.filter(needsAttention) : overview.data;
5362
+ const lines = [];
5363
+ for (const group of capabilityGroups(rows)) {
5364
+ lines.push(group.attention ? `${group.title} (${group.attention} need${group.attention === 1 ? "s" : ""} you)` : group.title);
5365
+ for (const item of group.items) {
5366
+ const detail = item.detail ? ` ${item.detail}` : "";
5367
+ lines.push(` ${item.name} ${CAPABILITY_STATUS_LABEL[item.status].toLowerCase()} ${capabilityLine(item)}${detail}`);
5368
+ }
5369
+ }
5370
+ for (const gap of overview.unavailable) lines.push(`(${gap.message})`);
5371
+ if (!lines.length) return options.attention ? "nothing needs you" : "nothing yet: connect an app (sky connectors) or install a plugin (sky plugins install)";
5372
+ return lines.join("\n");
5373
+ }
5374
+
5222
5375
  // src/compare.ts
5223
5376
  async function listComparisons(opts = {}) {
5224
5377
  const qs = opts.archived ? "?archived=true" : "";
@@ -5299,14 +5452,14 @@ function renderThreadSummary(t) {
5299
5452
  }
5300
5453
 
5301
5454
  // src/library.ts
5302
- import { readFileSync as readFileSync17 } from "fs";
5455
+ import { readFileSync as readFileSync18 } from "fs";
5303
5456
 
5304
5457
  // src/api-command.ts
5305
- import { readFileSync as readFileSync16 } from "fs";
5458
+ import { readFileSync as readFileSync17 } from "fs";
5306
5459
  var API_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
5307
- function readData(data, stdin = () => readFileSync16(0, "utf8")) {
5460
+ function readData(data, stdin = () => readFileSync17(0, "utf8")) {
5308
5461
  if (data === void 0) return void 0;
5309
- const raw = data === "-" ? stdin() : data.startsWith("@") ? readFileSync16(data.slice(1), "utf8") : data;
5462
+ const raw = data === "-" ? stdin() : data.startsWith("@") ? readFileSync17(data.slice(1), "utf8") : data;
5310
5463
  try {
5311
5464
  JSON.parse(raw);
5312
5465
  } catch {
@@ -5512,7 +5665,7 @@ function registerLibraryLinkCommands(library2) {
5512
5665
  });
5513
5666
  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
5667
  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));
5668
+ const body = opts.file !== void 0 ? { text: new TextDecoder("utf-8", { fatal: true }).decode(readFileSync18(opts.file)) } : JSON.parse(readData(opts.data));
5516
5669
  if (!body || typeof body !== "object" || Array.isArray(body)) throw new Error("--data must be a JSON object with one native save field.");
5517
5670
  if ("revision" in body && body.revision !== opts.revision) throw new Error("--data revision must match --revision.");
5518
5671
  console.log(JSON.stringify(await saveSharedLibraryFile(opts.token, sharedLibrarySaveSchema.parse({ ...body, revision: opts.revision })), null, 2));
@@ -5555,7 +5708,7 @@ function renderTodo(todo) {
5555
5708
  }
5556
5709
 
5557
5710
  // src/design-systems.ts
5558
- import { readdirSync as readdirSync8, readFileSync as readFileSync18, statSync as statSync9 } from "fs";
5711
+ import { readdirSync as readdirSync8, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
5559
5712
  import { join as join18, relative as relative5, sep as sep3 } from "path";
5560
5713
  var TEXT2 = /\.(mdx?|markdown|txt|json|m?js|cjs|jsx|tsx?|css|html?|svg|xml|csv|ya?ml|toml)$/i;
5561
5714
  var MEDIA = {
@@ -5606,7 +5759,7 @@ function fileTableFrom(dir) {
5606
5759
  continue;
5607
5760
  }
5608
5761
  const key = relative5(dir, path).split(sep3).join("/");
5609
- const bytes = readFileSync18(path);
5762
+ const bytes = readFileSync19(path);
5610
5763
  files2[key] = TEXT2.test(name) ? bytes.toString("utf8") : `data:${MEDIA[name.split(".").pop()?.toLowerCase() ?? ""] ?? "application/octet-stream"};base64,${bytes.toString("base64")}`;
5611
5764
  }
5612
5765
  };
@@ -5715,19 +5868,19 @@ function workspaceFlagIsCommands(argv, commandPath) {
5715
5868
  }
5716
5869
 
5717
5870
  // src/harness.ts
5718
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "fs";
5719
- import { dirname as dirname9, join as join19, resolve as resolve8 } from "path";
5871
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
5872
+ import { dirname as dirname10, join as join19, resolve as resolve8 } from "path";
5720
5873
  var HARNESS_FILE = "harness.json";
5721
5874
  function harnessFilePath(dir) {
5722
5875
  return join19(resolve8(dir), HARNESS_FILE);
5723
5876
  }
5724
5877
  function readHarnessFile(dir) {
5725
5878
  const path = harnessFilePath(dir);
5726
- if (!existsSync12(path)) {
5879
+ if (!existsSync13(path)) {
5727
5880
  throw new Error(`no ${HARNESS_FILE} found in ${resolve8(dir)} \u2014 run \`sky harness init\` first`);
5728
5881
  }
5729
5882
  try {
5730
- return JSON.parse(readFileSync19(path, "utf8"));
5883
+ return JSON.parse(readFileSync20(path, "utf8"));
5731
5884
  } catch (err) {
5732
5885
  throw new Error(`could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`);
5733
5886
  }
@@ -5754,11 +5907,11 @@ var INIT_COMMENT = `# harness.json \u2014 workspace harness profile skeleton
5754
5907
  `;
5755
5908
  function harnessInit(dir) {
5756
5909
  const path = harnessFilePath(dir);
5757
- if (existsSync12(path)) {
5910
+ if (existsSync13(path)) {
5758
5911
  throw new Error(`${path} already exists \u2014 delete it to re-init`);
5759
5912
  }
5760
- mkdirSync6(dirname9(path), { recursive: true });
5761
- writeFileSync9(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
5913
+ mkdirSync7(dirname10(path), { recursive: true });
5914
+ writeFileSync10(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
5762
5915
  `);
5763
5916
  console.log(`Created ${path}`);
5764
5917
  console.log(INIT_COMMENT);
@@ -6515,6 +6668,14 @@ session.command("handoff <ref> <targetAgent>").description("hand the session's c
6515
6668
  if (done.target_session) console.log(`${done.target_session} (${done.resolved_mode === "native_fork" ? "forked" : "from a written summary"})`);
6516
6669
  })
6517
6670
  );
6671
+ session.command("continue-here <ref>").description("move an idle Claude Code or Codex session you own onto this computer and print how to resume it; the cloud session then takes no more turns").option("--dir <folder>", "where the session's workspace goes", ".").action(
6672
+ run(async (ref, opts) => {
6673
+ const id = await resolveSessionRef(ref);
6674
+ const moved = await continueHere(id, opts.dir, { onStatus: (h) => console.error(`${h.id}: ${h.status}`) });
6675
+ if (!moved.workspaceCarried) console.error("The workspace was not copied with this move; copy what you need with sky session workspace ls and cat.");
6676
+ console.log(moved.resume);
6677
+ })
6678
+ );
6518
6679
  session.command("cloud-copy <ref>").description("what is kept in the cloud for a chat synced from your own computer: its working folder and native session").option("--json", "print the raw answer").action(
6519
6680
  run(async (ref, opts) => {
6520
6681
  const id = await resolveSessionRef(ref);
@@ -6548,7 +6709,7 @@ sessionWorkspace.command("cat <ref> <path>").description("print a file (up to 1
6548
6709
  run(async (ref, path, opts) => {
6549
6710
  const bytes = await readFile(await resolveSessionRef(ref), path);
6550
6711
  if (opts.out) {
6551
- writeFileSync10(opts.out, bytes);
6712
+ writeFileSync11(opts.out, bytes);
6552
6713
  console.error(`saved ${bytes.length} bytes to ${opts.out}`);
6553
6714
  } else process.stdout.write(bytes);
6554
6715
  })
@@ -6565,7 +6726,7 @@ sessionWorkspace.command("patch <ref> [repo]").description("the work in a reposi
6565
6726
  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)})`);
6566
6727
  if (!patch.length) console.error("nothing changed");
6567
6728
  else if (opts.out) {
6568
- writeFileSync10(opts.out, patch);
6729
+ writeFileSync11(opts.out, patch);
6569
6730
  console.error(`wrote ${opts.out} \u2014 apply with: git apply ${opts.out}`);
6570
6731
  } else process.stdout.write(patch);
6571
6732
  })
@@ -6799,7 +6960,7 @@ async function launchFromFile(path, spec, opts) {
6799
6960
  program.command("launch").description("scaffold ./agent.toml if absent, create the agent and its first session (idle until the first message), print its address").option("-f, --file <path>", "agent file", "agent.toml").option("--type <type>", "override the file's harness: hermes | claude_code | codex | openclaw | pi | dsh | kimi_code | opencode").option("--llm <llm>", "override the file's model (must suit the harness)").option("--start", "boot the first session now instead of on the first message").action(
6800
6961
  run(async (opts) => {
6801
6962
  const path = resolve9(opts.file);
6802
- if (!existsSync13(path)) {
6963
+ if (!existsSync14(path)) {
6803
6964
  const name = basename9(process.cwd()).replace(/[^a-zA-Z0-9 _-]/g, "") || "my-agent";
6804
6965
  scaffoldAgentFile(path, name);
6805
6966
  console.log(`Scaffolded ${opts.file} \u2014 edit it anytime; re-apply with \`sky deploy\`.`);
@@ -7070,14 +7231,14 @@ task.command("get <task> <path>").description("read one task file; prints it, or
7070
7231
  run(async (taskId, path, opts) => {
7071
7232
  const bytes = await readTaskFile(taskId, path);
7072
7233
  if (opts.out) {
7073
- writeFileSync10(opts.out, bytes);
7234
+ writeFileSync11(opts.out, bytes);
7074
7235
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
7075
7236
  } else process.stdout.write(bytes);
7076
7237
  })
7077
7238
  );
7078
7239
  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(
7079
7240
  run(async (taskId, path, local) => {
7080
- const { file, conflict } = await writeTaskFile(taskId, path, readFileSync20(local), mediaTypeFor(local));
7241
+ const { file, conflict } = await writeTaskFile(taskId, path, readFileSync21(local), mediaTypeFor(local));
7081
7242
  console.log(`${renderTaskFile(file)}${conflict ? " (replaced a version you had not seen)" : ""}`);
7082
7243
  })
7083
7244
  );
@@ -7315,7 +7476,7 @@ library.command("list").description("your Library, newest first").option("--sear
7315
7476
  );
7316
7477
  library.command("upload <path>").description("save a file from this computer to your Library").option("--workspace <key>", "place it in this workspace").action(
7317
7478
  run(async (path, opts) => {
7318
- const bytes = readFileSync20(path);
7479
+ const bytes = readFileSync21(path);
7319
7480
  const { artifact: artifact2 } = await uploadToLibrary({ bytes, name: basename9(path), mediaType: "application/octet-stream" }, `sky-upload-${crypto.randomUUID()}`, opts.workspace);
7320
7481
  console.log(renderLibraryArtifact(artifact2));
7321
7482
  })
@@ -7346,7 +7507,7 @@ library.command("place <id> <workspace>").description('place your artifact in a
7346
7507
  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(
7347
7508
  run(async (id, out, opts) => {
7348
7509
  const { bytes } = await downloadLibraryArtifact(id, opts.version ? Number(opts.version) : void 0);
7349
- writeFileSync10(out, bytes);
7510
+ writeFileSync11(out, bytes);
7350
7511
  console.log(`wrote ${bytes.length} bytes to ${out}`);
7351
7512
  })
7352
7513
  );
@@ -7389,7 +7550,7 @@ artifact.command("get <id> <path>").description("read one file of an artifact; p
7389
7550
  run(async (id, path, opts) => {
7390
7551
  const bytes = await readArtifactFile(id, path);
7391
7552
  if (opts.out) {
7392
- writeFileSync10(opts.out, bytes);
7553
+ writeFileSync11(opts.out, bytes);
7393
7554
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
7394
7555
  } else process.stdout.write(bytes);
7395
7556
  })
@@ -7427,14 +7588,14 @@ designSystem.command("import <task> <folder>").description("import a local desig
7427
7588
  );
7428
7589
  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(
7429
7590
  run(async (id, file, opts) => {
7430
- const tokens = JSON.parse(readFileSync20(resolve9(file), "utf8"));
7591
+ const tokens = JSON.parse(readFileSync21(resolve9(file), "utf8"));
7431
7592
  console.log(renderArtifact(await saveDesignTokens(id, opts.base, tokens, opts.note)));
7432
7593
  })
7433
7594
  );
7434
7595
  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(
7435
7596
  run(async (id, path, file, opts) => {
7436
7597
  if (file === void 0 === (opts.restore === void 0)) throw Error("Give a local [file] to save, or --restore <version>.");
7437
- const change = opts.restore === void 0 ? { content: readFileSync20(resolve9(file), "utf8") } : { restore_version: opts.restore };
7598
+ const change = opts.restore === void 0 ? { content: readFileSync21(resolve9(file), "utf8") } : { restore_version: opts.restore };
7438
7599
  console.log(renderArtifact(await saveDesignSystemFile(id, path, opts.base, change, opts.note)));
7439
7600
  })
7440
7601
  );
@@ -7747,7 +7908,7 @@ usageOptions(
7747
7908
  run(async (opts) => {
7748
7909
  const { bytes } = await apiBytes("GET", `/billing/usage/export${usageQuery(opts)}`);
7749
7910
  if (opts.out) {
7750
- writeFileSync10(opts.out, bytes);
7911
+ writeFileSync11(opts.out, bytes);
7751
7912
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
7752
7913
  } else {
7753
7914
  process.stdout.write(bytes);
@@ -8103,6 +8264,16 @@ vendor.command("usage <id>").description("the agents and tasks that used this ve
8103
8264
  for (const t of tasks) console.log(` task ${t.session_id} ${t.title ?? "(untitled)"} ${t.last_used_at.slice(0, 10)}`);
8104
8265
  })
8105
8266
  );
8267
+ program.command("capabilities").description("everything your agents can use here: connected apps, tools, plugins, MCP servers, secrets, browser logins, what your Macs lend and your plans \u2014 where each works, who shared it, its status and its cost").option("--attention", "only what needs you: a sign-in or a permission").option("--json", "print as JSON").action(
8268
+ run(async (opts) => {
8269
+ const overview = await listCapabilities();
8270
+ if (opts.json) {
8271
+ console.log(JSON.stringify(overview, null, 2));
8272
+ return;
8273
+ }
8274
+ console.log(renderCapabilities(overview, { attention: opts.attention }));
8275
+ })
8276
+ );
8106
8277
  var mac = program.command("mac").description("your Macs: what each lends to agents now, and asking one for a folder, a browser window, its screen or its apps and files");
8107
8278
  mac.command("list").description("your Macs: online or not, what each can lend, and the folders, browser windows and screens lent now").option("--json", "print as JSON").action(
8108
8279
  run(async (opts) => {
@@ -8359,7 +8530,7 @@ notes.command("read <storeId> <noteId>").description("print one note").action(
8359
8530
  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(
8360
8531
  run(async (storeId, file, opts) => {
8361
8532
  if (!opts.path === !opts.note) throw new Error("pass exactly one of --path (new note) or --note (update)");
8362
- const content = readFileSync20(file, "utf8");
8533
+ const content = readFileSync21(file, "utf8");
8363
8534
  const target = `/memory_stores/${encodeURIComponent(storeId)}/memories${opts.note ? `/${encodeURIComponent(opts.note)}` : ""}`;
8364
8535
  const { memory: memory2 } = await api("POST", target, { content, ...opts.path ? { path: opts.path } : {} });
8365
8536
  console.log(`Saved ${memory2.path} (${memory2.id})`);
@@ -8459,7 +8630,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
8459
8630
  }));
8460
8631
  var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
8461
8632
  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) => {
8462
- const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-6KAXVDDM.js");
8633
+ const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-5SW4YMCC.js");
8463
8634
  if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
8464
8635
  const scopes = parseContentScopes(opts.capture);
8465
8636
  const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
@@ -8494,7 +8665,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
8494
8665
  }));
8495
8666
  traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
8496
8667
  try {
8497
- const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-6KAXVDDM.js");
8668
+ const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-5SW4YMCC.js");
8498
8669
  const chunks = [];
8499
8670
  for await (const chunk of process.stdin) chunks.push(chunk);
8500
8671
  const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
@@ -8507,14 +8678,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
8507
8678
  }
8508
8679
  });
8509
8680
  traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
8510
- const { readState, flush, grantSender } = await import("./trace-6KAXVDDM.js");
8681
+ const { readState, flush, grantSender } = await import("./trace-5SW4YMCC.js");
8511
8682
  const state = readState();
8512
8683
  if (!state) throw new Error("no trace is running here");
8513
8684
  const outcome = await flush(grantSender(state), { attempts: 4 });
8514
8685
  console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
8515
8686
  }));
8516
8687
  traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
8517
- const { readState, spoolStatus } = await import("./trace-6KAXVDDM.js");
8688
+ const { readState, spoolStatus } = await import("./trace-5SW4YMCC.js");
8518
8689
  const state = readState();
8519
8690
  if (!state) {
8520
8691
  console.log("No trace is running here.");
@@ -8524,7 +8695,7 @@ traceCmd.command("status").description("the running trace and its spool").action
8524
8695
  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`);
8525
8696
  }));
8526
8697
  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) => {
8527
- const { readState } = await import("./trace-6KAXVDDM.js");
8698
+ const { readState } = await import("./trace-5SW4YMCC.js");
8528
8699
  const ref = id ?? readState()?.trace_id;
8529
8700
  if (!ref) throw new Error("name a trace, or start one here");
8530
8701
  const bundle = await api("GET", `/traces/${ref}`);
@@ -8551,7 +8722,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
8551
8722
  for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
8552
8723
  }));
8553
8724
  traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
8554
- const { readState, record, flush, grantSender, clearState } = await import("./trace-6KAXVDDM.js");
8725
+ const { readState, record, flush, grantSender, clearState } = await import("./trace-5SW4YMCC.js");
8555
8726
  const state = readState();
8556
8727
  if (!state) throw new Error("no trace is running here");
8557
8728
  if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
@@ -8561,7 +8732,7 @@ traceCmd.command("stop").description("end the root span, send what is left, and
8561
8732
  console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
8562
8733
  }));
8563
8734
  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) => {
8564
- const lib = await import("./trace-library-C7ZM4BA2.js");
8735
+ const lib = await import("./trace-library-RKZNJ5O5.js");
8565
8736
  if (opts.hook) {
8566
8737
  try {
8567
8738
  let raw = payload ?? "";
@@ -8621,9 +8792,9 @@ traceCmd.command("sync [payload]").description("upload this machine's agent sess
8621
8792
  }
8622
8793
  if (opts.installSchedule) {
8623
8794
  const { join: join20 } = await import("path");
8624
- const { homedir: homedir10 } = await import("os");
8795
+ const { homedir: homedir11 } = await import("os");
8625
8796
  const { execFileSync } = await import("child_process");
8626
- const log = join20(homedir10(), ".config", "sky", "trace-sync.log");
8797
+ const log = join20(homedir11(), ".config", "sky", "trace-sync.log");
8627
8798
  const plist = lib.installLaunchd([process.execPath, process.argv[1], "trace", "sync", "--quiet"], log);
8628
8799
  try {
8629
8800
  execFileSync("launchctl", ["unload", plist], { stdio: "ignore" });
@@ -8633,11 +8804,11 @@ traceCmd.command("sync [payload]").description("upload this machine's agent sess
8633
8804
  console.log(`Sweeping every 15 minutes (${plist}); a full re-read runs weekly. Log: ${log}`);
8634
8805
  }
8635
8806
  if (opts.status) {
8636
- const { readFileSync: readFileSync21 } = await import("fs");
8807
+ const { readFileSync: readFileSync22 } = await import("fs");
8637
8808
  const { join: join20 } = await import("path");
8638
8809
  let state = { sessions: {} };
8639
8810
  try {
8640
- state = JSON.parse(readFileSync21(join20(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
8811
+ state = JSON.parse(readFileSync22(join20(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
8641
8812
  } catch {
8642
8813
  }
8643
8814
  const counts = /* @__PURE__ */ new Map();
@@ -8676,7 +8847,7 @@ traceCmd.command("search <query...>").description("search every session in a wor
8676
8847
  console.log(opts.json ? JSON.stringify(page, null, 2) : renderContextPage(page));
8677
8848
  }));
8678
8849
  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) => {
8679
- const { libraryRequest } = await import("./trace-library-C7ZM4BA2.js");
8850
+ const { libraryRequest } = await import("./trace-library-RKZNJ5O5.js");
8680
8851
  const workspace2 = opts.workspace ?? currentUniverse();
8681
8852
  if (!workspace2) throw new Error("name a workspace with --workspace");
8682
8853
  const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);