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