@agentsky/sky 2.20.1 → 2.21.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.
Files changed (51) hide show
  1. package/dist/{chunk-ICTCB4VT.js → chunk-6JMFB3CV.js} +1 -1
  2. package/dist/{chunk-NAD26CDY.js → chunk-GHTAIKQ6.js} +80 -30
  3. package/dist/{chunk-S6A5V7XR.js → chunk-ZZ6UF7QA.js} +4 -3
  4. package/dist/index.js +152 -55
  5. package/dist/{src-KP6YIFNP.js → src-QBXMNV2V.js} +28 -6
  6. package/dist/{trace-SJHQ66JA.js → trace-NMBMU4GS.js} +2 -2
  7. package/dist/{trace-library-IWF7BVNB.js → trace-library-OWYB75AR.js} +97 -11
  8. package/package.json +6 -11
  9. package/vendor/trace-collect/SOURCE.json +6 -0
  10. package/vendor/trace-collect/collect.mjs +75 -0
  11. package/vendor/trace-collect/identity.d.ts +8 -0
  12. package/vendor/trace-collect/identity.mjs +23 -0
  13. package/vendor/trace-collect/muse.mjs +87 -0
  14. package/vendor/trace-collect/normalize.d.ts +6 -0
  15. package/vendor/trace-collect/normalize.mjs +312 -0
  16. package/vendor/trace-collect/scrub.d.ts +2 -0
  17. package/vendor/trace-collect/scrub.mjs +186 -0
  18. package/vendor/trace-collect/sinks/agentsky.mjs +156 -0
  19. package/vendor/trace-collect/sources/_cline-family.mjs +182 -0
  20. package/vendor/trace-collect/sources/_project-root.mjs +40 -0
  21. package/vendor/trace-collect/sources/amp.mjs +18 -0
  22. package/vendor/trace-collect/sources/chatgpt.mjs +203 -0
  23. package/vendor/trace-collect/sources/claude-ai.mjs +94 -0
  24. package/vendor/trace-collect/sources/claude-code.mjs +4 -0
  25. package/vendor/trace-collect/sources/claude-desktop.mjs +87 -0
  26. package/vendor/trace-collect/sources/cline.mjs +14 -0
  27. package/vendor/trace-collect/sources/codex.mjs +4 -0
  28. package/vendor/trace-collect/sources/continue.mjs +117 -0
  29. package/vendor/trace-collect/sources/copilot-chat.mjs +145 -0
  30. package/vendor/trace-collect/sources/cursor-chat.mjs +274 -0
  31. package/vendor/trace-collect/sources/cursor.mjs +4 -0
  32. package/vendor/trace-collect/sources/deepseek.mjs +172 -0
  33. package/vendor/trace-collect/sources/dsh.mjs +145 -0
  34. package/vendor/trace-collect/sources/gemini-cli.mjs +113 -0
  35. package/vendor/trace-collect/sources/gemini.mjs +150 -0
  36. package/vendor/trace-collect/sources/goose.mjs +93 -0
  37. package/vendor/trace-collect/sources/grok-cli.mjs +110 -0
  38. package/vendor/trace-collect/sources/grok.mjs +83 -0
  39. package/vendor/trace-collect/sources/hermes.mjs +4 -0
  40. package/vendor/trace-collect/sources/index.mjs +119 -0
  41. package/vendor/trace-collect/sources/jan.mjs +134 -0
  42. package/vendor/trace-collect/sources/kilo-code.mjs +14 -0
  43. package/vendor/trace-collect/sources/kiro.mjs +77 -0
  44. package/vendor/trace-collect/sources/lm-studio.mjs +84 -0
  45. package/vendor/trace-collect/sources/muse.mjs +11 -0
  46. package/vendor/trace-collect/sources/opencode.mjs +109 -0
  47. package/vendor/trace-collect/sources/qwen-code.mjs +95 -0
  48. package/vendor/trace-collect/sources/roo-code.mjs +14 -0
  49. package/vendor/trace-collect/sources/zed.mjs +70 -0
  50. package/dist/products.d.ts +0 -652
  51. package/dist/products.js +0 -208
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  resolveSessionRef,
10
10
  streamEvents,
11
11
  uploadFile
12
- } from "./chunk-S6A5V7XR.js";
12
+ } from "./chunk-ZZ6UF7QA.js";
13
13
  import {
14
14
  CLI_VERSION,
15
15
  USER_AGENT,
@@ -20,7 +20,7 @@ import {
20
20
  currentUniverse,
21
21
  loadConfig,
22
22
  saveConfig
23
- } from "./chunk-ICTCB4VT.js";
23
+ } from "./chunk-6JMFB3CV.js";
24
24
  import {
25
25
  AGENT_TYPES,
26
26
  MODEL_SUBSCRIPTION_PLAN_PHRASE,
@@ -42,11 +42,11 @@ import {
42
42
  skillRefSchema,
43
43
  splitMcpServers,
44
44
  supersededBy
45
- } from "./chunk-NAD26CDY.js";
45
+ } from "./chunk-GHTAIKQ6.js";
46
46
  import "./chunk-MLKGABMK.js";
