@agentsky/sky 2.17.0 → 2.18.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.
@@ -38,7 +38,7 @@ function currentUniverse() {
38
38
  }
39
39
 
40
40
  // src/version.ts
41
- var CLI_VERSION = "2.17.0";
41
+ var CLI_VERSION = "2.18.0";
42
42
  var USER_AGENT = `sky-cli/${CLI_VERSION} (${process.platform}; node/${process.versions.node})`;
43
43
 
44
44
  export {
@@ -3,7 +3,7 @@ import {
3
3
  apiBase,
4
4
  apiToken,
5
5
  currentUniverse
6
- } from "./chunk-H7SWXCH7.js";
6
+ } from "./chunk-MUHFB3LC.js";
7
7
 
8
8
  // src/api.ts
9
9
  import { createWriteStream, writeFileSync } from "fs";
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  resolveSessionRef,
10
10
  streamEvents,
11
11
  uploadFile
12
- } from "./chunk-FU43NICZ.js";
12
+ } from "./chunk-PL5KNPCX.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-H7SWXCH7.js";
23
+ } from "./chunk-MUHFB3LC.js";
24
24
  import {
25
25
  AGENT_TYPES,
26
26
  MODEL_SUBSCRIPTION_PLAN_PHRASE,
@@ -51,8 +51,8 @@ import { createInterface as createInterface6 } from "readline";
51
51
  import { Command } from "commander";
52
52
 
53
53
  // src/files.ts
54
- import { readFileSync as readFileSync2, statSync as statSync2 } from "fs";
55
- import { basename as basename2, extname } from "path";
54
+ import { readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
55
+ import { basename as basename2, extname, join as join2 } from "path";
56
56
 
57
57
  // src/resumable-upload.ts
58
58
  import { createHash } from "crypto";
@@ -184,6 +184,58 @@ async function uploadLocalFile(path, expiresInSeconds, onProgress = () => {
184
184
  const bytes = readFileSync2(path);
185
185
  return uploadFile(new Uint8Array(bytes), basename2(path), mediaTypeFor(path), expiresInSeconds);
186
186
  }
187
+ var IGNORED_NAMES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db", "desktop.ini"]);
188
+ function filesUnder(paths) {
189
+ const found = [];
190
+ const walk = (path) => {
191
+ const stat = statSync2(path);
192
+ if (stat.isFile()) {
193
+ if (!IGNORED_NAMES.has(basename2(path))) found.push(path);
194
+ return;
195
+ }
196
+ if (!stat.isDirectory()) return;
197
+ for (const name of readdirSync(path).sort()) walk(join2(path, name));
198
+ };
199
+ for (const path of paths) walk(path);
200
+ return found;
201
+ }
202
+ function transient(error) {
203
+ return !(error instanceof ApiError) || error.status === 429 || error.status >= 500;
204
+ }
205
+ async function uploadLocalFiles(paths, {
206
+ concurrency = 4,
207
+ attempts = 4,
208
+ expiresInSeconds,
209
+ onUploaded,
210
+ onFailed,
211
+ wait = (ms) => new Promise((done) => setTimeout(done, ms))
212
+ }) {
213
+ let next = 0;
214
+ let uploaded = 0;
215
+ let failed = 0;
216
+ const worker = async () => {
217
+ while (next < paths.length) {
218
+ const path = paths[next++];
219
+ for (let attempt = 1; ; attempt++) {
220
+ try {
221
+ onUploaded(path, await uploadLocalFile(path, expiresInSeconds));
222
+ uploaded += 1;
223
+ break;
224
+ } catch (error) {
225
+ if (attempt < attempts && transient(error)) {
226
+ await wait(1e3 * 2 ** (attempt - 1));
227
+ continue;
228
+ }
229
+ onFailed(path, error);
230
+ failed += 1;
231
+ break;
232
+ }
233
+ }
234
+ }
235
+ };
236
+ await Promise.all(Array.from({ length: Math.min(concurrency, paths.length) }, worker));
237
+ return { uploaded, failed };
238
+ }
187
239
  function fileBlock(file) {
188
240
  const source = { type: "file", file_id: file.id };
189
241
  return file.mime_type.startsWith("image/") ? { type: "image", source } : { type: "document", source, title: file.filename };
@@ -565,12 +617,12 @@ function renderCatalogAgent(agent2) {
565
617
  import { spawn } from "child_process";
566
618
  import { existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
567
619
  import { homedir } from "os";
568
- import { basename as basename3, join as join2 } from "path";
620
+ import { basename as basename3, join as join3 } from "path";
569
621
  import { createInterface } from "readline";
570
622
  var PROMPT_CAP = 1e5;
571
623
  var HARNESSES = ["claude_code", "codex", "openclaw"];
572
624
  function claudeConfigRoot() {
573
- return process.env.CLAUDE_CONFIG_DIR ?? join2(homedir(), ".claude");
625
+ return process.env.CLAUDE_CONFIG_DIR ?? join3(homedir(), ".claude");
574
626
  }
575
627
  function readIfExists(path) {
576
628
  try {
@@ -590,9 +642,9 @@ function readJson(path) {
590
642
  }
591
643
  function claudeModel(configRoot) {
592
644
  const candidates = [
593
- join2(process.cwd(), ".claude", "settings.local.json"),
594
- join2(process.cwd(), ".claude", "settings.json"),
595
- join2(configRoot, "settings.json")
645
+ join3(process.cwd(), ".claude", "settings.local.json"),
646
+ join3(process.cwd(), ".claude", "settings.json"),
647
+ join3(configRoot, "settings.json")
596
648
  ];
597
649
  for (const path of candidates) {
598
650
  const model = readJson(path)?.model;
@@ -602,11 +654,11 @@ function claudeModel(configRoot) {
602
654
  }
603
655
  function claudeMcpServers() {
604
656
  const merged = {};
605
- const userConfig = readJson(join2(homedir(), ".claude.json"));
657
+ const userConfig = readJson(join3(homedir(), ".claude.json"));
606
658
  Object.assign(merged, userConfig?.mcpServers ?? {});
607
659
  Object.assign(merged, userConfig?.projects?.[process.cwd()]?.mcpServers ?? {});
608
660
  const projectConfig = readJson(
609
- join2(process.cwd(), ".mcp.json")
661
+ join3(process.cwd(), ".mcp.json")
610
662
  );
611
663
  Object.assign(merged, projectConfig?.mcpServers ?? {});
612
664
  return merged;
@@ -623,13 +675,13 @@ function readClaudeCode() {
623
675
  const configRoot = claudeConfigRoot();
624
676
  const parts = [];
625
677
  const sources = [];
626
- const global = readIfExists(join2(configRoot, "CLAUDE.md"));
678
+ const global = readIfExists(join3(configRoot, "CLAUDE.md"));
627
679
  if (global?.trim()) {
628
680
  parts.push({ label: "Global CLAUDE.md", content: global });
629
681
  sources.push("global CLAUDE.md");
630
682
  }
631
683
  for (const name of ["CLAUDE.md", "AGENTS.md"]) {
632
- const project = readIfExists(join2(process.cwd(), name));
684
+ const project = readIfExists(join3(process.cwd(), name));
633
685
  if (project?.trim()) {
634
686
  parts.push({ label: `Project ${name}`, content: project });
635
687
  sources.push(`project ${name}`);
@@ -670,8 +722,8 @@ function detectHarness(explicit) {
670
722
  return explicit;
671
723
  }
672
724
  if (existsSync2(claudeConfigRoot())) return "claude_code";
673
- if (existsSync2(join2(homedir(), ".codex"))) return "codex";
674
- if (existsSync2(join2(homedir(), ".openclaw"))) return "openclaw";
725
+ if (existsSync2(join3(homedir(), ".codex"))) return "codex";
726
+ if (existsSync2(join3(homedir(), ".openclaw"))) return "openclaw";
675
727
  throw new Error(
676
728
  "no local harness found (~/.claude, ~/.codex, ~/.openclaw) \u2014 pass --harness to override"
677
729
  );
@@ -683,7 +735,7 @@ function readLocal(harness2) {
683
735
  );
684
736
  }
685
737
  function linkPath(configRoot) {
686
- return join2(configRoot, "agentsky-link.json");
738
+ return join3(configRoot, "agentsky-link.json");
687
739
  }
688
740
  function readLink(configRoot) {
689
741
  const link = readJson(linkPath(configRoot));
@@ -929,22 +981,22 @@ async function clone(opts) {
929
981
  }
930
982
 
931
983
  // src/import-local.ts
932
- import { closeSync as closeSync3, existsSync as existsSync5, openSync as openSync3, readdirSync as readdirSync3, readFileSync as readFileSync8, readSync as readSync3, statSync as statSync5 } from "fs";
984
+ import { closeSync as closeSync3, existsSync as existsSync5, openSync as openSync3, readdirSync as readdirSync4, readFileSync as readFileSync8, readSync as readSync3, statSync as statSync5 } from "fs";
933
985
  import { homedir as homedir4 } from "os";
934
- import { join as join6 } from "path";
986
+ import { join as join7 } from "path";
935
987
  import { createHash as createHash3 } from "crypto";
936
988
 
937
989
  // src/import-files.ts
938
990
  import { isUtf8 } from "buffer";
939
991
  import { existsSync as existsSync4, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
940
992
  import { homedir as homedir3 } from "os";
941
- import { dirname as dirname4, extname as extname2, isAbsolute, join as join4, relative as relative2, resolve as resolve4, sep as sep2, basename as basename5 } from "path";
993
+ import { dirname as dirname4, extname as extname2, isAbsolute, join as join5, relative as relative2, resolve as resolve4, sep as sep2, basename as basename5 } from "path";
942
994
 
943
995
  // src/import-workspace.ts
944
996
  import { spawnSync } from "child_process";
945
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync5, realpathSync, statSync as statSync3 } from "fs";
997
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, realpathSync, statSync as statSync3 } from "fs";
946
998
  import { homedir as homedir2 } from "os";
947
- import { basename as basename4, dirname as dirname3, join as join3, relative, sep } from "path";
999
+ import { basename as basename4, dirname as dirname3, join as join4, relative, sep } from "path";
948
1000
  import { parse as parseToml2 } from "smol-toml";
949
1001
  var MAX_TREE = 5e3;
950
1002
  var SKILL_LINE = /Base directory for this skill: (\/[^\s"'\\<>]+)/g;
@@ -967,13 +1019,13 @@ var isDir = (path) => {
967
1019
  }
968
1020
  };
969
1021
  function sharedInstructionPaths(home = homedir2()) {
970
- const rules = join3(home, ".agents", "rules");
1022
+ const rules = join4(home, ".agents", "rules");
971
1023
  let ruleFiles = [];
972
1024
  try {
973
- ruleFiles = readdirSync(rules).filter((name) => name.endsWith(".md")).sort().map((name) => join3(rules, name));
1025
+ ruleFiles = readdirSync2(rules).filter((name) => name.endsWith(".md")).sort().map((name) => join4(rules, name));
974
1026
  } catch {
975
1027
  }
976
- return [join3(home, "AGENTS.md"), join3(home, "MEMORY.md"), ...ruleFiles].filter(isFile);
1028
+ return [join4(home, "AGENTS.md"), join4(home, "MEMORY.md"), ...ruleFiles].filter(isFile);
977
1029
  }
978
1030
  function strings(value, out, depth = 0) {
979
1031
  if (depth > 12) return;
@@ -982,30 +1034,30 @@ function strings(value, out, depth = 0) {
982
1034
  else if (value && typeof value === "object") for (const item of Object.values(value)) strings(item, out, depth + 1);
983
1035
  }
984
1036
  function skillRoots(cwd, home) {
985
- const claude = process.env.CLAUDE_CONFIG_DIR ?? join3(home, ".claude");
986
- const codex = process.env.CODEX_HOME ?? join3(home, ".codex");
1037
+ const claude = process.env.CLAUDE_CONFIG_DIR ?? join4(home, ".claude");
1038
+ const codex = process.env.CODEX_HOME ?? join4(home, ".codex");
987
1039
  return [
988
- ...cwd ? [join3(cwd, ".claude", "skills"), join3(cwd, ".agents", "skills")] : [],
989
- join3(home, ".agents", "skills"),
990
- join3(claude, "skills"),
991
- join3(codex, "skills"),
992
- join3(home, ".hermes", "skills")
1040
+ ...cwd ? [join4(cwd, ".claude", "skills"), join4(cwd, ".agents", "skills")] : [],
1041
+ join4(home, ".agents", "skills"),
1042
+ join4(claude, "skills"),
1043
+ join4(codex, "skills"),
1044
+ join4(home, ".hermes", "skills")
993
1045
  ];
994
1046
  }
995
1047
  function pluginSkill(plugin, skill, home) {
996
- const base = join3(process.env.CLAUDE_CONFIG_DIR ?? join3(home, ".claude"), "plugins");
1048
+ const base = join4(process.env.CLAUDE_CONFIG_DIR ?? join4(home, ".claude"), "plugins");
997
1049
  const walk = (dir, depth) => {
998
1050
  if (depth > 7) return null;
999
1051
  let entries;
1000
1052
  try {
1001
- entries = readdirSync(dir, { withFileTypes: true });
1053
+ entries = readdirSync2(dir, { withFileTypes: true });
1002
1054
  } catch {
1003
1055
  return null;
1004
1056
  }
1005
1057
  for (const entry2 of entries) {
1006
1058
  if (!entry2.isDirectory() || entry2.name === "node_modules" || entry2.name === ".git") continue;
1007
- const path = join3(dir, entry2.name);
1008
- if (entry2.name === skill && basename4(dir) === "skills" && path.includes(`${sep}${plugin}${sep}`) && isFile(join3(path, "SKILL.md"))) return path;
1059
+ const path = join4(dir, entry2.name);
1060
+ if (entry2.name === skill && basename4(dir) === "skills" && path.includes(`${sep}${plugin}${sep}`) && isFile(join4(path, "SKILL.md"))) return path;
1009
1061
  const found = walk(path, depth + 1);
1010
1062
  if (found) return found;
1011
1063
  }
@@ -1017,8 +1069,8 @@ function findSkill(name, cwd, home) {
1017
1069
  const [scope, skill] = name.includes(":") ? name.split(":", 2) : [null, name];
1018
1070
  if (scope && skill) return pluginSkill(scope, skill, home);
1019
1071
  for (const root of skillRoots(cwd, home)) {
1020
- const direct = join3(root, name);
1021
- if (isFile(join3(direct, "SKILL.md"))) return realpathSync(direct);
1072
+ const direct = join4(root, name);
1073
+ if (isFile(join4(direct, "SKILL.md"))) return realpathSync(direct);
1022
1074
  }
1023
1075
  return null;
1024
1076
  }
@@ -1026,7 +1078,7 @@ function loadedSkills(records, touched, cwd, home = homedir2()) {
1026
1078
  const dirs = /* @__PURE__ */ new Map();
1027
1079
  const missing = /* @__PURE__ */ new Set();
1028
1080
  const add = (dir, name = basename4(dir)) => {
1029
- if (!isFile(join3(dir, "SKILL.md"))) return false;
1081
+ if (!isFile(join4(dir, "SKILL.md"))) return false;
1030
1082
  const real = realpathSync(dir);
1031
1083
  if (![...dirs.values()].includes(real)) dirs.set(name, real);
1032
1084
  return true;
@@ -1097,16 +1149,16 @@ function mcpServers(harness2, cwd, home = homedir2()) {
1097
1149
  }
1098
1150
  };
1099
1151
  if (harness2 === "claude_code") {
1100
- const config = readJson2(join3(process.env.CLAUDE_CONFIG_DIR ? dirname3(process.env.CLAUDE_CONFIG_DIR) : home, ".claude.json"));
1152
+ const config = readJson2(join4(process.env.CLAUDE_CONFIG_DIR ? dirname3(process.env.CLAUDE_CONFIG_DIR) : home, ".claude.json"));
1101
1153
  const projects = config?.projects && typeof config.projects === "object" ? config.projects : {};
1102
1154
  const root = cwd ? git(cwd, "rev-parse", "--show-toplevel")?.trim() || cwd : "";
1103
1155
  if (cwd) push(projects[cwd]?.mcpServers ?? projects[root]?.mcpServers, "local");
1104
- if (root) push(readJson2(join3(root, ".mcp.json"))?.mcpServers, "project");
1156
+ if (root) push(readJson2(join4(root, ".mcp.json"))?.mcpServers, "project");
1105
1157
  push(config?.mcpServers, "user");
1106
1158
  }
1107
1159
  if (harness2 === "codex") {
1108
1160
  try {
1109
- const config = parseToml2(readFileSync5(join3(process.env.CODEX_HOME ?? join3(home, ".codex"), "config.toml"), "utf8"));
1161
+ const config = parseToml2(readFileSync5(join4(process.env.CODEX_HOME ?? join4(home, ".codex"), "config.toml"), "utf8"));
1110
1162
  push(config.mcp_servers, "user");
1111
1163
  } catch {
1112
1164
  }
@@ -1160,13 +1212,13 @@ function skillFiles(skill) {
1160
1212
  if (depth > 8 || out.length > 400) return;
1161
1213
  let entries;
1162
1214
  try {
1163
- entries = readdirSync(dir, { withFileTypes: true });
1215
+ entries = readdirSync2(dir, { withFileTypes: true });
1164
1216
  } catch {
1165
1217
  return;
1166
1218
  }
1167
1219
  for (const entry2 of entries) {
1168
1220
  if (entry2.name === "node_modules" || entry2.name === ".git" || entry2.name === "__pycache__" || entry2.name === ".venv") continue;
1169
- const path = join3(dir, entry2.name);
1221
+ const path = join4(dir, entry2.name);
1170
1222
  if (entry2.isDirectory()) walk(path, depth + 1);
1171
1223
  else if (entry2.isFile()) out.push({ path, name: `skills/${skill.name}/${relative(skill.dir, path).split(sep).join("/")}` });
1172
1224
  }
@@ -1177,7 +1229,7 @@ function skillFiles(skill) {
1177
1229
  function codexThreadName(sessionId, home = homedir2()) {
1178
1230
  let name = null;
1179
1231
  try {
1180
- for (const line of readFileSync5(join3(process.env.CODEX_HOME ?? join3(home, ".codex"), "session_index.jsonl"), "utf8").split("\n")) {
1232
+ for (const line of readFileSync5(join4(process.env.CODEX_HOME ?? join4(home, ".codex"), "session_index.jsonl"), "utf8").split("\n")) {
1181
1233
  if (!line.includes(sessionId)) continue;
1182
1234
  try {
1183
1235
  const entry2 = JSON.parse(line);
@@ -1297,7 +1349,7 @@ function touchedPaths(records, cwd, home = homedir3()) {
1297
1349
  }
1298
1350
  function gitRoot(dir) {
1299
1351
  for (let d = dir; ; d = dirname4(d)) {
1300
- if (existsSync4(join4(d, ".git"))) return d;
1352
+ if (existsSync4(join5(d, ".git"))) return d;
1301
1353
  if (d === dirname4(d)) return null;
1302
1354
  }
1303
1355
  }
@@ -1306,12 +1358,12 @@ function instructionPaths(cwd, harness2, home = homedir3()) {
1306
1358
  if (cwd && existsSync4(cwd)) {
1307
1359
  const root = gitRoot(cwd) ?? cwd;
1308
1360
  for (let d = resolve4(cwd); ; d = dirname4(d)) {
1309
- for (const name of INSTRUCTION_FILES) out.push(join4(d, name));
1361
+ for (const name of INSTRUCTION_FILES) out.push(join5(d, name));
1310
1362
  if (d === root || d === dirname4(d)) break;
1311
1363
  }
1312
1364
  }
1313
- if (harness2 === "claude_code") out.push(join4(process.env.CLAUDE_CONFIG_DIR ?? join4(home, ".claude"), "CLAUDE.md"));
1314
- if (harness2 === "codex") out.push(join4(process.env.CODEX_HOME ?? join4(home, ".codex"), "AGENTS.md"));
1365
+ if (harness2 === "claude_code") out.push(join5(process.env.CLAUDE_CONFIG_DIR ?? join5(home, ".claude"), "CLAUDE.md"));
1366
+ if (harness2 === "codex") out.push(join5(process.env.CODEX_HOME ?? join5(home, ".codex"), "AGENTS.md"));
1315
1367
  out.push(...sharedInstructionPaths(home));
1316
1368
  return out.filter((path) => {
1317
1369
  try {
@@ -1436,9 +1488,9 @@ function collectSessionFiles(records, opts) {
1436
1488
  // src/import-environment.ts
1437
1489
  import { spawnSync as spawnSync2 } from "child_process";
1438
1490
  import { createHash as createHash2 } from "crypto";
1439
- import { closeSync as closeSync2, createWriteStream, lstatSync, mkdtempSync, openSync as openSync2, readdirSync as readdirSync2, readFileSync as readFileSync7, readSync as readSync2, rmSync as rmSync2 } from "fs";
1491
+ import { closeSync as closeSync2, createWriteStream, lstatSync, mkdtempSync, openSync as openSync2, readdirSync as readdirSync3, readFileSync as readFileSync7, readSync as readSync2, rmSync as rmSync2 } from "fs";
1440
1492
  import { tmpdir } from "os";
1441
- import { join as join5 } from "path";
1493
+ import { join as join6 } from "path";
1442
1494
  import { isUtf8 as isUtf82 } from "buffer";
1443
1495
  import { createGzip } from "zlib";
1444
1496
 
@@ -1617,14 +1669,14 @@ function listFiles(cwd) {
1617
1669
  const walk = (dir, prefix) => {
1618
1670
  let entries;
1619
1671
  try {
1620
- entries = readdirSync2(dir, { withFileTypes: true });
1672
+ entries = readdirSync3(dir, { withFileTypes: true });
1621
1673
  } catch {
1622
1674
  return;
1623
1675
  }
1624
1676
  for (const entry2 of entries) {
1625
1677
  if (SKIPPED.has(entry2.name)) continue;
1626
1678
  const rel = prefix ? `${prefix}/${entry2.name}` : entry2.name;
1627
- if (entry2.isDirectory()) walk(join5(dir, entry2.name), rel);
1679
+ if (entry2.isDirectory()) walk(join6(dir, entry2.name), rel);
1628
1680
  else out.push(rel);
1629
1681
  if (out.length > MAX_ENVIRONMENT_FILES) return;
1630
1682
  }
@@ -1641,8 +1693,8 @@ function textOf(path, size) {
1641
1693
  async function packEnvironment(cwd, resources, platform = IMPORT_PLATFORM) {
1642
1694
  const listed = listFiles(cwd);
1643
1695
  if (listed.length > MAX_ENVIRONMENT_FILES) throw new Error(`The working folder has more than ${MAX_ENVIRONMENT_FILES} files; import it with --no-environment.`);
1644
- const scratch = mkdtempSync(join5(tmpdir(), "sky-environment-"));
1645
- const path = join5(scratch, "environment.tar.gz");
1696
+ const scratch = mkdtempSync(join6(tmpdir(), "sky-environment-"));
1697
+ const path = join6(scratch, "environment.tar.gz");
1646
1698
  const leftOut = [];
1647
1699
  const written = /* @__PURE__ */ new Set();
1648
1700
  const hash = createHash2("sha256");
@@ -1670,7 +1722,7 @@ async function packEnvironment(cwd, resources, platform = IMPORT_PLATFORM) {
1670
1722
  });
1671
1723
  try {
1672
1724
  for (const rel of listed) {
1673
- const full = join5(cwd, ...rel.split("/"));
1725
+ const full = join6(cwd, ...rel.split("/"));
1674
1726
  if (SECRET_FILE2.test(rel)) {
1675
1727
  leftOut.push({ path: rel, reason: "credential file" });
1676
1728
  continue;
@@ -1824,16 +1876,16 @@ function sniffTitle(filePath) {
1824
1876
  }
1825
1877
  }
1826
1878
  function listClaudeCodeSessions(limit) {
1827
- const root = process.env.CLAUDE_CONFIG_DIR ?? join6(homedir4(), ".claude");
1828
- const projectsDir = join6(root, "projects");
1879
+ const root = process.env.CLAUDE_CONFIG_DIR ?? join7(homedir4(), ".claude");
1880
+ const projectsDir = join7(root, "projects");
1829
1881
  if (!existsSync5(projectsDir)) return [];
1830
1882
  const sessions = [];
1831
1883
  try {
1832
- for (const encoded of readdirSync3(projectsDir)) {
1833
- const projectDir = join6(projectsDir, encoded);
1884
+ for (const encoded of readdirSync4(projectsDir)) {
1885
+ const projectDir = join7(projectsDir, encoded);
1834
1886
  let entries;
1835
1887
  try {
1836
- entries = readdirSync3(projectDir);
1888
+ entries = readdirSync4(projectDir);
1837
1889
  } catch {
1838
1890
  continue;
1839
1891
  }
@@ -1841,7 +1893,7 @@ function listClaudeCodeSessions(limit) {
1841
1893
  for (const entry2 of entries) {
1842
1894
  if (!entry2.endsWith(".jsonl")) continue;
1843
1895
  const sessionId = entry2.slice(0, -6);
1844
- const mainFile = join6(projectDir, entry2);
1896
+ const mainFile = join7(projectDir, entry2);
1845
1897
  let stat;
1846
1898
  try {
1847
1899
  stat = statSync5(mainFile);
@@ -1851,12 +1903,12 @@ function listClaudeCodeSessions(limit) {
1851
1903
  if (!stat.isFile()) continue;
1852
1904
  let discoveryError;
1853
1905
  const subagentFiles = [];
1854
- const subagentDir = join6(projectDir, sessionId, "subagents");
1906
+ const subagentDir = join7(projectDir, sessionId, "subagents");
1855
1907
  if (existsSync5(subagentDir)) {
1856
1908
  try {
1857
- const subFiles = readdirSync3(subagentDir).filter((f) => f.endsWith(".jsonl")).sort();
1909
+ const subFiles = readdirSync4(subagentDir).filter((f) => f.endsWith(".jsonl")).sort();
1858
1910
  for (const f of subFiles) {
1859
- subagentFiles.push(join6(subagentDir, f));
1911
+ subagentFiles.push(join7(subagentDir, f));
1860
1912
  }
1861
1913
  } catch {
1862
1914
  discoveryError = "Cannot read all recorded subagent conversations. Fix local file access before importing this session.";
@@ -1878,17 +1930,17 @@ function listClaudeCodeSessions(limit) {
1878
1930
  return sessions.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, limit);
1879
1931
  }
1880
1932
  function listCodexSessions(limit) {
1881
- const sessionsDir = join6(process.env.CODEX_HOME ?? process.env.CODEX_CONFIG_DIR ?? join6(homedir4(), ".codex"), "sessions");
1933
+ const sessionsDir = join7(process.env.CODEX_HOME ?? process.env.CODEX_CONFIG_DIR ?? join7(homedir4(), ".codex"), "sessions");
1882
1934
  const records = [];
1883
1935
  function walk(dir) {
1884
1936
  let entries;
1885
1937
  try {
1886
- entries = readdirSync3(dir, { withFileTypes: true });
1938
+ entries = readdirSync4(dir, { withFileTypes: true });
1887
1939
  } catch {
1888
1940
  return;
1889
1941
  }
1890
1942
  for (const entry2 of entries) {
1891
- const full = join6(dir, entry2.name);
1943
+ const full = join7(dir, entry2.name);
1892
1944
  if (entry2.isDirectory()) {
1893
1945
  walk(full);
1894
1946
  continue;
@@ -2440,8 +2492,8 @@ async function triggerRequest(id, resource, change) {
2440
2492
  // src/session-workspace.ts
2441
2493
  import { spawnSync as spawnSync3 } from "child_process";
2442
2494
  import { createHash as createHash5, randomUUID } from "crypto";
2443
- import { readdirSync as readdirSync4, statSync as statSync6 } from "fs";
2444
- import { basename as basename6, join as join7, relative as relative3, resolve as resolve5 } from "path";
2495
+ import { readdirSync as readdirSync5, statSync as statSync6 } from "fs";
2496
+ import { basename as basename6, join as join8, relative as relative3, resolve as resolve5 } from "path";
2445
2497
  var SINGLE_IMPORT_MAX = 25 * 1024 * 1024;
2446
2498
  var PART_SIZE = 8 * 1024 * 1024;
2447
2499
  var SKIPPED2 = /* @__PURE__ */ new Set([".git", "node_modules"]);
@@ -2475,13 +2527,13 @@ function folderFiles(dir) {
2475
2527
  const git2 = spawnSync3("git", ["-C", dir, "ls-files", "-z", "--cached", "--others", "--exclude-standard"], { encoding: "utf8" });
2476
2528
  const top = spawnSync3("git", ["-C", dir, "rev-parse", "--show-prefix"], { encoding: "utf8" });
2477
2529
  if (git2.status === 0 && top.status === 0) {
2478
- return git2.stdout.split("\0").filter((path) => path && statSync6(join7(dir, path), { throwIfNoEntry: false })?.isFile());
2530
+ return git2.stdout.split("\0").filter((path) => path && statSync6(join8(dir, path), { throwIfNoEntry: false })?.isFile());
2479
2531
  }
2480
2532
  const files2 = [];
2481
2533
  const walk = (at) => {
2482
- for (const entry2 of readdirSync4(at, { withFileTypes: true })) {
2534
+ for (const entry2 of readdirSync5(at, { withFileTypes: true })) {
2483
2535
  if (SKIPPED2.has(entry2.name)) continue;
2484
- const full = join7(at, entry2.name);
2536
+ const full = join8(at, entry2.name);
2485
2537
  if (entry2.isDirectory()) walk(full);
2486
2538
  else if (entry2.isFile()) files2.push(relative3(dir, full));
2487
2539
  }
@@ -2565,15 +2617,15 @@ async function handoff(id, targetAgent, opts = {}) {
2565
2617
  // src/local-agents.ts
2566
2618
  import { existsSync as existsSync6 } from "fs";
2567
2619
  import { homedir as homedir5 } from "os";
2568
- import { join as join8 } from "path";
2620
+ import { join as join9 } from "path";
2569
2621
  function localAgents(env = process.env, home = homedir5()) {
2570
- const claude = env.CLAUDE_CONFIG_DIR || join8(home, ".claude");
2571
- const codex = env.CODEX_HOME || join8(home, ".codex");
2572
- const cursor = join8(home, ".cursor");
2622
+ const claude = env.CLAUDE_CONFIG_DIR || join9(home, ".claude");
2623
+ const codex = env.CODEX_HOME || join9(home, ".codex");
2624
+ const cursor = join9(home, ".cursor");
2573
2625
  return [
2574
- { id: "claude_code", name: "Claude Code", root: claude, skillsDir: join8(claude, "skills") },
2575
- { id: "codex", name: "Codex", root: codex, skillsDir: join8(codex, "skills") },
2576
- { id: "cursor", name: "Cursor", root: cursor, skillsDir: join8(cursor, "skills") }
2626
+ { id: "claude_code", name: "Claude Code", root: claude, skillsDir: join9(claude, "skills") },
2627
+ { id: "codex", name: "Codex", root: codex, skillsDir: join9(codex, "skills") },
2628
+ { id: "cursor", name: "Cursor", root: cursor, skillsDir: join9(cursor, "skills") }
2577
2629
  ];
2578
2630
  }
2579
2631
  function detectLocalAgents(env = process.env, home = homedir5()) {
@@ -2679,7 +2731,7 @@ async function readTurn(sessionId, opts = {}) {
2679
2731
 
2680
2732
  // src/setup.ts
2681
2733
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
2682
- import { dirname as dirname6, join as join12 } from "path";
2734
+ import { dirname as dirname6, join as join13 } from "path";
2683
2735
  import { createInterface as createInterface3 } from "readline";
2684
2736
 
2685
2737
  // src/mcp-register.ts
@@ -2687,7 +2739,7 @@ import { spawnSync as spawnSync4 } from "child_process";
2687
2739
 
2688
2740
  // src/skill.ts
2689
2741
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
2690
- import { join as join9 } from "path";
2742
+ import { join as join10 } from "path";
2691
2743
 
2692
2744
  // src/catalog-file.ts
2693
2745
  var CATALOG_FILE = "catalog.md";
@@ -3128,7 +3180,7 @@ To set a per-repo default, create \`.agentsky.json\` at the git root:
3128
3180
  }
3129
3181
  function installedVersion(dir) {
3130
3182
  try {
3131
- const marker = JSON.parse(readFileSync9(join9(dir, SKILL_MARKER), "utf8"));
3183
+ const marker = JSON.parse(readFileSync9(join10(dir, SKILL_MARKER), "utf8"));
3132
3184
  return typeof marker.version === "string" ? marker.version : null;
3133
3185
  } catch {
3134
3186
  return null;
@@ -3138,25 +3190,25 @@ function isInstalledSkill(dir) {
3138
3190
  return installedVersion(dir) !== null;
3139
3191
  }
3140
3192
  function installSkill(agent2, opts = {}) {
3141
- const dir = join9(agent2.skillsDir, SKILL_NAME);
3193
+ const dir = join10(agent2.skillsDir, SKILL_NAME);
3142
3194
  const previous = installedVersion(dir);
3143
3195
  const outcome = previous === CLI_VERSION ? "current" : previous ? "updated" : "installed";
3144
3196
  if (opts.dryRun) return { agent: agent2.id, path: dir, outcome };
3145
3197
  if (outcome !== "current") {
3146
3198
  mkdirSync2(dir, { recursive: true });
3147
- writeFileSync4(join9(dir, "SKILL.md"), skillDocument());
3148
- writeFileSync4(join9(dir, SKILL_MARKER), `${JSON.stringify({ version: CLI_VERSION }, null, 2)}
3199
+ writeFileSync4(join10(dir, "SKILL.md"), skillDocument());
3200
+ writeFileSync4(join10(dir, SKILL_MARKER), `${JSON.stringify({ version: CLI_VERSION }, null, 2)}
3149
3201
  `);
3150
3202
  }
3151
3203
  if (opts.catalog) {
3152
3204
  mkdirSync2(dir, { recursive: true });
3153
- writeFileSync4(join9(dir, CATALOG_FILE), renderCatalog(opts.catalog, opts.now ?? /* @__PURE__ */ new Date()));
3205
+ writeFileSync4(join10(dir, CATALOG_FILE), renderCatalog(opts.catalog, opts.now ?? /* @__PURE__ */ new Date()));
3154
3206
  }
3155
- const refsDir = join9(dir, REFERENCES_DIR);
3207
+ const refsDir = join10(dir, REFERENCES_DIR);
3156
3208
  mkdirSync2(refsDir, { recursive: true });
3157
- writeFileSync4(join9(refsDir, "import.md"), importReferenceDoc());
3158
- writeFileSync4(join9(refsDir, "workspaces.md"), workspacesReferenceDoc());
3159
- writeFileSync4(join9(refsDir, "focused-agents.md"), focusedAgentsReferenceDoc());
3209
+ writeFileSync4(join10(refsDir, "import.md"), importReferenceDoc());
3210
+ writeFileSync4(join10(refsDir, "workspaces.md"), workspacesReferenceDoc());
3211
+ writeFileSync4(join10(refsDir, "focused-agents.md"), focusedAgentsReferenceDoc());
3160
3212
  return { agent: agent2.id, path: dir, outcome };
3161
3213
  }
3162
3214
 
@@ -3208,9 +3260,9 @@ function registerMcpServer(agent2, opts, runner = systemCommandRunner()) {
3208
3260
 
3209
3261
  // src/setup-local.ts
3210
3262
  import { isUtf8 as isUtf83 } from "buffer";
3211
- import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync10, statSync as statSync7 } from "fs";
3263
+ import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync10, statSync as statSync7 } from "fs";
3212
3264
  import { homedir as homedir6 } from "os";
3213
- import { dirname as dirname5, isAbsolute as isAbsolute2, join as join10, resolve as resolve6 } from "path";
3265
+ import { dirname as dirname5, isAbsolute as isAbsolute2, join as join11, resolve as resolve6 } from "path";
3214
3266
  import { parse as parseToml3 } from "smol-toml";
3215
3267
  var MAX_SKILL_FILE_BYTES = 1024 * 1024;
3216
3268
  var MAX_IMPORT_DEPTH = 5;
@@ -3234,8 +3286,8 @@ function redacted(data) {
3234
3286
  }
3235
3287
  function skillFiles2(root, prefix) {
3236
3288
  const files2 = [];
3237
- for (const entry2 of readdirSync5(root, { withFileTypes: true })) {
3238
- const path = join10(root, entry2.name);
3289
+ for (const entry2 of readdirSync6(root, { withFileTypes: true })) {
3290
+ const path = join11(root, entry2.name);
3239
3291
  if (entry2.isDirectory()) {
3240
3292
  if (!SKIPPED_DIRS.has(entry2.name)) files2.push(...skillFiles2(path, `${prefix}/${entry2.name}`));
3241
3293
  } else if (entry2.isFile() && !sensitive(entry2.name) && statSync7(path).size <= MAX_SKILL_FILE_BYTES) {
@@ -3250,8 +3302,8 @@ function readLocalSkills(agents) {
3250
3302
  const ignored = [];
3251
3303
  for (const agent2 of agents) {
3252
3304
  if (!existsSync7(agent2.skillsDir)) continue;
3253
- for (const entry2 of readdirSync5(agent2.skillsDir, { withFileTypes: true })) {
3254
- const dir = join10(agent2.skillsDir, entry2.name);
3305
+ for (const entry2 of readdirSync6(agent2.skillsDir, { withFileTypes: true })) {
3306
+ const dir = join11(agent2.skillsDir, entry2.name);
3255
3307
  let isDir2 = entry2.isDirectory();
3256
3308
  if (entry2.isSymbolicLink()) {
3257
3309
  try {
@@ -3260,8 +3312,8 @@ function readLocalSkills(agents) {
3260
3312
  isDir2 = false;
3261
3313
  }
3262
3314
  }
3263
- if (!isDir2 || !existsSync7(join10(dir, "SKILL.md")) || isInstalledSkill(dir)) continue;
3264
- const name = frontmatterName(readFileSync10(join10(dir, "SKILL.md"), "utf8"));
3315
+ if (!isDir2 || !existsSync7(join11(dir, "SKILL.md")) || isInstalledSkill(dir)) continue;
3316
+ const name = frontmatterName(readFileSync10(join11(dir, "SKILL.md"), "utf8"));
3265
3317
  if (!name) {
3266
3318
  ignored.push({ agent: agent2.id, dir, reason: "SKILL.md has no name" });
3267
3319
  continue;
@@ -3289,7 +3341,7 @@ function inlineImports(content, from, home, depth, seen) {
3289
3341
  }
3290
3342
  const target = fence ? void 0 : line.match(/^@(\S+\.(?:md|markdown|txt))$/i)?.[1];
3291
3343
  if (!target || depth >= MAX_IMPORT_DEPTH) return line;
3292
- const path = target.startsWith("~/") ? join10(home, target.slice(2)) : isAbsolute2(target) ? target : resolve6(dirname5(from), target);
3344
+ const path = target.startsWith("~/") ? join11(home, target.slice(2)) : isAbsolute2(target) ? target : resolve6(dirname5(from), target);
3293
3345
  if (seen.includes(path)) return "";
3294
3346
  let imported;
3295
3347
  try {
@@ -3306,7 +3358,7 @@ function readGlobalInstructions(agents, home = homedir6()) {
3306
3358
  for (const agent2 of agents) {
3307
3359
  const file = INSTRUCTION_FILES2[agent2.id];
3308
3360
  if (!file) continue;
3309
- const path = join10(agent2.root, file);
3361
+ const path = join11(agent2.root, file);
3310
3362
  let raw;
3311
3363
  try {
3312
3364
  raw = readFileSync10(path, "utf8");
@@ -3342,10 +3394,10 @@ function bearerOf(def) {
3342
3394
  return match?.[1] ?? null;
3343
3395
  }
3344
3396
  function serversOf(agent2, home) {
3345
- if (agent2.id === "claude_code") return readJson3(join10(home, ".claude.json"))?.mcpServers ?? {};
3346
- if (agent2.id === "cursor") return readJson3(join10(agent2.root, "mcp.json"))?.mcpServers ?? {};
3397
+ if (agent2.id === "claude_code") return readJson3(join11(home, ".claude.json"))?.mcpServers ?? {};
3398
+ if (agent2.id === "cursor") return readJson3(join11(agent2.root, "mcp.json"))?.mcpServers ?? {};
3347
3399
  try {
3348
- return parseToml3(readFileSync10(join10(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
3400
+ return parseToml3(readFileSync10(join11(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
3349
3401
  } catch {
3350
3402
  return {};
3351
3403
  }
@@ -3368,7 +3420,7 @@ function findLocalSecrets(agents, home = homedir6()) {
3368
3420
  import { spawn as spawn3 } from "child_process";
3369
3421
  import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
3370
3422
  import { homedir as homedir7 } from "os";
3371
- import { join as join11 } from "path";
3423
+ import { join as join12 } from "path";
3372
3424
  import { createInterface as createInterface2 } from "readline";
3373
3425
  var ALIASES = {
3374
3426
  claude: "anthropic",
@@ -3464,7 +3516,7 @@ async function connectClaude() {
3464
3516
  console.log(`Connected Claude subscription${expiry}. Powers new eligible agents.`);
3465
3517
  }
3466
3518
  function codexSignIn(env = process.env, home = homedir7()) {
3467
- const path = join11(env.CODEX_HOME || join11(home, ".codex"), "auth.json");
3519
+ const path = join12(env.CODEX_HOME || join12(home, ".codex"), "auth.json");
3468
3520
  if (!existsSync8(path)) {
3469
3521
  throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
3470
3522
  }
@@ -3477,7 +3529,7 @@ function codexSignIn(env = process.env, home = homedir7()) {
3477
3529
  }
3478
3530
  }
3479
3531
  function cursorSignIn(env = process.env, home = homedir7()) {
3480
- const path = join11(env.XDG_CONFIG_HOME || join11(home, ".config"), "cursor", "auth.json");
3532
+ const path = join12(env.XDG_CONFIG_HOME || join12(home, ".config"), "cursor", "auth.json");
3481
3533
  if (!existsSync8(path)) {
3482
3534
  throw new ApiError(404, "no_cursor_auth", `no ${path} \u2014 run \`cursor-agent login\` first`);
3483
3535
  }
@@ -3640,7 +3692,7 @@ function planProviders(names2) {
3640
3692
  }));
3641
3693
  }
3642
3694
  function reportPath() {
3643
- return join12(dirname6(configPath()), "setup.json");
3695
+ return join13(dirname6(configPath()), "setup.json");
3644
3696
  }
3645
3697
  function loadReport() {
3646
3698
  try {
@@ -4007,15 +4059,15 @@ function renderArtifact(artifact2) {
4007
4059
  }
4008
4060
 
4009
4061
  // src/skills-store.ts
4010
- import { readdirSync as readdirSync6, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
4011
- import { basename as basename7, join as join13, relative as relative4, resolve as resolve7 } from "path";
4062
+ import { readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync8 } from "fs";
4063
+ import { basename as basename7, join as join14, relative as relative4, resolve as resolve7 } from "path";
4012
4064
  function skillBundle(dir) {
4013
4065
  const root = resolve7(dir);
4014
4066
  const top = basename7(root);
4015
4067
  const files2 = [];
4016
4068
  const walk = (path) => {
4017
- for (const name of readdirSync6(path).sort()) {
4018
- const full = join13(path, name);
4069
+ for (const name of readdirSync7(path).sort()) {
4070
+ const full = join14(path, name);
4019
4071
  if (statSync8(full).isDirectory()) walk(full);
4020
4072
  else files2.push({ path: `${top}/${relative4(root, full)}`, bytes: readFileSync13(full) });
4021
4073
  }
@@ -4271,10 +4323,10 @@ function confirmPrompt(question) {
4271
4323
 
4272
4324
  // src/harness.ts
4273
4325
  import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync14, writeFileSync as writeFileSync6 } from "fs";
4274
- import { dirname as dirname7, join as join14, resolve as resolve8 } from "path";
4326
+ import { dirname as dirname7, join as join15, resolve as resolve8 } from "path";
4275
4327
  var HARNESS_FILE = "harness.json";
4276
4328
  function harnessFilePath(dir) {
4277
- return join14(resolve8(dir), HARNESS_FILE);
4329
+ return join15(resolve8(dir), HARNESS_FILE);
4278
4330
  }
4279
4331
  function readHarnessFile(dir) {
4280
4332
  const path = harnessFilePath(dir);
@@ -5427,10 +5479,40 @@ Importing ${label} \u2026
5427
5479
  )
5428
5480
  );
5429
5481
  var files = program.command("files").description("files: upload once, reference by id from any message");
5430
- files.command("upload <path>").description("upload a local file; prints the file id to reference from a message").option("--expires <seconds>", "expire the upload after this many seconds (3600\u20137776000)").action(
5431
- run(async (path, opts) => {
5432
- const file = await uploadLocalFile(path, opts.expires ? Number(opts.expires) : void 0, uploadProgress);
5433
- console.log(`${file.id} ${file.filename} ${file.mime_type} ${file.size_bytes} bytes`);
5482
+ files.command("upload <paths...>").description("upload local files and folders, up to 50 GiB each; prints each file id to reference from a message").option("--expires <seconds>", "expire the uploads after this many seconds (3600\u20137776000)").action(
5483
+ run(async (paths, opts) => {
5484
+ const expires = opts.expires ? Number(opts.expires) : void 0;
5485
+ const chosen = filesUnder(paths);
5486
+ if (chosen.length === 0) throw new Error("no files to upload");
5487
+ const line = (file) => `${file.id} ${file.filename} ${file.mime_type} ${file.size_bytes} bytes`;
5488
+ if (chosen.length === 1) {
5489
+ console.log(line(await uploadLocalFile(chosen[0], expires, uploadProgress)));
5490
+ return;
5491
+ }
5492
+ let done = 0;
5493
+ const tally = () => process.stderr.write(`${process.stderr.isTTY ? "\r" : ""}uploaded ${++done} / ${chosen.length}${process.stderr.isTTY && done < chosen.length ? "" : "\n"}`);
5494
+ const result = await uploadLocalFiles(chosen, {
5495
+ expiresInSeconds: expires,
5496
+ onUploaded: (_path, file) => {
5497
+ console.log(line(file));
5498
+ tally();
5499
+ },
5500
+ onFailed: (path, error) => {
5501
+ console.error(`sky: ${path}: ${error instanceof Error ? error.message : String(error)}`);
5502
+ tally();
5503
+ }
5504
+ });
5505
+ if (result.failed) {
5506
+ console.error(`sky: ${result.failed} of ${chosen.length} files failed; run the same command for those paths to retry`);
5507
+ process.exitCode = 1;
5508
+ }
5509
+ })
5510
+ );
5511
+ files.command("usage").description("how many files your workspace holds and the space they take (there is no storage limit)").action(
5512
+ run(async () => {
5513
+ const usage = await api("GET", "/files/usage");
5514
+ const gib = (bytes) => `${(bytes / 1024 ** 3).toFixed(2)} GiB`;
5515
+ console.log(`${usage.file_count} files ${gib(usage.size_bytes)} used ${usage.storage_limit_bytes === null ? "no storage limit" : `${gib(usage.storage_limit_bytes)} limit`} up to ${gib(usage.max_file_bytes)} per file`);
5434
5516
  })
5435
5517
  );
5436
5518
  files.command("list").description("list your uploads, or one session's files with --session").option("--session <ref>", "list the files of this session (its message copies and outputs)").option("--limit <n>", "page size (default 20)").option("--page <cursor>", "continue from a previous page").action(
@@ -6168,7 +6250,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
6168
6250
  }));
6169
6251
  var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
6170
6252
  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) => {
6171
- const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-H3AP64UZ.js");
6253
+ const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-QLJH7VK6.js");
6172
6254
  if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
6173
6255
  const scopes = parseContentScopes(opts.capture);
6174
6256
  const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
@@ -6203,7 +6285,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
6203
6285
  }));
6204
6286
  traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
6205
6287
  try {
6206
- const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-H3AP64UZ.js");
6288
+ const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-QLJH7VK6.js");
6207
6289
  const chunks = [];
6208
6290
  for await (const chunk of process.stdin) chunks.push(chunk);
6209
6291
  const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
@@ -6216,14 +6298,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
6216
6298
  }
6217
6299
  });
6218
6300
  traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
6219
- const { readState, flush, grantSender } = await import("./trace-H3AP64UZ.js");
6301
+ const { readState, flush, grantSender } = await import("./trace-QLJH7VK6.js");
6220
6302
  const state = readState();
6221
6303
  if (!state) throw new Error("no trace is running here");
6222
6304
  const outcome = await flush(grantSender(state), { attempts: 4 });
6223
6305
  console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
6224
6306
  }));
6225
6307
  traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
6226
- const { readState, spoolStatus } = await import("./trace-H3AP64UZ.js");
6308
+ const { readState, spoolStatus } = await import("./trace-QLJH7VK6.js");
6227
6309
  const state = readState();
6228
6310
  if (!state) {
6229
6311
  console.log("No trace is running here.");
@@ -6233,7 +6315,7 @@ traceCmd.command("status").description("the running trace and its spool").action
6233
6315
  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`);
6234
6316
  }));
6235
6317
  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) => {
6236
- const { readState } = await import("./trace-H3AP64UZ.js");
6318
+ const { readState } = await import("./trace-QLJH7VK6.js");
6237
6319
  const ref = id ?? readState()?.trace_id;
6238
6320
  if (!ref) throw new Error("name a trace, or start one here");
6239
6321
  const bundle = await api("GET", `/traces/${ref}`);
@@ -6260,7 +6342,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
6260
6342
  for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
6261
6343
  }));
6262
6344
  traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
6263
- const { readState, record, flush, grantSender, clearState } = await import("./trace-H3AP64UZ.js");
6345
+ const { readState, record, flush, grantSender, clearState } = await import("./trace-QLJH7VK6.js");
6264
6346
  const state = readState();
6265
6347
  if (!state) throw new Error("no trace is running here");
6266
6348
  if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
@@ -6270,7 +6352,7 @@ traceCmd.command("stop").description("end the root span, send what is left, and
6270
6352
  console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
6271
6353
  }));
6272
6354
  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) => {
6273
- const lib = await import("./trace-library-LGPKAQTY.js");
6355
+ const lib = await import("./trace-library-FS5PCBJC.js");
6274
6356
  if (opts.hook) {
6275
6357
  try {
6276
6358
  let raw = payload ?? "";
@@ -6318,10 +6400,10 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
6318
6400
  console.log(`A repository's .agentsky.json "workspace" wins over these rules.`);
6319
6401
  }
6320
6402
  if (opts.installSchedule) {
6321
- const { join: join15 } = await import("path");
6403
+ const { join: join16 } = await import("path");
6322
6404
  const { homedir: homedir8 } = await import("os");
6323
6405
  const { execFileSync } = await import("child_process");
6324
- const log = join15(homedir8(), ".config", "sky", "trace-sync.log");
6406
+ const log = join16(homedir8(), ".config", "sky", "trace-sync.log");
6325
6407
  const plist = lib.installLaunchd([process.execPath, process.argv[1], "trace", "sync", "--quiet"], log);
6326
6408
  try {
6327
6409
  execFileSync("launchctl", ["unload", plist], { stdio: "ignore" });
@@ -6332,10 +6414,10 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
6332
6414
  }
6333
6415
  if (opts.status) {
6334
6416
  const { readFileSync: readFileSync16 } = await import("fs");
6335
- const { join: join15 } = await import("path");
6417
+ const { join: join16 } = await import("path");
6336
6418
  let state = { sessions: {} };
6337
6419
  try {
6338
- state = JSON.parse(readFileSync16(join15(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
6420
+ state = JSON.parse(readFileSync16(join16(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
6339
6421
  } catch {
6340
6422
  }
6341
6423
  const counts = /* @__PURE__ */ new Map();
@@ -6368,7 +6450,7 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
6368
6450
  })();
6369
6451
  });
6370
6452
  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) => {
6371
- const { libraryRequest } = await import("./trace-library-LGPKAQTY.js");
6453
+ const { libraryRequest } = await import("./trace-library-FS5PCBJC.js");
6372
6454
  const workspace2 = opts.workspace ?? currentUniverse();
6373
6455
  if (!workspace2) throw new Error("name a workspace with --workspace");
6374
6456
  const params = new URLSearchParams({ q: words.join(" "), scope: "traces", limit: String(opts.limit), ...opts.cursor ? { cursor: opts.cursor } : {} });
@@ -6385,7 +6467,7 @@ traceCmd.command("search <query...>").description("search every session in a wor
6385
6467
  if (page.nextCursor) console.log(`More: sky trace search ${JSON.stringify(words.join(" "))} --workspace ${workspace2} --cursor ${page.nextCursor}`);
6386
6468
  }));
6387
6469
  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) => {
6388
- const { libraryRequest } = await import("./trace-library-LGPKAQTY.js");
6470
+ const { libraryRequest } = await import("./trace-library-FS5PCBJC.js");
6389
6471
  const workspace2 = opts.workspace ?? currentUniverse();
6390
6472
  if (!workspace2) throw new Error("name a workspace with --workspace");
6391
6473
  const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  USER_AGENT,
3
3
  configPath
4
- } from "./chunk-H7SWXCH7.js";
4
+ } from "./chunk-MUHFB3LC.js";
5
5
  import {
6
6
  TRACE_CONTENT_SCOPES,
7
7
  redactTraceText
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  ApiError
3
- } from "./chunk-FU43NICZ.js";
3
+ } from "./chunk-PL5KNPCX.js";
4
4
  import {
5
5
  USER_AGENT,
6
6
  apiBase,
7
7
  apiToken
8
- } from "./chunk-H7SWXCH7.js";
8
+ } from "./chunk-MUHFB3LC.js";
9
9
  import {
10
10
  SessionSourceCollector,
11
11
  publicRemote,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsky/sky",
3
- "version": "2.17.0",
3
+ "version": "2.18.0",
4
4
  "description": "sky \u2014 the AgentSky developer CLI: launch and talk to long-lived agents from your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",