@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.
- package/dist/{chunk-H7SWXCH7.js → chunk-MUHFB3LC.js} +1 -1
- package/dist/{chunk-FU43NICZ.js → chunk-PL5KNPCX.js} +1 -1
- package/dist/index.js +212 -130
- package/dist/{trace-H3AP64UZ.js → trace-QLJH7VK6.js} +1 -1
- package/dist/{trace-library-LGPKAQTY.js → trace-library-FS5PCBJC.js} +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveSessionRef,
|
|
10
10
|
streamEvents,
|
|
11
11
|
uploadFile
|
|
12
|
-
} from "./chunk-
|
|
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-
|
|
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
|
|
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 ??
|
|
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
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
674
|
-
if (existsSync2(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
1022
|
+
const rules = join4(home, ".agents", "rules");
|
|
971
1023
|
let ruleFiles = [];
|
|
972
1024
|
try {
|
|
973
|
-
ruleFiles =
|
|
1025
|
+
ruleFiles = readdirSync2(rules).filter((name) => name.endsWith(".md")).sort().map((name) => join4(rules, name));
|
|
974
1026
|
} catch {
|
|
975
1027
|
}
|
|
976
|
-
return [
|
|
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 ??
|
|
986
|
-
const codex = process.env.CODEX_HOME ??
|
|
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 ? [
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1008
|
-
if (entry2.name === skill && basename4(dir) === "skills" && path.includes(`${sep}${plugin}${sep}`) && isFile(
|
|
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 =
|
|
1021
|
-
if (isFile(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
1314
|
-
if (harness2 === "codex") out.push(
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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(
|
|
1645
|
-
const path =
|
|
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 =
|
|
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 ??
|
|
1828
|
-
const projectsDir =
|
|
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
|
|
1833
|
-
const projectDir =
|
|
1884
|
+
for (const encoded of readdirSync4(projectsDir)) {
|
|
1885
|
+
const projectDir = join7(projectsDir, encoded);
|
|
1834
1886
|
let entries;
|
|
1835
1887
|
try {
|
|
1836
|
-
entries =
|
|
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 =
|
|
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 =
|
|
1906
|
+
const subagentDir = join7(projectDir, sessionId, "subagents");
|
|
1855
1907
|
if (existsSync5(subagentDir)) {
|
|
1856
1908
|
try {
|
|
1857
|
-
const subFiles =
|
|
1909
|
+
const subFiles = readdirSync4(subagentDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
1858
1910
|
for (const f of subFiles) {
|
|
1859
|
-
subagentFiles.push(
|
|
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 =
|
|
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 =
|
|
1938
|
+
entries = readdirSync4(dir, { withFileTypes: true });
|
|
1887
1939
|
} catch {
|
|
1888
1940
|
return;
|
|
1889
1941
|
}
|
|
1890
1942
|
for (const entry2 of entries) {
|
|
1891
|
-
const full =
|
|
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
|
|
2444
|
-
import { basename as basename6, join as
|
|
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(
|
|
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
|
|
2534
|
+
for (const entry2 of readdirSync5(at, { withFileTypes: true })) {
|
|
2483
2535
|
if (SKIPPED2.has(entry2.name)) continue;
|
|
2484
|
-
const full =
|
|
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
|
|
2620
|
+
import { join as join9 } from "path";
|
|
2569
2621
|
function localAgents(env = process.env, home = homedir5()) {
|
|
2570
|
-
const claude = env.CLAUDE_CONFIG_DIR ||
|
|
2571
|
-
const codex = env.CODEX_HOME ||
|
|
2572
|
-
const 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:
|
|
2575
|
-
{ id: "codex", name: "Codex", root: codex, skillsDir:
|
|
2576
|
-
{ id: "cursor", name: "Cursor", root: cursor, skillsDir:
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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(
|
|
3148
|
-
writeFileSync4(
|
|
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(
|
|
3205
|
+
writeFileSync4(join10(dir, CATALOG_FILE), renderCatalog(opts.catalog, opts.now ?? /* @__PURE__ */ new Date()));
|
|
3154
3206
|
}
|
|
3155
|
-
const refsDir =
|
|
3207
|
+
const refsDir = join10(dir, REFERENCES_DIR);
|
|
3156
3208
|
mkdirSync2(refsDir, { recursive: true });
|
|
3157
|
-
writeFileSync4(
|
|
3158
|
-
writeFileSync4(
|
|
3159
|
-
writeFileSync4(
|
|
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
|
|
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
|
|
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
|
|
3238
|
-
const path =
|
|
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
|
|
3254
|
-
const dir =
|
|
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(
|
|
3264
|
-
const name = frontmatterName(readFileSync10(
|
|
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("~/") ?
|
|
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 =
|
|
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(
|
|
3346
|
-
if (agent2.id === "cursor") return readJson3(
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
4011
|
-
import { basename as basename7, join as
|
|
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
|
|
4018
|
-
const full =
|
|
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
|
|
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
|
|
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 <
|
|
5431
|
-
run(async (
|
|
5432
|
-
const
|
|
5433
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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:
|
|
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 =
|
|
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:
|
|
6417
|
+
const { join: join16 } = await import("path");
|
|
6336
6418
|
let state = { sessions: {} };
|
|
6337
6419
|
try {
|
|
6338
|
-
state = JSON.parse(readFileSync16(
|
|
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-
|
|
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-
|
|
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);
|