47
47
 
48
48
  // src/index.ts
49
- import { existsSync as existsSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
49
+ import { existsSync as existsSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "fs";
50
50
  import { basename as basename8, resolve as resolve9 } from "path";
51
51
  import { createInterface as createInterface6 } from "readline";
52
52
  import { Command } from "commander";
@@ -2279,6 +2279,12 @@ async function bind(connectionId, opts) {
2279
2279
  async function send(threadId, text) {
2280
2280
  await api("POST", `/channels/threads/${encodeURIComponent(threadId)}/messages`, { parts: [{ type: "markdown", text }] });
2281
2281
  }
2282
+ async function history(threadId, opts) {
2283
+ const query = new URLSearchParams();
2284
+ if (opts.limit) query.set("limit", opts.limit);
2285
+ if (opts.cursor) query.set("cursor", opts.cursor);
2286
+ return api("GET", `/channels/threads/${encodeURIComponent(threadId)}/messages?${query}`);
2287
+ }
2282
2288
 
2283
2289
  // src/connectors.ts
2284
2290
  import { createServer as createServer2 } from "http";
@@ -2705,7 +2711,7 @@ function latestTurn(events) {
2705
2711
  }
2706
2712
  return reading;
2707
2713
  }
2708
- async function history(sessionId) {
2714
+ async function history2(sessionId) {
2709
2715
  const events = [];
2710
2716
  let cursor = null;
2711
2717
  for (; ; ) {
@@ -2724,18 +2730,19 @@ async function history(sessionId) {
2724
2730
  async function readTurn(sessionId, opts = {}) {
2725
2731
  const deadline = Date.now() + (opts.timeoutSeconds ?? 600) * 1e3;
2726
2732
  for (; ; ) {
2727
- const reading = latestTurn(await history(sessionId));
2733
+ const reading = latestTurn(await history2(sessionId));
2728
2734
  if (reading.finished || !opts.wait || Date.now() >= deadline) return reading;
2729
2735
  await new Promise((resolve10) => setTimeout(resolve10, opts.intervalMs ?? 3e3));
2730
2736
  }
2731
2737
  }
2732
2738
 
2733
2739
  // src/setup.ts
2734
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
2740
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
2735
2741
  import { dirname as dirname6, join as join13 } from "path";
2736
2742
  import { createInterface as createInterface3 } from "readline";
2737
2743
 
2738
2744
  // src/mcp-register.ts
2745
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
2739
2746
  import { spawnSync as spawnSync4 } from "child_process";
2740
2747
 
2741
2748
  // src/skill.ts
@@ -3268,6 +3275,9 @@ function redact(text, token) {
3268
3275
  return text.split(token).join(`${token.slice(0, 10)}\u2026`);
3269
3276
  }
3270
3277
  function registerMcpServer(agent2, opts, runner = systemCommandRunner()) {
3278
+ if (agent2.id === "cursor") {
3279
+ return registerCursorMcpServer(agent2, opts);
3280
+ }
3271
3281
  const commands = mcpCommands(agent2.id, opts);
3272
3282
  if (!commands) return { agent: agent2.id, outcome: "unsupported" };
3273
3283
  if (!runner.has(commands.command)) return { agent: agent2.id, outcome: "no_command", detail: `${commands.command} is not on PATH` };
@@ -3277,10 +3287,40 @@ function registerMcpServer(agent2, opts, runner = systemCommandRunner()) {
3277
3287
  if (added.status !== 0) return { agent: agent2.id, outcome: "failed", detail: redact(added.stderr.trim() || `exit ${added.status}`, opts.token) };
3278
3288
  return agent2.id === "codex" ? { agent: agent2.id, outcome: "registered", detail: `set ${CODEX_TOKEN_ENV} to an AgentSky API token in the shell that runs codex` } : { agent: agent2.id, outcome: "registered" };
3279
3289
  }
3290
+ function registerCursorMcpServer(agent2, opts) {
3291
+ const configPath2 = `${agent2.root}/mcp.json`;
3292
+ const entry2 = {
3293
+ url: opts.mcpUrl,
3294
+ headers: { Authorization: `Bearer ${opts.token}` }
3295
+ };
3296
+ if (opts.dryRun) {
3297
+ const preview = JSON.stringify({ agentsky: { url: opts.mcpUrl, headers: { Authorization: `Bearer ${opts.token.slice(0, 10)}\u2026` } } }, null, 2);
3298
+ return { agent: agent2.id, outcome: "planned", detail: `would write to ${configPath2}: ${preview}` };
3299
+ }
3300
+ let existing = { mcpServers: {} };
3301
+ try {
3302
+ const raw = readFileSync10(configPath2, "utf8");
3303
+ const parsed = JSON.parse(raw);
3304
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3305
+ existing = parsed;
3306
+ }
3307
+ } catch {
3308
+ }
3309
+ const updated = {
3310
+ ...existing,
3311
+ mcpServers: { ...existing.mcpServers ?? {}, [MCP_SERVER_NAME]: entry2 }
3312
+ };
3313
+ try {
3314
+ writeFileSync5(configPath2, JSON.stringify(updated, null, 2) + "\n", "utf8");
3315
+ } catch (err) {
3316
+ return { agent: agent2.id, outcome: "failed", detail: String(err) };
3317
+ }
3318
+ return { agent: agent2.id, outcome: "registered" };
3319
+ }
3280
3320
 
3281
3321
  // src/setup-local.ts
3282
3322
  import { isUtf8 as isUtf83 } from "buffer";
3283
- import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync10, statSync as statSync7 } from "fs";
3323
+ import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
3284
3324
  import { homedir as homedir6 } from "os";
3285
3325
  import { dirname as dirname5, isAbsolute as isAbsolute2, join as join11, resolve as resolve6 } from "path";
3286
3326
  import { parse as parseToml3 } from "smol-toml";
@@ -3311,7 +3351,7 @@ function skillFiles2(root, prefix) {
3311
3351
  if (entry2.isDirectory()) {
3312
3352
  if (!SKIPPED_DIRS.has(entry2.name)) files2.push(...skillFiles2(path, `${prefix}/${entry2.name}`));
3313
3353
  } else if (entry2.isFile() && !sensitive(entry2.name) && statSync7(path).size <= MAX_SKILL_FILE_BYTES) {
3314
- const bytes = redacted(readFileSync10(path));
3354
+ const bytes = redacted(readFileSync11(path));
3315
3355
  if (bytes) files2.push({ path: `${prefix}/${entry2.name}`, bytes });
3316
3356
  }
3317
3357
  }
@@ -3333,7 +3373,7 @@ function readLocalSkills(agents) {
3333
3373
  }
3334
3374
  }
3335
3375
  if (!isDir2 || !existsSync7(join11(dir, "SKILL.md")) || isInstalledSkill(dir)) continue;
3336
- const name = frontmatterName(readFileSync10(join11(dir, "SKILL.md"), "utf8"));
3376
+ const name = frontmatterName(readFileSync11(join11(dir, "SKILL.md"), "utf8"));
3337
3377
  if (!name) {
3338
3378
  ignored.push({ agent: agent2.id, dir, reason: "SKILL.md has no name" });
3339
3379
  continue;
@@ -3365,7 +3405,7 @@ function inlineImports(content, from, home, depth, seen) {
3365
3405
  if (seen.includes(path)) return "";
3366
3406
  let imported;
3367
3407
  try {
3368
- imported = readFileSync10(path, "utf8");
3408
+ imported = readFileSync11(path, "utf8");
3369
3409
  } catch {
3370
3410
  return line;
3371
3411
  }
@@ -3381,7 +3421,7 @@ function readGlobalInstructions(agents, home = homedir6()) {
3381
3421
  const path = join11(agent2.root, file);
3382
3422
  let raw;
3383
3423
  try {
3384
- raw = readFileSync10(path, "utf8");
3424
+ raw = readFileSync11(path, "utf8");
3385
3425
  } catch {
3386
3426
  continue;
3387
3427
  }
@@ -3400,7 +3440,7 @@ ${item.content.trim()}`).join("\n\n");
3400
3440
  }
3401
3441
  function readJson3(path) {
3402
3442
  try {
3403
- return JSON.parse(readFileSync10(path, "utf8"));
3443
+ return JSON.parse(readFileSync11(path, "utf8"));
3404
3444
  } catch {
3405
3445
  return void 0;
3406
3446
  }
@@ -3417,7 +3457,7 @@ function serversOf(agent2, home) {
3417
3457
  if (agent2.id === "claude_code") return readJson3(join11(home, ".claude.json"))?.mcpServers ?? {};
3418
3458
  if (agent2.id === "cursor") return readJson3(join11(agent2.root, "mcp.json"))?.mcpServers ?? {};
3419
3459
  try {
3420
- return parseToml3(readFileSync10(join11(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
3460
+ return parseToml3(readFileSync11(join11(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
3421
3461
  } catch {
3422
3462
  return {};
3423
3463
  }
@@ -3438,7 +3478,7 @@ function findLocalSecrets(agents, home = homedir6()) {
3438
3478
 
3439
3479
  // src/subscriptions.ts
3440
3480
  import { spawn as spawn3 } from "child_process";
3441
- import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
3481
+ import { existsSync as existsSync8, readFileSync as readFileSync12 } from "fs";
3442
3482
  import { homedir as homedir7 } from "os";
3443
3483
  import { join as join12 } from "path";
3444
3484
  import { createInterface as createInterface2 } from "readline";
@@ -3540,7 +3580,7 @@ function codexSignIn(env = process.env, home = homedir7()) {
3540
3580
  if (!existsSync8(path)) {
3541
3581
  throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
3542
3582
  }
3543
- const raw = readFileSync11(path, "utf8");
3583
+ const raw = readFileSync12(path, "utf8");
3544
3584
  try {
3545
3585
  const parsed = JSON.parse(raw);
3546
3586
  return { path, raw, account: parsed.tokens?.account_id };
@@ -3553,7 +3593,7 @@ function cursorSignIn(env = process.env, home = homedir7()) {
3553
3593
  if (!existsSync8(path)) {
3554
3594
  throw new ApiError(404, "no_cursor_auth", `no ${path} \u2014 run \`cursor-agent login\` first`);
3555
3595
  }
3556
- const raw = readFileSync11(path, "utf8");
3596
+ const raw = readFileSync12(path, "utf8");
3557
3597
  try {
3558
3598
  const parsed = JSON.parse(raw);
3559
3599
  if (typeof parsed.accessToken !== "string" || typeof parsed.refreshToken !== "string") throw new Error("shape");
@@ -3716,7 +3756,7 @@ function reportPath() {
3716
3756
  }
3717
3757
  function loadReport() {
3718
3758
  try {
3719
- const saved = JSON.parse(readFileSync12(reportPath(), "utf8"));
3759
+ const saved = JSON.parse(readFileSync13(reportPath(), "utf8"));
3720
3760
  return { agents: saved.agents ?? [], plans: saved.plans ?? [], ...saved.secrets ? { secrets: saved.secrets } : {} };
3721
3761
  } catch {
3722
3762
  return { agents: [], plans: [] };
@@ -3730,7 +3770,7 @@ function mergeReport(base, next) {
3730
3770
  }
3731
3771
  function saveReport(report) {
3732
3772
  mkdirSync3(dirname6(reportPath()), { recursive: true });
3733
- writeFileSync5(reportPath(), `${JSON.stringify(report, null, 2)}
3773
+ writeFileSync6(reportPath(), `${JSON.stringify(report, null, 2)}
3734
3774
  `, { mode: 384 });
3735
3775
  }
3736
3776
  function confirm3(question) {
@@ -4079,7 +4119,7 @@ function renderArtifact(artifact2) {
4079
4119
  }
4080
4120
 
4081
4121
  // src/skills-store.ts
4082
- import { readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
4122
+ import { readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync8 } from "fs";
4083
4123
  import { basename as basename7, join as join14, relative as relative4, resolve as resolve7 } from "path";
4084
4124
  function skillBundle(dir) {
4085
4125
  const root = resolve7(dir);
@@ -4089,7 +4129,7 @@ function skillBundle(dir) {
4089
4129
  for (const name of readdirSync7(path).sort()) {
4090
4130
  const full = join14(path, name);
4091
4131
  if (statSync8(full).isDirectory()) walk(full);
4092
- else files2.push({ path: `${top}/${relative4(root, full)}`, bytes: readFileSync13(full) });
4132
+ else files2.push({ path: `${top}/${relative4(root, full)}`, bytes: readFileSync14(full) });
4093
4133
  }
4094
4134
  };
4095
4135
  walk(root);
@@ -4128,7 +4168,7 @@ async function getSkillUsage(since) {
4128
4168
 
4129
4169
  // src/task-export.ts
4130
4170
  import { createHash as createHash6 } from "crypto";
4131
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "fs";
4171
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "fs";
4132
4172
  import { dirname as dirname7, join as join15 } from "path";
4133
4173
  import { stringify as stringifyToml2 } from "smol-toml";
4134
4174
  var TEXT_MAX = 2e4;
@@ -4421,7 +4461,7 @@ async function exportTaskHarbor(taskRef, outDir, opts) {
4421
4461
  for (const [path, content] of files2) {
4422
4462
  const target = join15(outDir, path);
4423
4463
  mkdirSync4(dirname7(target), { recursive: true });
4424
- writeFileSync6(target, content, typeof content === "string" ? { mode: path.endsWith(".sh") || path.endsWith(".py") ? 493 : 420 } : void 0);
4464
+ writeFileSync7(target, content, typeof content === "string" ? { mode: path.endsWith(".sh") || path.endsWith(".py") ? 493 : 420 } : void 0);
4425
4465
  written.push(path);
4426
4466
  }
4427
4467
  return { written, record };
@@ -4696,7 +4736,9 @@ async function listBrowserProfiles() {
4696
4736
  return data;
4697
4737
  }
4698
4738
  async function getBrowserProfile(scope) {
4699
- const { profile } = await api("GET", `/browser_profiles/${encodeURIComponent(scope)}`);
4739
+ const profiles = await listBrowserProfiles();
4740
+ const profile = profiles.find((entry2) => entry2.scope === scope);
4741
+ if (!profile) throw new ApiError(404, "not_found", "browser profile not found");
4700
4742
  return profile;
4701
4743
  }
4702
4744
  async function importBrowserProfileState(scope, state) {
@@ -4706,16 +4748,24 @@ async function listBrowserProfileSites(scope) {
4706
4748
  const profile = await getBrowserProfile(scope);
4707
4749
  return profile.sites;
4708
4750
  }
4751
+ async function browserSiteReference(scope, site) {
4752
+ const sites = await listBrowserProfileSites(scope);
4753
+ const row = sites.find((entry2) => entry2.site === site) ?? sites.find((entry2) => entry2.site_id === site);
4754
+ if (!row) throw new ApiError(404, "not_found", "site not found in this browser profile");
4755
+ return row.site_id ? `${encodeURIComponent(row.site_id)}?by=id` : encodeURIComponent(row.site);
4756
+ }
4709
4757
  async function removeBrowserProfileSite(scope, site) {
4710
- await api("DELETE", `/browser_profiles/${encodeURIComponent(scope)}/sites/${encodeURIComponent(site)}`);
4758
+ await api("DELETE", `/browser_profiles/${encodeURIComponent(scope)}/sites/${await browserSiteReference(scope, site)}`);
4711
4759
  }
4712
4760
  async function moveBrowserProfileSite(scope, site, to) {
4713
- return api("POST", `/browser_profiles/${encodeURIComponent(scope)}/sites/${encodeURIComponent(site)}/move`, { to });
4761
+ const reference = await browserSiteReference(scope, site);
4762
+ const [identifier, query] = reference.split("?");
4763
+ return api("POST", `/browser_profiles/${encodeURIComponent(scope)}/sites/${identifier}/move${query ? `?${query}` : ""}`, { to });
4714
4764
  }
4715
4765
  function renderBrowserProfileSite(site) {
4716
4766
  const who = site.signed_in_by?.email ?? site.signed_in_by?.name ?? "unknown";
4717
4767
  const used = site.last_used_at ? `used ${site.last_used_at.slice(0, 10)}` : "never used";
4718
- return `${site.site.padEnd(40)} ${site.status.padEnd(14)} ${who} ${used}`;
4768
+ return `${site.site.padEnd(40)} ${site.status.padEnd(14)} ${who} ${used}${site.status === "removing" && site.site_id ? ` retry with site ID ${site.site_id}` : ""}`;
4719
4769
  }
4720
4770
  function renderBrowserProfile(profile) {
4721
4771
  const lines = [`scope: ${profile.scope} revision: ${profile.revision} sites: ${profile.sites.length}`];
@@ -4756,7 +4806,7 @@ function renderThreadSummary(t) {
4756
4806
  }
4757
4807
 
4758
4808
  // src/harness.ts
4759
- import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
4809
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
4760
4810
  import { dirname as dirname8, join as join16, resolve as resolve8 } from "path";
4761
4811
  var HARNESS_FILE = "harness.json";
4762
4812
  function harnessFilePath(dir) {
@@ -4768,7 +4818,7 @@ function readHarnessFile(dir) {
4768
4818
  throw new Error(`no ${HARNESS_FILE} found in ${resolve8(dir)} \u2014 run \`sky harness init\` first`);
4769
4819
  }
4770
4820
  try {
4771
- return JSON.parse(readFileSync14(path, "utf8"));
4821
+ return JSON.parse(readFileSync15(path, "utf8"));
4772
4822
  } catch (err) {
4773
4823
  throw new Error(`could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`);
4774
4824
  }
@@ -4799,7 +4849,7 @@ function harnessInit(dir) {
4799
4849
  throw new Error(`${path} already exists \u2014 delete it to re-init`);
4800
4850
  }
4801
4851
  mkdirSync5(dirname8(path), { recursive: true });
4802
- writeFileSync7(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
4852
+ writeFileSync8(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
4803
4853
  `);
4804
4854
  console.log(`Created ${path}`);
4805
4855
  console.log(INIT_COMMENT);
@@ -5258,12 +5308,15 @@ session.command("create <agent>").description("create a session (starts provisio
5258
5308
  }
5259
5309
  )
5260
5310
  );
5261
- session.command("list [agent]").action(
5262
- run(async (agentRef) => {
5263
- const qs = agentRef ? `?agent=${encodeURIComponent(agentRef)}` : "";
5264
- const { sessions } = await api("GET", `/sessions${qs}`);
5311
+ session.command("list [agent]").option("--limit <n>", "how many of the newest sessions to list (1-500)", "100").option("--cursor <cursor>", "continue from the cursor a previous page printed").action(
5312
+ run(async (agentRef, opts = {}) => {
5313
+ const params = new URLSearchParams();
5314
+ if (agentRef) params.set("agent", agentRef);
5315
+ if (opts.limit) params.set("limit", opts.limit);
5316
+ if (opts.cursor) params.set("cursor", opts.cursor);
5317
+ const { sessions, next_cursor } = await api("GET", `/sessions?${params}`);
5265
5318
  if (!sessions.length) {
5266
- console.log("No sessions. `sky session create <agent>` to start one.");
5319
+ console.log(opts.cursor ? "No more sessions." : "No sessions. `sky session create <agent>` to start one.");
5267
5320
  return;
5268
5321
  }
5269
5322
  for (const s of sessions) {
@@ -5271,6 +5324,7 @@ session.command("list [agent]").action(
5271
5324
  `${s.id.padEnd(24)} ${(s.agentId ?? "-").padEnd(20)} ${(s.title ?? "").padEnd(16)} ${s.status}${s.default ? " *" : ""}`
5272
5325
  );
5273
5326
  }
5327
+ if (next_cursor) console.log(` more: sky session list${agentRef ? ` ${agentRef}` : ""} --cursor ${next_cursor}`);
5274
5328
  })
5275
5329
  );
5276
5330
  session.command("show <id>").action(
@@ -5504,7 +5558,7 @@ sessionWorkspace.command("cat <ref> <path>").description("print a file (up to 1
5504
5558
  run(async (ref, path, opts) => {
5505
5559
  const bytes = await readFile(await resolveSessionRef(ref), path);
5506
5560
  if (opts.out) {
5507
- writeFileSync8(opts.out, bytes);
5561
+ writeFileSync9(opts.out, bytes);
5508
5562
  console.error(`saved ${bytes.length} bytes to ${opts.out}`);
5509
5563
  } else process.stdout.write(bytes);
5510
5564
  })
@@ -5521,7 +5575,7 @@ sessionWorkspace.command("patch <ref> [repo]").description("the work in a reposi
5521
5575
  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)})`);
5522
5576
  if (!patch.length) console.error("nothing changed");
5523
5577
  else if (opts.out) {
5524
- writeFileSync8(opts.out, patch);
5578
+ writeFileSync9(opts.out, patch);
5525
5579
  console.error(`wrote ${opts.out} \u2014 apply with: git apply ${opts.out}`);
5526
5580
  } else process.stdout.write(patch);
5527
5581
  })
@@ -6029,14 +6083,14 @@ task.command("get <task> <path>").description("read one task file; prints it, or
6029
6083
  run(async (taskId, path, opts) => {
6030
6084
  const bytes = await readTaskFile(taskId, path);
6031
6085
  if (opts.out) {
6032
- writeFileSync8(opts.out, bytes);
6086
+ writeFileSync9(opts.out, bytes);
6033
6087
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
6034
6088
  } else process.stdout.write(bytes);
6035
6089
  })
6036
6090
  );
6037
6091
  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(
6038
6092
  run(async (taskId, path, local) => {
6039
- const { file, conflict } = await writeTaskFile(taskId, path, readFileSync15(local), mediaTypeFor(local));
6093
+ const { file, conflict } = await writeTaskFile(taskId, path, readFileSync16(local), mediaTypeFor(local));
6040
6094
  console.log(`${renderTaskFile(file)}${conflict ? " (replaced a version you had not seen)" : ""}`);
6041
6095
  })
6042
6096
  );
@@ -6190,7 +6244,7 @@ artifact.command("get <id> <path>").description("read one file of an artifact; p
6190
6244
  run(async (id, path, opts) => {
6191
6245
  const bytes = await readArtifactFile(id, path);
6192
6246
  if (opts.out) {
6193
- writeFileSync8(opts.out, bytes);
6247
+ writeFileSync9(opts.out, bytes);
6194
6248
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
6195
6249
  } else process.stdout.write(bytes);
6196
6250
  })
@@ -6488,7 +6542,7 @@ usageOptions(
6488
6542
  run(async (opts) => {
6489
6543
  const { bytes } = await apiBytes("GET", `/billing/usage/export${usageQuery(opts)}`);
6490
6544
  if (opts.out) {
6491
- writeFileSync8(opts.out, bytes);
6545
+ writeFileSync9(opts.out, bytes);
6492
6546
  console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
6493
6547
  } else {
6494
6548
  process.stdout.write(bytes);
@@ -6562,7 +6616,7 @@ webhook.command("list").action(
6562
6616
  for (const w of webhooks) console.log(webhookLine(w));
6563
6617
  })
6564
6618
  );
6565
- webhook.command("create <url>").description("register an endpoint; its signing secret is printed once").requiredOption("--event <type...>", "event types to deliver, e.g. goal.completed routine_run.failed").action(
6619
+ webhook.command("create <url>").description("register an endpoint; its signing secret is printed once").requiredOption("--event <type...>", "event types to deliver, e.g. goal.completed routine_run.failed connector.connected connector.granted").action(
6566
6620
  run(async (url, opts) => {
6567
6621
  const { webhook: created } = await api("POST", "/webhooks", { url, events: opts.event });
6568
6622
  console.error(webhookLine(created));
@@ -6606,6 +6660,9 @@ channel.command("bind <connectionId>").description("route a connection to a sess
6606
6660
  console.log(`${connectionId} \u2192 ${opts.session ?? opts.webhook}`);
6607
6661
  })
6608
6662
  );
6663
+ channel.command("history <threadId>").description("read one authorized history page; provider history or retained SDK cache, never an agent turn").option("--limit <count>", "messages per page (1..50)", "20").option("--cursor <cursor>", "opaque next_cursor returned for this thread and page size").action(run(async (threadId, opts) => {
6664
+ console.log(JSON.stringify(await history(threadId, opts), null, 2));
6665
+ }));
6609
6666
  channel.command("send <threadId> <text...>").description("post a markdown message into a connected thread").action(
6610
6667
  run(async (threadId, text) => {
6611
6668
  await send(threadId, text.join(" "));
@@ -6691,6 +6748,35 @@ connector.command("unshare <connectionId>").description("stop sharing a connecti
6691
6748
  console.log(`Stopped sharing ${connectionId} with ${slug}`);
6692
6749
  })
6693
6750
  );
6751
+ var grantLine = (g) => `${g.id} \u2192 ${g.workspace.slug} ${g.key ? `key ${g.key.name} (${g.key.id})` : "every key"} since ${g.created_at.slice(0, 10)} ${g.use_count} call${g.use_count === 1 ? "" : "s"}`;
6752
+ connector.command("grant <connectionId>").description("let a workspace's API keys call through one of your connections (POST /connectors/proxy)").option("--key <id>", "only this key of the workspace, instead of every key").option("--universe <slug>", "the workspace (default: the current one)").action(
6753
+ run(async (connectionId, opts) => {
6754
+ const slug = await workspaceSlug(opts.universe);
6755
+ const { grant } = await api("POST", `/connectors/connections/${encodeURIComponent(connectionId)}/grants`, opts.key ? { key_id: opts.key } : {}, { universe: slug });
6756
+ console.log(`Granted ${connectionId} to ${grant.key ? `key ${grant.key.name}` : "every key"} of ${slug}`);
6757
+ })
6758
+ );
6759
+ connector.command("revoke <connectionId>").description("take a grant back; the service loses the connection at once").option("--key <id>", "the grant for this one key, instead of the workspace-wide one").option("--universe <slug>", "the workspace (default: the current one)").action(
6760
+ run(async (connectionId, opts) => {
6761
+ const slug = await workspaceSlug(opts.universe);
6762
+ await api("DELETE", `/connectors/connections/${encodeURIComponent(connectionId)}/grants`, opts.key ? { key_id: opts.key } : {}, { universe: slug });
6763
+ console.log(`Revoked ${connectionId} from ${opts.key ? `key ${opts.key}` : "every key"} of ${slug}`);
6764
+ })
6765
+ );
6766
+ connector.command("grants <connectionId>").description("who may call through one of your connections with a key, and how often they did").action(
6767
+ run(async (connectionId) => {
6768
+ const { grants } = await api("GET", `/connectors/connections/${encodeURIComponent(connectionId)}/grants`);
6769
+ if (!grants.length) console.log("no grants \u2014 `sky connector grant <connectionId> --universe <slug>`");
6770
+ for (const g of grants) console.log(grantLine(g));
6771
+ })
6772
+ );
6773
+ connector.command("granted").description("connections other people let this key call through").action(
6774
+ run(async () => {
6775
+ const { connections } = await api("GET", "/connectors/connections?granted=true");
6776
+ if (!connections.length) console.log("nothing is granted to this key");
6777
+ for (const c of connections) console.log(`${connectionLine2(c)} owner ${c.owner_user_id}${c.grant.key_id ? "" : " (workspace-wide)"}`);
6778
+ })
6779
+ );
6694
6780
  connector.command("shared").description("everything you share with workspaces, and the calls made through each").action(
6695
6781
  run(async () => {
6696
6782
  const { shared } = await api("GET", "/shared-connections");
@@ -7007,7 +7093,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
7007
7093
  }));
7008
7094
  var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
7009
7095
  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) => {
7010
- const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-SJHQ66JA.js");
7096
+ const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-NMBMU4GS.js");
7011
7097
  if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
7012
7098
  const scopes = parseContentScopes(opts.capture);
7013
7099
  const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
@@ -7042,7 +7128,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
7042
7128
  }));
7043
7129
  traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
7044
7130
  try {
7045
- const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-SJHQ66JA.js");
7131
+ const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-NMBMU4GS.js");
7046
7132
  const chunks = [];
7047
7133
  for await (const chunk of process.stdin) chunks.push(chunk);
7048
7134
  const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
@@ -7055,14 +7141,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
7055
7141
  }
7056
7142
  });
7057
7143
  traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
7058
- const { readState, flush, grantSender } = await import("./trace-SJHQ66JA.js");
7144
+ const { readState, flush, grantSender } = await import("./trace-NMBMU4GS.js");
7059
7145
  const state = readState();
7060
7146
  if (!state) throw new Error("no trace is running here");
7061
7147
  const outcome = await flush(grantSender(state), { attempts: 4 });
7062
7148
  console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
7063
7149
  }));
7064
7150
  traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
7065
- const { readState, spoolStatus } = await import("./trace-SJHQ66JA.js");
7151
+ const { readState, spoolStatus } = await import("./trace-NMBMU4GS.js");
7066
7152
  const state = readState();
7067
7153
  if (!state) {
7068
7154
  console.log("No trace is running here.");
@@ -7072,7 +7158,7 @@ traceCmd.command("status").description("the running trace and its spool").action
7072
7158
  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`);
7073
7159
  }));
7074
7160
  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) => {
7075
- const { readState } = await import("./trace-SJHQ66JA.js");
7161
+ const { readState } = await import("./trace-NMBMU4GS.js");
7076
7162
  const ref = id ?? readState()?.trace_id;
7077
7163
  if (!ref) throw new Error("name a trace, or start one here");
7078
7164
  const bundle = await api("GET", `/traces/${ref}`);
@@ -7099,7 +7185,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
7099
7185
  for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
7100
7186
  }));
7101
7187
  traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
7102
- const { readState, record, flush, grantSender, clearState } = await import("./trace-SJHQ66JA.js");
7188
+ const { readState, record, flush, grantSender, clearState } = await import("./trace-NMBMU4GS.js");
7103
7189
  const state = readState();
7104
7190
  if (!state) throw new Error("no trace is running here");
7105
7191
  if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
@@ -7108,8 +7194,8 @@ traceCmd.command("stop").description("end the root span, send what is left, and
7108
7194
  clearState();
7109
7195
  console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
7110
7196
  }));
7111
- traceCmd.command("sync [payload]").description("upload this machine's Claude Code and Codex sessions 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("--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) => {
7112
- const lib = await import("./trace-library-IWF7BVNB.js");
7197
+ 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) => {
7198
+ const lib = await import("./trace-library-OWYB75AR.js");
7113
7199
  if (opts.hook) {
7114
7200
  try {
7115
7201
  let raw = payload ?? "";
@@ -7150,12 +7236,23 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
7150
7236
  };
7151
7237
  lib.saveSyncConfig(next);
7152
7238
  console.log(`Trace sync is ${next.enabled ? "on" : "off"} on this machine. It reads only:`);
7153
- for (const folder of lib.sourceFolders()) console.log(` ${folder}`);
7239
+ for (const folder of await lib.sourceFolders()) console.log(` ${folder}`);
7154
7240
  console.log("and sends each session, redacted here first, to:");
7155
7241
  for (const rule of next.rules) console.log(` folder path contains "${rule.match}" \u2192 ${rule.workspace}`);
7156
7242
  console.log(` anything else \u2192 ${next.fallback ?? "stays on this machine"}`);
7157
7243
  console.log(`A repository's .agentsky.json "workspace" wins over these rules.`);
7158
7244
  }
7245
+ if (opts.agents) {
7246
+ for (const agent2 of await lib.supportedAgents()) {
7247
+ const how = agent2.kind === "export" ? "cloud export: sky trace sync --import <file>" : agent2.found ? "found on this machine" : "not on this machine";
7248
+ console.log(` ${agent2.name.padEnd(46)} ${how}`);
7249
+ }
7250
+ return;
7251
+ }
7252
+ for (const input of opts.import ?? []) {
7253
+ const imported = await lib.importExport(input);
7254
+ console.log(`Added ${imported.sessions} ${imported.agent} session${imported.sessions === 1 ? "" : "s"} from ${input}.`);
7255
+ }
7159
7256
  if (opts.installSchedule) {
7160
7257
  const { join: join17 } = await import("path");
7161
7258
  const { homedir: homedir8 } = await import("os");
@@ -7170,11 +7267,11 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
7170
7267
  console.log(`Sweeping every 15 minutes (${plist}); a full re-read runs weekly. Log: ${log}`);
7171
7268
  }
7172
7269
  if (opts.status) {
7173
- const { readFileSync: readFileSync16 } = await import("fs");
7270
+ const { readFileSync: readFileSync17 } = await import("fs");
7174
7271
  const { join: join17 } = await import("path");
7175
7272
  let state = { sessions: {} };
7176
7273
  try {
7177
- state = JSON.parse(readFileSync16(join17(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
7274
+ state = JSON.parse(readFileSync17(join17(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
7178
7275
  } catch {
7179
7276
  }
7180
7277
  const counts = /* @__PURE__ */ new Map();
@@ -7207,7 +7304,7 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
7207
7304
  })();
7208
7305
  });
7209
7306
  traceCmd.command("search <query...>").description("search every session in a workspace's trace library (literal substring)").option("--workspace <slug>", "the workspace to search (default: the current one)").option("--limit <n>", "hits per page", (v) => Number.parseInt(v, 10), 20).option("--cursor <cursor>", "the next page of an earlier search").option("--json", "print the page as JSON").action(run(async (words, opts) => {
7210
- const { libraryRequest } = await import("./trace-library-IWF7BVNB.js");
7307
+ const { libraryRequest } = await import("./trace-library-OWYB75AR.js");
7211
7308
  const workspace2 = opts.workspace ?? currentUniverse();
7212
7309
  if (!workspace2) throw new Error("name a workspace with --workspace");
7213
7310
  const params = new URLSearchParams({ q: words.join(" "), scope: "traces", limit: String(opts.limit), ...opts.cursor ? { cursor: opts.cursor } : {} });
@@ -7224,7 +7321,7 @@ traceCmd.command("search <query...>").description("search every session in a wor
7224
7321
  if (page.nextCursor) console.log(`More: sky trace search ${JSON.stringify(words.join(" "))} --workspace ${workspace2} --cursor ${page.nextCursor}`);
7225
7322
  }));
7226
7323
  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) => {
7227
- const { libraryRequest } = await import("./trace-library-IWF7BVNB.js");
7324
+ const { libraryRequest } = await import("./trace-library-OWYB75AR.js");
7228
7325
  const workspace2 = opts.workspace ?? currentUniverse();
7229
7326
  if (!workspace2) throw new Error("name a workspace with --workspace");
7230
7327
  const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);