@agentsky/sky 2.20.0 → 2.20.2
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-DC3R6BV2.js → chunk-GHTAIKQ6.js} +80 -30
- package/dist/{chunk-BHW2NAXP.js → chunk-HB7SPKQ5.js} +1 -1
- package/dist/{chunk-ICSGMEG5.js → chunk-WTFBVTMI.js} +4 -3
- package/dist/index.js +158 -53
- package/dist/{src-3HXHE2S6.js → src-QBXMNV2V.js} +28 -6
- package/dist/{trace-DI2SQI7M.js → trace-HTWXINXI.js} +2 -2
- package/dist/{trace-library-4WWKCSVU.js → trace-library-QR54Q4Z3.js} +3 -3
- package/package.json +4 -10
- package/dist/products.d.ts +0 -652
- package/dist/products.js +0 -208
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveSessionRef,
|
|
10
10
|
streamEvents,
|
|
11
11
|
uploadFile
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WTFBVTMI.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-HB7SPKQ5.js";
|
|
24
24
|
import {
|
|
25
25
|
AGENT_TYPES,
|
|
26
26
|
MODEL_SUBSCRIPTION_PLAN_PHRASE,
|
|
@@ -42,11 +42,11 @@ import {
|
|
|
42
42
|
skillRefSchema,
|
|
43
43
|
splitMcpServers,
|
|
44
44
|
supersededBy
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-GHTAIKQ6.js";
|
|
46
46
|
import "./chunk-MLKGABMK.js";
|
|
47
47
|
|
|
48
48
|
// src/index.ts
|
|
49
|
-
import { existsSync as existsSync10, readFileSync as
|
|
49
|
+
import { existsSync as existsSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "fs";
|
|
50
50
|
import { basename as basename8, resolve as resolve9 } from "path";
|
|
51
51
|
import { createInterface as createInterface6 } from "readline";
|
|
52
52
|
import { Command } from "commander";
|
|
@@ -2279,6 +2279,12 @@ async function bind(connectionId, opts) {
|
|
|
2279
2279
|
async function send(threadId, text) {
|
|
2280
2280
|
await api("POST", `/channels/threads/${encodeURIComponent(threadId)}/messages`, { parts: [{ type: "markdown", text }] });
|
|
2281
2281
|
}
|
|
2282
|
+
async function history(threadId, opts) {
|
|
2283
|
+
const query = new URLSearchParams();
|
|
2284
|
+
if (opts.limit) query.set("limit", opts.limit);
|
|
2285
|
+
if (opts.cursor) query.set("cursor", opts.cursor);
|
|
2286
|
+
return api("GET", `/channels/threads/${encodeURIComponent(threadId)}/messages?${query}`);
|
|
2287
|
+
}
|
|
2282
2288
|
|
|
2283
2289
|
// src/connectors.ts
|
|
2284
2290
|
import { createServer as createServer2 } from "http";
|
|
@@ -2705,7 +2711,7 @@ function latestTurn(events) {
|
|
|
2705
2711
|
}
|
|
2706
2712
|
return reading;
|
|
2707
2713
|
}
|
|
2708
|
-
async function
|
|
2714
|
+
async function history2(sessionId) {
|
|
2709
2715
|
const events = [];
|
|
2710
2716
|
let cursor = null;
|
|
2711
2717
|
for (; ; ) {
|
|
@@ -2724,18 +2730,19 @@ async function history(sessionId) {
|
|
|
2724
2730
|
async function readTurn(sessionId, opts = {}) {
|
|
2725
2731
|
const deadline = Date.now() + (opts.timeoutSeconds ?? 600) * 1e3;
|
|
2726
2732
|
for (; ; ) {
|
|
2727
|
-
const reading = latestTurn(await
|
|
2733
|
+
const reading = latestTurn(await history2(sessionId));
|
|
2728
2734
|
if (reading.finished || !opts.wait || Date.now() >= deadline) return reading;
|
|
2729
2735
|
await new Promise((resolve10) => setTimeout(resolve10, opts.intervalMs ?? 3e3));
|
|
2730
2736
|
}
|
|
2731
2737
|
}
|
|
2732
2738
|
|
|
2733
2739
|
// src/setup.ts
|
|
2734
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
2740
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
|
|
2735
2741
|
import { dirname as dirname6, join as join13 } from "path";
|
|
2736
2742
|
import { createInterface as createInterface3 } from "readline";
|
|
2737
2743
|
|
|
2738
2744
|
// src/mcp-register.ts
|
|
2745
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
2739
2746
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
2740
2747
|
|
|
2741
2748
|
// src/skill.ts
|
|
@@ -2831,6 +2838,25 @@ Details: \`${REFERENCES_DIR}/workspaces.md\` in this skill's folder.
|
|
|
2831
2838
|
- Do the work yourself when it is small, when it depends on what you already have
|
|
2832
2839
|
in front of you, or when explaining it would take as long as doing it.
|
|
2833
2840
|
|
|
2841
|
+
## Local first, cloud when it is not here, never a stand-in
|
|
2842
|
+
|
|
2843
|
+
- When the person names an engine that is installed and signed in on this
|
|
2844
|
+
computer, run it here: it costs them nothing on AgentSky.
|
|
2845
|
+
- When it is not installed here, start that same engine in the cloud: its handle
|
|
2846
|
+
(\`@codex\`, \`@claude_code\`, \u2026) with \`start_session\` and a \`budget_cents\`, and say so
|
|
2847
|
+
in one line ("Codex is not installed on this Mac, so it ran in the cloud").
|
|
2848
|
+
Do not pick another engine instead.
|
|
2849
|
+
- Every refused tool call carries a stable error \`code\` (in the error text and in
|
|
2850
|
+
\`structuredContent.error\`) and, when there is one, a \`next_step\`. Read the code:
|
|
2851
|
+
\`insufficient_credits\`, \`workspace_wallet_empty\` and \`payment_setup_required\` mean
|
|
2852
|
+
the account cannot pay; \`budget_reached\` means that session's cap is spent.
|
|
2853
|
+
Stop that piece of work and tell the person what was refused and what unblocks
|
|
2854
|
+
it (credit or a card under Settings \u203A Billing, a larger \`budget_cents\`), then
|
|
2855
|
+
offer the engines that are installed here as the free alternative. Never hire a
|
|
2856
|
+
cheaper or different agent to get around a refusal.
|
|
2857
|
+
- \`get_usage\` shows the balance; check it before starting several cloud sessions
|
|
2858
|
+
at once so the person is told once, up front, instead of after the first fails.
|
|
2859
|
+
|
|
2834
2860
|
## How to pick
|
|
2835
2861
|
|
|
2836
2862
|
Read \`${CATALOG_FILE}\` in this skill's folder. It lists every agent you can hire,
|
|
@@ -3249,6 +3275,9 @@ function redact(text, token) {
|
|
|
3249
3275
|
return text.split(token).join(`${token.slice(0, 10)}\u2026`);
|
|
3250
3276
|
}
|
|
3251
3277
|
function registerMcpServer(agent2, opts, runner = systemCommandRunner()) {
|
|
3278
|
+
if (agent2.id === "cursor") {
|
|
3279
|
+
return registerCursorMcpServer(agent2, opts);
|
|
3280
|
+
}
|
|
3252
3281
|
const commands = mcpCommands(agent2.id, opts);
|
|
3253
3282
|
if (!commands) return { agent: agent2.id, outcome: "unsupported" };
|
|
3254
3283
|
if (!runner.has(commands.command)) return { agent: agent2.id, outcome: "no_command", detail: `${commands.command} is not on PATH` };
|
|
@@ -3258,10 +3287,40 @@ function registerMcpServer(agent2, opts, runner = systemCommandRunner()) {
|
|
|
3258
3287
|
if (added.status !== 0) return { agent: agent2.id, outcome: "failed", detail: redact(added.stderr.trim() || `exit ${added.status}`, opts.token) };
|
|
3259
3288
|
return agent2.id === "codex" ? { agent: agent2.id, outcome: "registered", detail: `set ${CODEX_TOKEN_ENV} to an AgentSky API token in the shell that runs codex` } : { agent: agent2.id, outcome: "registered" };
|
|
3260
3289
|
}
|
|
3290
|
+
function registerCursorMcpServer(agent2, opts) {
|
|
3291
|
+
const configPath2 = `${agent2.root}/mcp.json`;
|
|
3292
|
+
const entry2 = {
|
|
3293
|
+
url: opts.mcpUrl,
|
|
3294
|
+
headers: { Authorization: `Bearer ${opts.token}` }
|
|
3295
|
+
};
|
|
3296
|
+
if (opts.dryRun) {
|
|
3297
|
+
const preview = JSON.stringify({ agentsky: { url: opts.mcpUrl, headers: { Authorization: `Bearer ${opts.token.slice(0, 10)}\u2026` } } }, null, 2);
|
|
3298
|
+
return { agent: agent2.id, outcome: "planned", detail: `would write to ${configPath2}: ${preview}` };
|
|
3299
|
+
}
|
|
3300
|
+
let existing = { mcpServers: {} };
|
|
3301
|
+
try {
|
|
3302
|
+
const raw = readFileSync10(configPath2, "utf8");
|
|
3303
|
+
const parsed = JSON.parse(raw);
|
|
3304
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3305
|
+
existing = parsed;
|
|
3306
|
+
}
|
|
3307
|
+
} catch {
|
|
3308
|
+
}
|
|
3309
|
+
const updated = {
|
|
3310
|
+
...existing,
|
|
3311
|
+
mcpServers: { ...existing.mcpServers ?? {}, [MCP_SERVER_NAME]: entry2 }
|
|
3312
|
+
};
|
|
3313
|
+
try {
|
|
3314
|
+
writeFileSync5(configPath2, JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
3315
|
+
} catch (err) {
|
|
3316
|
+
return { agent: agent2.id, outcome: "failed", detail: String(err) };
|
|
3317
|
+
}
|
|
3318
|
+
return { agent: agent2.id, outcome: "registered" };
|
|
3319
|
+
}
|
|
3261
3320
|
|
|
3262
3321
|
// src/setup-local.ts
|
|
3263
3322
|
import { isUtf8 as isUtf83 } from "buffer";
|
|
3264
|
-
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as
|
|
3323
|
+
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
|
|
3265
3324
|
import { homedir as homedir6 } from "os";
|
|
3266
3325
|
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join11, resolve as resolve6 } from "path";
|
|
3267
3326
|
import { parse as parseToml3 } from "smol-toml";
|
|
@@ -3292,7 +3351,7 @@ function skillFiles2(root, prefix) {
|
|
|
3292
3351
|
if (entry2.isDirectory()) {
|
|
3293
3352
|
if (!SKIPPED_DIRS.has(entry2.name)) files2.push(...skillFiles2(path, `${prefix}/${entry2.name}`));
|
|
3294
3353
|
} else if (entry2.isFile() && !sensitive(entry2.name) && statSync7(path).size <= MAX_SKILL_FILE_BYTES) {
|
|
3295
|
-
const bytes = redacted(
|
|
3354
|
+
const bytes = redacted(readFileSync11(path));
|
|
3296
3355
|
if (bytes) files2.push({ path: `${prefix}/${entry2.name}`, bytes });
|
|
3297
3356
|
}
|
|
3298
3357
|
}
|
|
@@ -3314,7 +3373,7 @@ function readLocalSkills(agents) {
|
|
|
3314
3373
|
}
|
|
3315
3374
|
}
|
|
3316
3375
|
if (!isDir2 || !existsSync7(join11(dir, "SKILL.md")) || isInstalledSkill(dir)) continue;
|
|
3317
|
-
const name = frontmatterName(
|
|
3376
|
+
const name = frontmatterName(readFileSync11(join11(dir, "SKILL.md"), "utf8"));
|
|
3318
3377
|
if (!name) {
|
|
3319
3378
|
ignored.push({ agent: agent2.id, dir, reason: "SKILL.md has no name" });
|
|
3320
3379
|
continue;
|
|
@@ -3346,7 +3405,7 @@ function inlineImports(content, from, home, depth, seen) {
|
|
|
3346
3405
|
if (seen.includes(path)) return "";
|
|
3347
3406
|
let imported;
|
|
3348
3407
|
try {
|
|
3349
|
-
imported =
|
|
3408
|
+
imported = readFileSync11(path, "utf8");
|
|
3350
3409
|
} catch {
|
|
3351
3410
|
return line;
|
|
3352
3411
|
}
|
|
@@ -3362,7 +3421,7 @@ function readGlobalInstructions(agents, home = homedir6()) {
|
|
|
3362
3421
|
const path = join11(agent2.root, file);
|
|
3363
3422
|
let raw;
|
|
3364
3423
|
try {
|
|
3365
|
-
raw =
|
|
3424
|
+
raw = readFileSync11(path, "utf8");
|
|
3366
3425
|
} catch {
|
|
3367
3426
|
continue;
|
|
3368
3427
|
}
|
|
@@ -3381,7 +3440,7 @@ ${item.content.trim()}`).join("\n\n");
|
|
|
3381
3440
|
}
|
|
3382
3441
|
function readJson3(path) {
|
|
3383
3442
|
try {
|
|
3384
|
-
return JSON.parse(
|
|
3443
|
+
return JSON.parse(readFileSync11(path, "utf8"));
|
|
3385
3444
|
} catch {
|
|
3386
3445
|
return void 0;
|
|
3387
3446
|
}
|
|
@@ -3398,7 +3457,7 @@ function serversOf(agent2, home) {
|
|
|
3398
3457
|
if (agent2.id === "claude_code") return readJson3(join11(home, ".claude.json"))?.mcpServers ?? {};
|
|
3399
3458
|
if (agent2.id === "cursor") return readJson3(join11(agent2.root, "mcp.json"))?.mcpServers ?? {};
|
|
3400
3459
|
try {
|
|
3401
|
-
return parseToml3(
|
|
3460
|
+
return parseToml3(readFileSync11(join11(agent2.root, "config.toml"), "utf8")).mcp_servers ?? {};
|
|
3402
3461
|
} catch {
|
|
3403
3462
|
return {};
|
|
3404
3463
|
}
|
|
@@ -3419,7 +3478,7 @@ function findLocalSecrets(agents, home = homedir6()) {
|
|
|
3419
3478
|
|
|
3420
3479
|
// src/subscriptions.ts
|
|
3421
3480
|
import { spawn as spawn3 } from "child_process";
|
|
3422
|
-
import { existsSync as existsSync8, readFileSync as
|
|
3481
|
+
import { existsSync as existsSync8, readFileSync as readFileSync12 } from "fs";
|
|
3423
3482
|
import { homedir as homedir7 } from "os";
|
|
3424
3483
|
import { join as join12 } from "path";
|
|
3425
3484
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -3521,7 +3580,7 @@ function codexSignIn(env = process.env, home = homedir7()) {
|
|
|
3521
3580
|
if (!existsSync8(path)) {
|
|
3522
3581
|
throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
|
|
3523
3582
|
}
|
|
3524
|
-
const raw =
|
|
3583
|
+
const raw = readFileSync12(path, "utf8");
|
|
3525
3584
|
try {
|
|
3526
3585
|
const parsed = JSON.parse(raw);
|
|
3527
3586
|
return { path, raw, account: parsed.tokens?.account_id };
|
|
@@ -3534,7 +3593,7 @@ function cursorSignIn(env = process.env, home = homedir7()) {
|
|
|
3534
3593
|
if (!existsSync8(path)) {
|
|
3535
3594
|
throw new ApiError(404, "no_cursor_auth", `no ${path} \u2014 run \`cursor-agent login\` first`);
|
|
3536
3595
|
}
|
|
3537
|
-
const raw =
|
|
3596
|
+
const raw = readFileSync12(path, "utf8");
|
|
3538
3597
|
try {
|
|
3539
3598
|
const parsed = JSON.parse(raw);
|
|
3540
3599
|
if (typeof parsed.accessToken !== "string" || typeof parsed.refreshToken !== "string") throw new Error("shape");
|
|
@@ -3697,7 +3756,7 @@ function reportPath() {
|
|
|
3697
3756
|
}
|
|
3698
3757
|
function loadReport() {
|
|
3699
3758
|
try {
|
|
3700
|
-
const saved = JSON.parse(
|
|
3759
|
+
const saved = JSON.parse(readFileSync13(reportPath(), "utf8"));
|
|
3701
3760
|
return { agents: saved.agents ?? [], plans: saved.plans ?? [], ...saved.secrets ? { secrets: saved.secrets } : {} };
|
|
3702
3761
|
} catch {
|
|
3703
3762
|
return { agents: [], plans: [] };
|
|
@@ -3711,7 +3770,7 @@ function mergeReport(base, next) {
|
|
|
3711
3770
|
}
|
|
3712
3771
|
function saveReport(report) {
|
|
3713
3772
|
mkdirSync3(dirname6(reportPath()), { recursive: true });
|
|
3714
|
-
|
|
3773
|
+
writeFileSync6(reportPath(), `${JSON.stringify(report, null, 2)}
|
|
3715
3774
|
`, { mode: 384 });
|
|
3716
3775
|
}
|
|
3717
3776
|
function confirm3(question) {
|
|
@@ -4060,7 +4119,7 @@ function renderArtifact(artifact2) {
|
|
|
4060
4119
|
}
|
|
4061
4120
|
|
|
4062
4121
|
// src/skills-store.ts
|
|
4063
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
4122
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync8 } from "fs";
|
|
4064
4123
|
import { basename as basename7, join as join14, relative as relative4, resolve as resolve7 } from "path";
|
|
4065
4124
|
function skillBundle(dir) {
|
|
4066
4125
|
const root = resolve7(dir);
|
|
@@ -4070,7 +4129,7 @@ function skillBundle(dir) {
|
|
|
4070
4129
|
for (const name of readdirSync7(path).sort()) {
|
|
4071
4130
|
const full = join14(path, name);
|
|
4072
4131
|
if (statSync8(full).isDirectory()) walk(full);
|
|
4073
|
-
else files2.push({ path: `${top}/${relative4(root, full)}`, bytes:
|
|
4132
|
+
else files2.push({ path: `${top}/${relative4(root, full)}`, bytes: readFileSync14(full) });
|
|
4074
4133
|
}
|
|
4075
4134
|
};
|
|
4076
4135
|
walk(root);
|
|
@@ -4109,7 +4168,7 @@ async function getSkillUsage(since) {
|
|
|
4109
4168
|
|
|
4110
4169
|
// src/task-export.ts
|
|
4111
4170
|
import { createHash as createHash6 } from "crypto";
|
|
4112
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
4171
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
4113
4172
|
import { dirname as dirname7, join as join15 } from "path";
|
|
4114
4173
|
import { stringify as stringifyToml2 } from "smol-toml";
|
|
4115
4174
|
var TEXT_MAX = 2e4;
|
|
@@ -4402,7 +4461,7 @@ async function exportTaskHarbor(taskRef, outDir, opts) {
|
|
|
4402
4461
|
for (const [path, content] of files2) {
|
|
4403
4462
|
const target = join15(outDir, path);
|
|
4404
4463
|
mkdirSync4(dirname7(target), { recursive: true });
|
|
4405
|
-
|
|
4464
|
+
writeFileSync7(target, content, typeof content === "string" ? { mode: path.endsWith(".sh") || path.endsWith(".py") ? 493 : 420 } : void 0);
|
|
4406
4465
|
written.push(path);
|
|
4407
4466
|
}
|
|
4408
4467
|
return { written, record };
|
|
@@ -4677,7 +4736,9 @@ async function listBrowserProfiles() {
|
|
|
4677
4736
|
return data;
|
|
4678
4737
|
}
|
|
4679
4738
|
async function getBrowserProfile(scope) {
|
|
4680
|
-
const
|
|
4739
|
+
const profiles = await listBrowserProfiles();
|
|
4740
|
+
const profile = profiles.find((entry2) => entry2.scope === scope);
|
|
4741
|
+
if (!profile) throw new ApiError(404, "not_found", "browser profile not found");
|
|
4681
4742
|
return profile;
|
|
4682
4743
|
}
|
|
4683
4744
|
async function importBrowserProfileState(scope, state) {
|
|
@@ -4687,16 +4748,24 @@ async function listBrowserProfileSites(scope) {
|
|
|
4687
4748
|
const profile = await getBrowserProfile(scope);
|
|
4688
4749
|
return profile.sites;
|
|
4689
4750
|
}
|
|
4751
|
+
async function browserSiteReference(scope, site) {
|
|
4752
|
+
const sites = await listBrowserProfileSites(scope);
|
|
4753
|
+
const row = sites.find((entry2) => entry2.site === site) ?? sites.find((entry2) => entry2.site_id === site);
|
|
4754
|
+
if (!row) throw new ApiError(404, "not_found", "site not found in this browser profile");
|
|
4755
|
+
return row.site_id ? `${encodeURIComponent(row.site_id)}?by=id` : encodeURIComponent(row.site);
|
|
4756
|
+
}
|
|
4690
4757
|
async function removeBrowserProfileSite(scope, site) {
|
|
4691
|
-
await api("DELETE", `/browser_profiles/${encodeURIComponent(scope)}/sites/${
|
|
4758
|
+
await api("DELETE", `/browser_profiles/${encodeURIComponent(scope)}/sites/${await browserSiteReference(scope, site)}`);
|
|
4692
4759
|
}
|
|
4693
4760
|
async function moveBrowserProfileSite(scope, site, to) {
|
|
4694
|
-
|
|
4761
|
+
const reference = await browserSiteReference(scope, site);
|
|
4762
|
+
const [identifier, query] = reference.split("?");
|
|
4763
|
+
return api("POST", `/browser_profiles/${encodeURIComponent(scope)}/sites/${identifier}/move${query ? `?${query}` : ""}`, { to });
|
|
4695
4764
|
}
|
|
4696
4765
|
function renderBrowserProfileSite(site) {
|
|
4697
4766
|
const who = site.signed_in_by?.email ?? site.signed_in_by?.name ?? "unknown";
|
|
4698
4767
|
const used = site.last_used_at ? `used ${site.last_used_at.slice(0, 10)}` : "never used";
|
|
4699
|
-
return `${site.site.padEnd(40)} ${site.status.padEnd(14)} ${who} ${used}`;
|
|
4768
|
+
return `${site.site.padEnd(40)} ${site.status.padEnd(14)} ${who} ${used}${site.status === "removing" && site.site_id ? ` retry with site ID ${site.site_id}` : ""}`;
|
|
4700
4769
|
}
|
|
4701
4770
|
function renderBrowserProfile(profile) {
|
|
4702
4771
|
const lines = [`scope: ${profile.scope} revision: ${profile.revision} sites: ${profile.sites.length}`];
|
|
@@ -4737,7 +4806,7 @@ function renderThreadSummary(t) {
|
|
|
4737
4806
|
}
|
|
4738
4807
|
|
|
4739
4808
|
// src/harness.ts
|
|
4740
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as
|
|
4809
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
|
|
4741
4810
|
import { dirname as dirname8, join as join16, resolve as resolve8 } from "path";
|
|
4742
4811
|
var HARNESS_FILE = "harness.json";
|
|
4743
4812
|
function harnessFilePath(dir) {
|
|
@@ -4749,7 +4818,7 @@ function readHarnessFile(dir) {
|
|
|
4749
4818
|
throw new Error(`no ${HARNESS_FILE} found in ${resolve8(dir)} \u2014 run \`sky harness init\` first`);
|
|
4750
4819
|
}
|
|
4751
4820
|
try {
|
|
4752
|
-
return JSON.parse(
|
|
4821
|
+
return JSON.parse(readFileSync15(path, "utf8"));
|
|
4753
4822
|
} catch (err) {
|
|
4754
4823
|
throw new Error(`could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
4755
4824
|
}
|
|
@@ -4780,7 +4849,7 @@ function harnessInit(dir) {
|
|
|
4780
4849
|
throw new Error(`${path} already exists \u2014 delete it to re-init`);
|
|
4781
4850
|
}
|
|
4782
4851
|
mkdirSync5(dirname8(path), { recursive: true });
|
|
4783
|
-
|
|
4852
|
+
writeFileSync8(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
|
|
4784
4853
|
`);
|
|
4785
4854
|
console.log(`Created ${path}`);
|
|
4786
4855
|
console.log(INIT_COMMENT);
|
|
@@ -5239,12 +5308,15 @@ session.command("create <agent>").description("create a session (starts provisio
|
|
|
5239
5308
|
}
|
|
5240
5309
|
)
|
|
5241
5310
|
);
|
|
5242
|
-
session.command("list [agent]").action(
|
|
5243
|
-
run(async (agentRef) => {
|
|
5244
|
-
const
|
|
5245
|
-
|
|
5311
|
+
session.command("list [agent]").option("--limit <n>", "how many of the newest sessions to list (1-500)", "100").option("--cursor <cursor>", "continue from the cursor a previous page printed").action(
|
|
5312
|
+
run(async (agentRef, opts = {}) => {
|
|
5313
|
+
const params = new URLSearchParams();
|
|
5314
|
+
if (agentRef) params.set("agent", agentRef);
|
|
5315
|
+
if (opts.limit) params.set("limit", opts.limit);
|
|
5316
|
+
if (opts.cursor) params.set("cursor", opts.cursor);
|
|
5317
|
+
const { sessions, next_cursor } = await api("GET", `/sessions?${params}`);
|
|
5246
5318
|
if (!sessions.length) {
|
|
5247
|
-
console.log("No sessions. `sky session create <agent>` to start one.");
|
|
5319
|
+
console.log(opts.cursor ? "No more sessions." : "No sessions. `sky session create <agent>` to start one.");
|
|
5248
5320
|
return;
|
|
5249
5321
|
}
|
|
5250
5322
|
for (const s of sessions) {
|
|
@@ -5252,6 +5324,7 @@ session.command("list [agent]").action(
|
|
|
5252
5324
|
`${s.id.padEnd(24)} ${(s.agentId ?? "-").padEnd(20)} ${(s.title ?? "").padEnd(16)} ${s.status}${s.default ? " *" : ""}`
|
|
5253
5325
|
);
|
|
5254
5326
|
}
|
|
5327
|
+
if (next_cursor) console.log(` more: sky session list${agentRef ? ` ${agentRef}` : ""} --cursor ${next_cursor}`);
|
|
5255
5328
|
})
|
|
5256
5329
|
);
|
|
5257
5330
|
session.command("show <id>").action(
|
|
@@ -5485,7 +5558,7 @@ sessionWorkspace.command("cat <ref> <path>").description("print a file (up to 1
|
|
|
5485
5558
|
run(async (ref, path, opts) => {
|
|
5486
5559
|
const bytes = await readFile(await resolveSessionRef(ref), path);
|
|
5487
5560
|
if (opts.out) {
|
|
5488
|
-
|
|
5561
|
+
writeFileSync9(opts.out, bytes);
|
|
5489
5562
|
console.error(`saved ${bytes.length} bytes to ${opts.out}`);
|
|
5490
5563
|
} else process.stdout.write(bytes);
|
|
5491
5564
|
})
|
|
@@ -5502,7 +5575,7 @@ sessionWorkspace.command("patch <ref> [repo]").description("the work in a reposi
|
|
|
5502
5575
|
console.error(`${meta.repo}: ${meta.commits.length} commit${meta.commits.length === 1 ? "" : "s"} since ${meta.base_branch || "the imported copy"} (${meta.base_commit.slice(0, 12)})`);
|
|
5503
5576
|
if (!patch.length) console.error("nothing changed");
|
|
5504
5577
|
else if (opts.out) {
|
|
5505
|
-
|
|
5578
|
+
writeFileSync9(opts.out, patch);
|
|
5506
5579
|
console.error(`wrote ${opts.out} \u2014 apply with: git apply ${opts.out}`);
|
|
5507
5580
|
} else process.stdout.write(patch);
|
|
5508
5581
|
})
|
|
@@ -6010,14 +6083,14 @@ task.command("get <task> <path>").description("read one task file; prints it, or
|
|
|
6010
6083
|
run(async (taskId, path, opts) => {
|
|
6011
6084
|
const bytes = await readTaskFile(taskId, path);
|
|
6012
6085
|
if (opts.out) {
|
|
6013
|
-
|
|
6086
|
+
writeFileSync9(opts.out, bytes);
|
|
6014
6087
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
6015
6088
|
} else process.stdout.write(bytes);
|
|
6016
6089
|
})
|
|
6017
6090
|
);
|
|
6018
6091
|
task.command("put <task> <path> <local>").description("write a local file to <path> in the task's files (every session of the task sees it)").action(
|
|
6019
6092
|
run(async (taskId, path, local) => {
|
|
6020
|
-
const { file, conflict } = await writeTaskFile(taskId, path,
|
|
6093
|
+
const { file, conflict } = await writeTaskFile(taskId, path, readFileSync16(local), mediaTypeFor(local));
|
|
6021
6094
|
console.log(`${renderTaskFile(file)}${conflict ? " (replaced a version you had not seen)" : ""}`);
|
|
6022
6095
|
})
|
|
6023
6096
|
);
|
|
@@ -6171,7 +6244,7 @@ artifact.command("get <id> <path>").description("read one file of an artifact; p
|
|
|
6171
6244
|
run(async (id, path, opts) => {
|
|
6172
6245
|
const bytes = await readArtifactFile(id, path);
|
|
6173
6246
|
if (opts.out) {
|
|
6174
|
-
|
|
6247
|
+
writeFileSync9(opts.out, bytes);
|
|
6175
6248
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
6176
6249
|
} else process.stdout.write(bytes);
|
|
6177
6250
|
})
|
|
@@ -6469,7 +6542,7 @@ usageOptions(
|
|
|
6469
6542
|
run(async (opts) => {
|
|
6470
6543
|
const { bytes } = await apiBytes("GET", `/billing/usage/export${usageQuery(opts)}`);
|
|
6471
6544
|
if (opts.out) {
|
|
6472
|
-
|
|
6545
|
+
writeFileSync9(opts.out, bytes);
|
|
6473
6546
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
6474
6547
|
} else {
|
|
6475
6548
|
process.stdout.write(bytes);
|
|
@@ -6543,7 +6616,7 @@ webhook.command("list").action(
|
|
|
6543
6616
|
for (const w of webhooks) console.log(webhookLine(w));
|
|
6544
6617
|
})
|
|
6545
6618
|
);
|
|
6546
|
-
webhook.command("create <url>").description("register an endpoint; its signing secret is printed once").requiredOption("--event <type...>", "event types to deliver, e.g. goal.completed routine_run.failed").action(
|
|
6619
|
+
webhook.command("create <url>").description("register an endpoint; its signing secret is printed once").requiredOption("--event <type...>", "event types to deliver, e.g. goal.completed routine_run.failed connector.connected connector.granted").action(
|
|
6547
6620
|
run(async (url, opts) => {
|
|
6548
6621
|
const { webhook: created } = await api("POST", "/webhooks", { url, events: opts.event });
|
|
6549
6622
|
console.error(webhookLine(created));
|
|
@@ -6587,6 +6660,9 @@ channel.command("bind <connectionId>").description("route a connection to a sess
|
|
|
6587
6660
|
console.log(`${connectionId} \u2192 ${opts.session ?? opts.webhook}`);
|
|
6588
6661
|
})
|
|
6589
6662
|
);
|
|
6663
|
+
channel.command("history <threadId>").description("read one authorized history page; provider history or retained SDK cache, never an agent turn").option("--limit <count>", "messages per page (1..50)", "20").option("--cursor <cursor>", "opaque next_cursor returned for this thread and page size").action(run(async (threadId, opts) => {
|
|
6664
|
+
console.log(JSON.stringify(await history(threadId, opts), null, 2));
|
|
6665
|
+
}));
|
|
6590
6666
|
channel.command("send <threadId> <text...>").description("post a markdown message into a connected thread").action(
|
|
6591
6667
|
run(async (threadId, text) => {
|
|
6592
6668
|
await send(threadId, text.join(" "));
|
|
@@ -6672,6 +6748,35 @@ connector.command("unshare <connectionId>").description("stop sharing a connecti
|
|
|
6672
6748
|
console.log(`Stopped sharing ${connectionId} with ${slug}`);
|
|
6673
6749
|
})
|
|
6674
6750
|
);
|
|
6751
|
+
var grantLine = (g) => `${g.id} \u2192 ${g.workspace.slug} ${g.key ? `key ${g.key.name} (${g.key.id})` : "every key"} since ${g.created_at.slice(0, 10)} ${g.use_count} call${g.use_count === 1 ? "" : "s"}`;
|
|
6752
|
+
connector.command("grant <connectionId>").description("let a workspace's API keys call through one of your connections (POST /connectors/proxy)").option("--key <id>", "only this key of the workspace, instead of every key").option("--universe <slug>", "the workspace (default: the current one)").action(
|
|
6753
|
+
run(async (connectionId, opts) => {
|
|
6754
|
+
const slug = await workspaceSlug(opts.universe);
|
|
6755
|
+
const { grant } = await api("POST", `/connectors/connections/${encodeURIComponent(connectionId)}/grants`, opts.key ? { key_id: opts.key } : {}, { universe: slug });
|
|
6756
|
+
console.log(`Granted ${connectionId} to ${grant.key ? `key ${grant.key.name}` : "every key"} of ${slug}`);
|
|
6757
|
+
})
|
|
6758
|
+
);
|
|
6759
|
+
connector.command("revoke <connectionId>").description("take a grant back; the service loses the connection at once").option("--key <id>", "the grant for this one key, instead of the workspace-wide one").option("--universe <slug>", "the workspace (default: the current one)").action(
|
|
6760
|
+
run(async (connectionId, opts) => {
|
|
6761
|
+
const slug = await workspaceSlug(opts.universe);
|
|
6762
|
+
await api("DELETE", `/connectors/connections/${encodeURIComponent(connectionId)}/grants`, opts.key ? { key_id: opts.key } : {}, { universe: slug });
|
|
6763
|
+
console.log(`Revoked ${connectionId} from ${opts.key ? `key ${opts.key}` : "every key"} of ${slug}`);
|
|
6764
|
+
})
|
|
6765
|
+
);
|
|
6766
|
+
connector.command("grants <connectionId>").description("who may call through one of your connections with a key, and how often they did").action(
|
|
6767
|
+
run(async (connectionId) => {
|
|
6768
|
+
const { grants } = await api("GET", `/connectors/connections/${encodeURIComponent(connectionId)}/grants`);
|
|
6769
|
+
if (!grants.length) console.log("no grants \u2014 `sky connector grant <connectionId> --universe <slug>`");
|
|
6770
|
+
for (const g of grants) console.log(grantLine(g));
|
|
6771
|
+
})
|
|
6772
|
+
);
|
|
6773
|
+
connector.command("granted").description("connections other people let this key call through").action(
|
|
6774
|
+
run(async () => {
|
|
6775
|
+
const { connections } = await api("GET", "/connectors/connections?granted=true");
|
|
6776
|
+
if (!connections.length) console.log("nothing is granted to this key");
|
|
6777
|
+
for (const c of connections) console.log(`${connectionLine2(c)} owner ${c.owner_user_id}${c.grant.key_id ? "" : " (workspace-wide)"}`);
|
|
6778
|
+
})
|
|
6779
|
+
);
|
|
6675
6780
|
connector.command("shared").description("everything you share with workspaces, and the calls made through each").action(
|
|
6676
6781
|
run(async () => {
|
|
6677
6782
|
const { shared } = await api("GET", "/shared-connections");
|
|
@@ -6988,7 +7093,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
|
|
|
6988
7093
|
}));
|
|
6989
7094
|
var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
|
|
6990
7095
|
traceCmd.command("start").description("start a trace: a grant for this machine, a root span, and the spool the hooks write to").option("--name <name>", "a name for the task").option("--source <source>", "how this machine reports itself", "claude-code").option("--hooks [settings]", "also install the Claude Code hooks (default: ./.claude/settings.local.json)").option("--capture <scopes>", "also send content, redacted on this machine first: any of prompts,tool_output,files").option("--file <path>", "a file the files scope may send (repeatable)", collect).option("--dir <path>", "a folder whose files the files scope may send when a file tool touches them (repeatable)", collect).action(run(async (opts) => {
|
|
6991
|
-
const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-
|
|
7096
|
+
const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-HTWXINXI.js");
|
|
6992
7097
|
if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
|
|
6993
7098
|
const scopes = parseContentScopes(opts.capture);
|
|
6994
7099
|
const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
|
|
@@ -7023,7 +7128,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
|
|
|
7023
7128
|
}));
|
|
7024
7129
|
traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
|
|
7025
7130
|
try {
|
|
7026
|
-
const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-
|
|
7131
|
+
const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-HTWXINXI.js");
|
|
7027
7132
|
const chunks = [];
|
|
7028
7133
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
7029
7134
|
const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
|
@@ -7036,14 +7141,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
|
|
|
7036
7141
|
}
|
|
7037
7142
|
});
|
|
7038
7143
|
traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
|
|
7039
|
-
const { readState, flush, grantSender } = await import("./trace-
|
|
7144
|
+
const { readState, flush, grantSender } = await import("./trace-HTWXINXI.js");
|
|
7040
7145
|
const state = readState();
|
|
7041
7146
|
if (!state) throw new Error("no trace is running here");
|
|
7042
7147
|
const outcome = await flush(grantSender(state), { attempts: 4 });
|
|
7043
7148
|
console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
|
|
7044
7149
|
}));
|
|
7045
7150
|
traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
|
|
7046
|
-
const { readState, spoolStatus } = await import("./trace-
|
|
7151
|
+
const { readState, spoolStatus } = await import("./trace-HTWXINXI.js");
|
|
7047
7152
|
const state = readState();
|
|
7048
7153
|
if (!state) {
|
|
7049
7154
|
console.log("No trace is running here.");
|
|
@@ -7053,7 +7158,7 @@ traceCmd.command("status").description("the running trace and its spool").action
|
|
|
7053
7158
|
console.log(`${state.trace_id} as ${state.source}: ${spool.pending} pending, ${spool.dropped_full} dropped (spool full), ${spool.dropped_expired} given up, ${spool.refused} refused`);
|
|
7054
7159
|
}));
|
|
7055
7160
|
traceCmd.command("show [id]").description("the trace bundle: spans, the sessions they reach, cost counted once per session").option("--json", "print the bundle as JSON").action(run(async (id, opts) => {
|
|
7056
|
-
const { readState } = await import("./trace-
|
|
7161
|
+
const { readState } = await import("./trace-HTWXINXI.js");
|
|
7057
7162
|
const ref = id ?? readState()?.trace_id;
|
|
7058
7163
|
if (!ref) throw new Error("name a trace, or start one here");
|
|
7059
7164
|
const bundle = await api("GET", `/traces/${ref}`);
|
|
@@ -7080,7 +7185,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
|
|
|
7080
7185
|
for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
|
|
7081
7186
|
}));
|
|
7082
7187
|
traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
|
|
7083
|
-
const { readState, record, flush, grantSender, clearState } = await import("./trace-
|
|
7188
|
+
const { readState, record, flush, grantSender, clearState } = await import("./trace-HTWXINXI.js");
|
|
7084
7189
|
const state = readState();
|
|
7085
7190
|
if (!state) throw new Error("no trace is running here");
|
|
7086
7191
|
if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
|
|
@@ -7090,7 +7195,7 @@ traceCmd.command("stop").description("end the root span, send what is left, and
|
|
|
7090
7195
|
console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
|
|
7091
7196
|
}));
|
|
7092
7197
|
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) => {
|
|
7093
|
-
const lib = await import("./trace-library-
|
|
7198
|
+
const lib = await import("./trace-library-QR54Q4Z3.js");
|
|
7094
7199
|
if (opts.hook) {
|
|
7095
7200
|
try {
|
|
7096
7201
|
let raw = payload ?? "";
|
|
@@ -7151,11 +7256,11 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
|
|
|
7151
7256
|
console.log(`Sweeping every 15 minutes (${plist}); a full re-read runs weekly. Log: ${log}`);
|
|
7152
7257
|
}
|
|
7153
7258
|
if (opts.status) {
|
|
7154
|
-
const { readFileSync:
|
|
7259
|
+
const { readFileSync: readFileSync17 } = await import("fs");
|
|
7155
7260
|
const { join: join17 } = await import("path");
|
|
7156
7261
|
let state = { sessions: {} };
|
|
7157
7262
|
try {
|
|
7158
|
-
state = JSON.parse(
|
|
7263
|
+
state = JSON.parse(readFileSync17(join17(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
|
|
7159
7264
|
} catch {
|
|
7160
7265
|
}
|
|
7161
7266
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -7188,7 +7293,7 @@ traceCmd.command("sync [payload]").description("upload this machine's Claude Cod
|
|
|
7188
7293
|
})();
|
|
7189
7294
|
});
|
|
7190
7295
|
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) => {
|
|
7191
|
-
const { libraryRequest } = await import("./trace-library-
|
|
7296
|
+
const { libraryRequest } = await import("./trace-library-QR54Q4Z3.js");
|
|
7192
7297
|
const workspace2 = opts.workspace ?? currentUniverse();
|
|
7193
7298
|
if (!workspace2) throw new Error("name a workspace with --workspace");
|
|
7194
7299
|
const params = new URLSearchParams({ q: words.join(" "), scope: "traces", limit: String(opts.limit), ...opts.cursor ? { cursor: opts.cursor } : {} });
|
|
@@ -7205,7 +7310,7 @@ traceCmd.command("search <query...>").description("search every session in a wor
|
|
|
7205
7310
|
if (page.nextCursor) console.log(`More: sky trace search ${JSON.stringify(words.join(" "))} --workspace ${workspace2} --cursor ${page.nextCursor}`);
|
|
7206
7311
|
}));
|
|
7207
7312
|
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) => {
|
|
7208
|
-
const { libraryRequest } = await import("./trace-library-
|
|
7313
|
+
const { libraryRequest } = await import("./trace-library-QR54Q4Z3.js");
|
|
7209
7314
|
const workspace2 = opts.workspace ?? currentUniverse();
|
|
7210
7315
|
if (!workspace2) throw new Error("name a workspace with --workspace");
|
|
7211
7316
|
const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);
|