@agentsky/sky 2.4.0 → 2.5.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.
|
@@ -18984,7 +18984,8 @@ var MODEL_REASONING_EFFORTS = {
|
|
|
18984
18984
|
"gemini-3.5-flash": ["low", "medium", "high"],
|
|
18985
18985
|
"glm-5.3": ["low", "high", "max"],
|
|
18986
18986
|
"glm-5.3-flash": ["low", "high", "max"],
|
|
18987
|
-
"grok-4.6": ["low", "medium", "high"]
|
|
18987
|
+
"grok-4.6": ["low", "medium", "high"],
|
|
18988
|
+
"grok-4.7": ["low", "medium", "high", "xhigh"]
|
|
18988
18989
|
};
|
|
18989
18990
|
var REASONING_EFFORTS = {
|
|
18990
18991
|
agoragentic_acp: null,
|
|
@@ -21200,6 +21201,10 @@ var questionSchema = external_exports.object({
|
|
|
21200
21201
|
blocksGoal: external_exports.boolean().optional(),
|
|
21201
21202
|
/** Informational deadline. Passing it never approves or answers the question. */
|
|
21202
21203
|
dueAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
21204
|
+
/** Hard permission deadline; unlike dueAt, later answers are refused. */
|
|
21205
|
+
expiresAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
21206
|
+
/** The owner withdrew this question. Never a human answer or consent. */
|
|
21207
|
+
cancelledAt: external_exports.string().datetime({ offset: true }).optional(),
|
|
21203
21208
|
/** What the platform is asking for when the question is one of its own
|
|
21204
21209
|
* requests rather than an agent's free question. Absent on an ordinary question. */
|
|
21205
21210
|
kind: external_exports.enum(QUESTION_REQUEST_KINDS).optional(),
|
|
@@ -22151,11 +22156,38 @@ function isCompatible(agentType, llm) {
|
|
|
22151
22156
|
function defaultLlm(agentType) {
|
|
22152
22157
|
return allowedLlms[agentType][0];
|
|
22153
22158
|
}
|
|
22159
|
+
var CHATGPT_PLAN_MODELS = /* @__PURE__ */ new Set([
|
|
22160
|
+
"gpt-6-astra",
|
|
22161
|
+
"gpt-5.6-sol",
|
|
22162
|
+
"gpt-5.6-terra",
|
|
22163
|
+
"gpt-5.6-luna",
|
|
22164
|
+
"gpt-5.5"
|
|
22165
|
+
]);
|
|
22166
|
+
var CLAUDE_PLAN_MODELS = /* @__PURE__ */ new Set([
|
|
22167
|
+
"claude-opus-5",
|
|
22168
|
+
"claude-fable-5-1",
|
|
22169
|
+
"claude-sonnet-5",
|
|
22170
|
+
"claude-haiku-4-5",
|
|
22171
|
+
"claude-sonnet-4-6",
|
|
22172
|
+
"claude-opus-4-8",
|
|
22173
|
+
"claude-fable-5"
|
|
22174
|
+
]);
|
|
22154
22175
|
function modelSubscriptionProviderFor(agentType, llm) {
|
|
22155
|
-
if (agentType === "claude_code" &&
|
|
22156
|
-
if (agentType === "codex" &&
|
|
22176
|
+
if (agentType === "claude_code" && CLAUDE_PLAN_MODELS.has(llm)) return "anthropic";
|
|
22177
|
+
if (agentType === "codex" && CHATGPT_PLAN_MODELS.has(llm)) return "openai";
|
|
22178
|
+
if (agentType === "cursor" && llm === "harness-default") return "cursor";
|
|
22157
22179
|
return null;
|
|
22158
22180
|
}
|
|
22181
|
+
var MODEL_SUBSCRIPTION_PROVIDER_NAME = {
|
|
22182
|
+
anthropic: "Claude",
|
|
22183
|
+
openai: "ChatGPT",
|
|
22184
|
+
cursor: "Cursor"
|
|
22185
|
+
};
|
|
22186
|
+
var MODEL_SUBSCRIPTION_PLAN_PHRASE = {
|
|
22187
|
+
anthropic: "Claude subscription",
|
|
22188
|
+
openai: "ChatGPT plan",
|
|
22189
|
+
cursor: "Cursor plan"
|
|
22190
|
+
};
|
|
22159
22191
|
var AGENT_TYPE_META = {
|
|
22160
22192
|
...Object.fromEntries(ACP_AGENT_TYPES.map((agentType) => [agentType, {
|
|
22161
22193
|
label: ACP_AGENTS[agentType].label,
|
|
@@ -22250,8 +22282,7 @@ var skillRefSchema = external_exports.discriminatedUnion("type", [
|
|
|
22250
22282
|
storeSkillRefSchema,
|
|
22251
22283
|
githubSkillRefSchema
|
|
22252
22284
|
]);
|
|
22253
|
-
var
|
|
22254
|
-
var skillsArraySchema = external_exports.array(skillRefSchema).max(MAX_SKILLS_PER_AGENT, `At most ${MAX_SKILLS_PER_AGENT} skills per agent.`).superRefine((arr, ctx) => {
|
|
22285
|
+
var skillsArraySchema = external_exports.array(skillRefSchema).superRefine((arr, ctx) => {
|
|
22255
22286
|
const targets = arr.map((s) => s.type === "skill" ? `skill:${s.skillId}` : `github:${s.url}`);
|
|
22256
22287
|
if (new Set(targets).size !== targets.length) {
|
|
22257
22288
|
ctx.addIssue({ code: "custom", message: "Duplicate skill entries." });
|
|
@@ -22312,6 +22343,50 @@ var hookSchema = external_exports.object({
|
|
|
22312
22343
|
path: ["matcher"]
|
|
22313
22344
|
});
|
|
22314
22345
|
var hooksSchema = external_exports.array(hookSchema).max(20);
|
|
22346
|
+
var POLICY_ACTIONS = ["allow", "ask", "deny"];
|
|
22347
|
+
var toolCallPolicyConfigSchema = external_exports.object({
|
|
22348
|
+
action: external_exports.enum(POLICY_ACTIONS),
|
|
22349
|
+
matcher: external_exports.string().min(1).max(255).refine((v) => /^(?:[A-Za-z0-9_:.-]|\.\*)+(?:\|(?:[A-Za-z0-9_:.-]|\.\*)+)*$/.test(v), {
|
|
22350
|
+
message: "matcher must be tool names or patterns separated by |"
|
|
22351
|
+
}).optional(),
|
|
22352
|
+
commandPatterns: external_exports.array(external_exports.string().min(1).max(500)).max(20).optional()
|
|
22353
|
+
}).strict();
|
|
22354
|
+
var spendCapPolicyConfigSchema = external_exports.object({
|
|
22355
|
+
warnUsdMicros: external_exports.number().int().min(0).nullish(),
|
|
22356
|
+
hardCapUsdMicros: external_exports.number().int().min(1)
|
|
22357
|
+
}).strict().refine((c) => !c.warnUsdMicros || c.warnUsdMicros < c.hardCapUsdMicros, {
|
|
22358
|
+
message: "warnUsdMicros must be less than hardCapUsdMicros"
|
|
22359
|
+
});
|
|
22360
|
+
var callCountPolicyConfigSchema = external_exports.object({ limitPerSession: external_exports.number().int().min(1).max(1e5) }).strict();
|
|
22361
|
+
var capabilityPolicyConfigSchema = external_exports.record(external_exports.string(), external_exports.enum(POLICY_ACTIONS)).superRefine((obj, ctx) => {
|
|
22362
|
+
for (const k of Object.keys(obj)) {
|
|
22363
|
+
if (!CAPABILITY_IDS.includes(k)) {
|
|
22364
|
+
ctx.addIssue({ code: "custom", message: `unknown capability id: ${k}`, path: [k] });
|
|
22365
|
+
}
|
|
22366
|
+
}
|
|
22367
|
+
});
|
|
22368
|
+
var policyRuleBaseSchema = external_exports.object({
|
|
22369
|
+
name: external_exports.string().min(1).max(128),
|
|
22370
|
+
enabled: external_exports.boolean().default(true),
|
|
22371
|
+
position: external_exports.number().int().min(0).max(9999).default(0)
|
|
22372
|
+
});
|
|
22373
|
+
var policyRuleSchema = external_exports.discriminatedUnion("kind", [
|
|
22374
|
+
policyRuleBaseSchema.extend({ kind: external_exports.literal("TOOL_CALL"), config: toolCallPolicyConfigSchema }),
|
|
22375
|
+
policyRuleBaseSchema.extend({ kind: external_exports.literal("SPEND_CAP"), config: spendCapPolicyConfigSchema }),
|
|
22376
|
+
policyRuleBaseSchema.extend({ kind: external_exports.literal("CALL_COUNT"), config: callCountPolicyConfigSchema }),
|
|
22377
|
+
policyRuleBaseSchema.extend({ kind: external_exports.literal("CAPABILITY"), config: capabilityPolicyConfigSchema })
|
|
22378
|
+
]);
|
|
22379
|
+
var policyRulePatchSchema = external_exports.object({
|
|
22380
|
+
name: external_exports.string().min(1).max(128).optional(),
|
|
22381
|
+
enabled: external_exports.boolean().optional(),
|
|
22382
|
+
position: external_exports.number().int().min(0).max(9999).optional(),
|
|
22383
|
+
config: external_exports.union([
|
|
22384
|
+
toolCallPolicyConfigSchema,
|
|
22385
|
+
spendCapPolicyConfigSchema,
|
|
22386
|
+
callCountPolicyConfigSchema,
|
|
22387
|
+
capabilityPolicyConfigSchema
|
|
22388
|
+
]).optional()
|
|
22389
|
+
});
|
|
22315
22390
|
var packagesSchema = external_exports.object({
|
|
22316
22391
|
apt: external_exports.array(packageNameSchema).max(32).default([]),
|
|
22317
22392
|
pip: external_exports.array(packageNameSchema).max(32).default([]),
|
|
@@ -22351,6 +22426,7 @@ var capabilityPoliciesSchema = external_exports.record(
|
|
|
22351
22426
|
capabilityIdInputSchema,
|
|
22352
22427
|
capabilityPermissionPolicySchema
|
|
22353
22428
|
);
|
|
22429
|
+
var nativeToolPolicySchema = external_exports.enum(["always_allow", "always_ask"]);
|
|
22354
22430
|
var publishSchema = external_exports.object({
|
|
22355
22431
|
name: external_exports.string().trim().min(1, "Give your agent a name."),
|
|
22356
22432
|
description: external_exports.string().default(""),
|
|
@@ -22398,6 +22474,8 @@ export {
|
|
|
22398
22474
|
supersededBy,
|
|
22399
22475
|
defaultLlm,
|
|
22400
22476
|
modelSubscriptionProviderFor,
|
|
22477
|
+
MODEL_SUBSCRIPTION_PROVIDER_NAME,
|
|
22478
|
+
MODEL_SUBSCRIPTION_PLAN_PHRASE,
|
|
22401
22479
|
capabilitiesSchema,
|
|
22402
22480
|
instructionFileSchema,
|
|
22403
22481
|
skillRefSchema,
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
AGENT_TYPES,
|
|
4
|
+
MODEL_SUBSCRIPTION_PLAN_PHRASE,
|
|
5
|
+
MODEL_SUBSCRIPTION_PROVIDER_NAME,
|
|
4
6
|
REASONING_EFFORT_VALUES,
|
|
5
7
|
capabilitiesSchema,
|
|
6
8
|
customDataSchema,
|
|
@@ -14,10 +16,10 @@ import {
|
|
|
14
16
|
skillRefSchema,
|
|
15
17
|
splitMcpServers,
|
|
16
18
|
supersededBy
|
|
17
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-MHL5Z6IQ.js";
|
|
18
20
|
|
|
19
21
|
// src/index.ts
|
|
20
|
-
import { existsSync as
|
|
22
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
21
23
|
import { basename as basename3, resolve as resolve3 } from "path";
|
|
22
24
|
import { createInterface as createInterface3 } from "readline";
|
|
23
25
|
import { Command } from "commander";
|
|
@@ -62,7 +64,7 @@ function currentUniverse() {
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
// src/version.ts
|
|
65
|
-
var CLI_VERSION = "2.
|
|
67
|
+
var CLI_VERSION = "2.5.0";
|
|
66
68
|
var USER_AGENT = `sky-cli/${CLI_VERSION} (${process.platform}; node/${process.versions.node})`;
|
|
67
69
|
|
|
68
70
|
// src/api.ts
|
|
@@ -165,7 +167,7 @@ async function resolveSessionRef(ref) {
|
|
|
165
167
|
return agent2.defaultSessionId;
|
|
166
168
|
}
|
|
167
169
|
async function* streamEvents(sessionId, signal) {
|
|
168
|
-
const { parseSseStream } = await import("./src-
|
|
170
|
+
const { parseSseStream } = await import("./src-GLBJHVIJ.js");
|
|
169
171
|
const res = await fetch(
|
|
170
172
|
`${apiBase()}/sessions/${encodeURIComponent(sessionId)}/stream`,
|
|
171
173
|
{
|
|
@@ -1073,6 +1075,33 @@ async function headlessLogin(verifier, challenge) {
|
|
|
1073
1075
|
throw new Error("login timed out after 10 minutes");
|
|
1074
1076
|
}
|
|
1075
1077
|
|
|
1078
|
+
// src/local-agents.ts
|
|
1079
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1080
|
+
import { homedir as homedir4 } from "os";
|
|
1081
|
+
import { join as join4 } from "path";
|
|
1082
|
+
function localAgents(env = process.env, home = homedir4()) {
|
|
1083
|
+
const claude = env.CLAUDE_CONFIG_DIR || join4(home, ".claude");
|
|
1084
|
+
const codex = env.CODEX_HOME || join4(home, ".codex");
|
|
1085
|
+
const cursor = join4(home, ".cursor");
|
|
1086
|
+
return [
|
|
1087
|
+
{ id: "claude_code", name: "Claude Code", root: claude, skillsDir: join4(claude, "skills") },
|
|
1088
|
+
{ id: "codex", name: "Codex", root: codex, skillsDir: join4(codex, "skills") },
|
|
1089
|
+
{ id: "cursor", name: "Cursor", root: cursor, skillsDir: join4(cursor, "skills") }
|
|
1090
|
+
];
|
|
1091
|
+
}
|
|
1092
|
+
function detectLocalAgents(env = process.env, home = homedir4()) {
|
|
1093
|
+
return localAgents(env, home).filter((agent2) => existsSync4(agent2.root));
|
|
1094
|
+
}
|
|
1095
|
+
function selectLocalAgents(ids, env = process.env, home = homedir4()) {
|
|
1096
|
+
if (!ids?.length) return detectLocalAgents(env, home);
|
|
1097
|
+
const known = localAgents(env, home);
|
|
1098
|
+
return ids.map((id) => {
|
|
1099
|
+
const agent2 = known.find((candidate) => candidate.id === id);
|
|
1100
|
+
if (!agent2) throw new Error(`unknown agent ${id} \u2014 expected ${known.map((candidate) => candidate.id).join(" | ")}`);
|
|
1101
|
+
return agent2;
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1076
1105
|
// src/render.ts
|
|
1077
1106
|
var dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
1078
1107
|
var red = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
@@ -1116,11 +1145,159 @@ function renderEvent(event, data) {
|
|
|
1116
1145
|
}
|
|
1117
1146
|
}
|
|
1118
1147
|
|
|
1148
|
+
// src/session-read.ts
|
|
1149
|
+
var TURN_TYPES = ["user.message", "agent.message", "session.status_idle", "session.status_terminated", "session.error"];
|
|
1150
|
+
function latestTurn(events) {
|
|
1151
|
+
let start = 0;
|
|
1152
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
1153
|
+
if (events[index].type === "user.message") {
|
|
1154
|
+
start = index + 1;
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
const reading = { finished: false, messages: [], errors: [] };
|
|
1159
|
+
for (const event of events.slice(start)) {
|
|
1160
|
+
if (event.type === "agent.message" && event.text?.trim()) reading.messages.push(event.text);
|
|
1161
|
+
else if (event.type === "session.error" && event.error?.retry_status !== "retrying") {
|
|
1162
|
+
reading.errors.push(event.error?.message ?? event.error?.type ?? "unknown error");
|
|
1163
|
+
} else if (event.type === "session.status_terminated") reading.finished = true;
|
|
1164
|
+
else if (event.type === "session.status_idle" && event.stop_reason?.type !== "requires_action") reading.finished = true;
|
|
1165
|
+
}
|
|
1166
|
+
return reading;
|
|
1167
|
+
}
|
|
1168
|
+
async function history(sessionId) {
|
|
1169
|
+
const events = [];
|
|
1170
|
+
let cursor = null;
|
|
1171
|
+
for (; ; ) {
|
|
1172
|
+
const query = new URLSearchParams({ limit: "500" });
|
|
1173
|
+
for (const type of TURN_TYPES) query.append("types[]", type);
|
|
1174
|
+
if (cursor) query.set("cursor", cursor);
|
|
1175
|
+
const page = await api(
|
|
1176
|
+
"GET",
|
|
1177
|
+
`/sessions/${encodeURIComponent(sessionId)}/events?${query}`
|
|
1178
|
+
);
|
|
1179
|
+
events.push(...page.events);
|
|
1180
|
+
if (!page.hasMore || !page.cursor) return events;
|
|
1181
|
+
cursor = page.cursor;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
async function readTurn(sessionId, opts = {}) {
|
|
1185
|
+
const deadline = Date.now() + (opts.timeoutSeconds ?? 600) * 1e3;
|
|
1186
|
+
for (; ; ) {
|
|
1187
|
+
const reading = latestTurn(await history(sessionId));
|
|
1188
|
+
if (reading.finished || !opts.wait || Date.now() >= deadline) return reading;
|
|
1189
|
+
await new Promise((resolve4) => setTimeout(resolve4, opts.intervalMs ?? 3e3));
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// src/skill.ts
|
|
1194
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
1195
|
+
import { join as join5 } from "path";
|
|
1196
|
+
var SKILL_NAME = "agentsky";
|
|
1197
|
+
var SKILL_MARKER = ".agentsky.json";
|
|
1198
|
+
function skillDocument() {
|
|
1199
|
+
return `---
|
|
1200
|
+
name: ${SKILL_NAME}
|
|
1201
|
+
description: Hand part of a job to another agent running in the cloud through AgentSky, and bring its result back. Use when the person asks for another agent or a named engine (Claude Code, Codex, Hermes, OpenClaw and others) to do, test or review something, or when independent work could run in parallel.
|
|
1202
|
+
---
|
|
1203
|
+
|
|
1204
|
+
# Working with other agents through AgentSky
|
|
1205
|
+
|
|
1206
|
+
AgentSky runs long-lived agents in the cloud. With the \`sky\` command you can
|
|
1207
|
+
find one, give it a job, and read what it produced. You stay responsible for
|
|
1208
|
+
the result.
|
|
1209
|
+
|
|
1210
|
+
If the \`agentsky\` MCP tools are available in this session (\`search_catalog\`,
|
|
1211
|
+
\`start_session\`, \`read_session\`, \`send_message\`), use them instead of the
|
|
1212
|
+
commands below; they do the same things.
|
|
1213
|
+
|
|
1214
|
+
## Before you start
|
|
1215
|
+
|
|
1216
|
+
Run \`sky auth whoami\`. If it says you are not logged in, ask the person to run
|
|
1217
|
+
\`sky auth login\` and stop there. Never ask them for a token.
|
|
1218
|
+
|
|
1219
|
+
## When to hand work over
|
|
1220
|
+
|
|
1221
|
+
- When the person asks another agent to do, test or review something, do that.
|
|
1222
|
+
Honor an agent or engine they name.
|
|
1223
|
+
- Otherwise, hand over work another agent is better suited to, or independent
|
|
1224
|
+
parts that can run at the same time as your own.
|
|
1225
|
+
- Do the work yourself when it is small, when it depends on what you already
|
|
1226
|
+
have in front of you, or when explaining it would take as long as doing it.
|
|
1227
|
+
|
|
1228
|
+
## How to pick
|
|
1229
|
+
|
|
1230
|
+
\`sky catalog search <words for the work> --json\`
|
|
1231
|
+
|
|
1232
|
+
Each result has a \`handle\`, what the agent does, its \`engine_type\`, its
|
|
1233
|
+
categories, how it is paid, and what it needs. If the person names an engine,
|
|
1234
|
+
match its \`engine_type\` and do not substitute another one silently. Run the
|
|
1235
|
+
command with no words to see every agent. If nothing fits, do the work
|
|
1236
|
+
yourself and say so.
|
|
1237
|
+
|
|
1238
|
+
## How to brief
|
|
1239
|
+
|
|
1240
|
+
\`sky session create @<handle> --title "<short name>" --message "<brief>" --json\`
|
|
1241
|
+
|
|
1242
|
+
It prints the new session's \`id\`. The agent starts working at once, on its own
|
|
1243
|
+
computer in the cloud. It cannot see this conversation or this machine, so a
|
|
1244
|
+
brief is one self-contained message that states:
|
|
1245
|
+
|
|
1246
|
+
1. what to produce,
|
|
1247
|
+
2. what "done" means,
|
|
1248
|
+
3. anything it must not do.
|
|
1249
|
+
|
|
1250
|
+
To give it a file, add \`--file <path>\`. Never put a password, key or token in a
|
|
1251
|
+
brief.
|
|
1252
|
+
|
|
1253
|
+
## How to collect
|
|
1254
|
+
|
|
1255
|
+
\`sky session read <session id> --wait --json\`
|
|
1256
|
+
|
|
1257
|
+
It waits until the agent finishes its turn and prints its messages, with
|
|
1258
|
+
\`finished\` true or false. If \`finished\` is false the wait timed out: run it
|
|
1259
|
+
again. A first turn can take a minute to begin while the agent's computer
|
|
1260
|
+
starts.
|
|
1261
|
+
|
|
1262
|
+
To correct it, answer it or ask for more:
|
|
1263
|
+
|
|
1264
|
+
\`sky session message <session id> "<text>" --detach\`
|
|
1265
|
+
|
|
1266
|
+
then read again. An agent saying it is done is not evidence: check what it
|
|
1267
|
+
produced before you rely on it.
|
|
1268
|
+
|
|
1269
|
+
## How to finish
|
|
1270
|
+
|
|
1271
|
+
Tell the person what was done and which agent did which part. Every agent you
|
|
1272
|
+
start is paid for by the person, so start only what the job needs.
|
|
1273
|
+
`;
|
|
1274
|
+
}
|
|
1275
|
+
function installedVersion(dir) {
|
|
1276
|
+
try {
|
|
1277
|
+
const marker = JSON.parse(readFileSync6(join5(dir, SKILL_MARKER), "utf8"));
|
|
1278
|
+
return typeof marker.version === "string" ? marker.version : null;
|
|
1279
|
+
} catch {
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
function installSkill(agent2, opts = {}) {
|
|
1284
|
+
const dir = join5(agent2.skillsDir, SKILL_NAME);
|
|
1285
|
+
const previous = installedVersion(dir);
|
|
1286
|
+
const outcome = previous === CLI_VERSION ? "current" : previous ? "updated" : "installed";
|
|
1287
|
+
if (outcome !== "current" && !opts.dryRun) {
|
|
1288
|
+
mkdirSync2(dir, { recursive: true });
|
|
1289
|
+
writeFileSync4(join5(dir, "SKILL.md"), skillDocument());
|
|
1290
|
+
writeFileSync4(join5(dir, SKILL_MARKER), `${JSON.stringify({ version: CLI_VERSION }, null, 2)}
|
|
1291
|
+
`);
|
|
1292
|
+
}
|
|
1293
|
+
return { agent: agent2.id, path: dir, outcome };
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1119
1296
|
// src/subscriptions.ts
|
|
1120
1297
|
import { spawn as spawn3 } from "child_process";
|
|
1121
|
-
import { existsSync as
|
|
1122
|
-
import { homedir as
|
|
1123
|
-
import { join as
|
|
1298
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
|
|
1299
|
+
import { homedir as homedir5 } from "os";
|
|
1300
|
+
import { join as join6 } from "path";
|
|
1124
1301
|
import { createInterface as createInterface2 } from "readline";
|
|
1125
1302
|
var ALIASES = {
|
|
1126
1303
|
claude: "anthropic",
|
|
@@ -1136,6 +1313,14 @@ function providerFor(name) {
|
|
|
1136
1313
|
}
|
|
1137
1314
|
return provider;
|
|
1138
1315
|
}
|
|
1316
|
+
function managedProviderFor(name) {
|
|
1317
|
+
if (name.toLowerCase() === "cursor") return "cursor";
|
|
1318
|
+
const provider = ALIASES[name.toLowerCase()];
|
|
1319
|
+
if (!provider) {
|
|
1320
|
+
throw new ApiError(400, "unknown_provider", `unknown provider "${name}" \u2014 use claude, chatgpt or cursor`);
|
|
1321
|
+
}
|
|
1322
|
+
return provider;
|
|
1323
|
+
}
|
|
1139
1324
|
function ask(question) {
|
|
1140
1325
|
return new Promise((done) => {
|
|
1141
1326
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
@@ -1198,12 +1383,12 @@ async function connectClaude() {
|
|
|
1198
1383
|
console.log(`Connected Claude subscription${expiry}. Powers new eligible agents.`);
|
|
1199
1384
|
}
|
|
1200
1385
|
async function connectChatgpt(opts) {
|
|
1201
|
-
const codexHome = process.env.CODEX_HOME ||
|
|
1202
|
-
const path =
|
|
1203
|
-
if (!
|
|
1386
|
+
const codexHome = process.env.CODEX_HOME || join6(homedir5(), ".codex");
|
|
1387
|
+
const path = join6(codexHome, "auth.json");
|
|
1388
|
+
if (!existsSync5(path)) {
|
|
1204
1389
|
throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
|
|
1205
1390
|
}
|
|
1206
|
-
const raw =
|
|
1391
|
+
const raw = readFileSync7(path, "utf8");
|
|
1207
1392
|
let accountId;
|
|
1208
1393
|
try {
|
|
1209
1394
|
const parsed = JSON.parse(raw);
|
|
@@ -1233,7 +1418,7 @@ async function listSubscriptions() {
|
|
|
1233
1418
|
}
|
|
1234
1419
|
for (const s of modelSubscriptions) {
|
|
1235
1420
|
const bits = [
|
|
1236
|
-
s.provider
|
|
1421
|
+
MODEL_SUBSCRIPTION_PROVIDER_NAME[s.provider].toLowerCase(),
|
|
1237
1422
|
s.status,
|
|
1238
1423
|
s.expiresAt ? `expires ~${s.expiresAt.slice(0, 10)}` : null,
|
|
1239
1424
|
s.lastUsedAt ? `last used ${s.lastUsedAt.slice(0, 10)}` : null,
|
|
@@ -1245,8 +1430,8 @@ async function listSubscriptions() {
|
|
|
1245
1430
|
}
|
|
1246
1431
|
}
|
|
1247
1432
|
async function disconnect(name, opts) {
|
|
1248
|
-
const provider =
|
|
1249
|
-
const label = provider
|
|
1433
|
+
const provider = managedProviderFor(name);
|
|
1434
|
+
const label = MODEL_SUBSCRIPTION_PROVIDER_NAME[provider];
|
|
1250
1435
|
if (!opts.yes) {
|
|
1251
1436
|
const ok = await confirm2(`Disconnect ${label}? Agents running on it will fail until reconnected or switched to Platform.`);
|
|
1252
1437
|
if (!ok) {
|
|
@@ -1272,7 +1457,7 @@ function printModelBilling(session2) {
|
|
|
1272
1457
|
if (session2.modelBilling !== "account") return;
|
|
1273
1458
|
const provider = modelSubscriptionProviderFor(session2.agentType, session2.llm);
|
|
1274
1459
|
if (!provider) return;
|
|
1275
|
-
const label =
|
|
1460
|
+
const label = `your ${MODEL_SUBSCRIPTION_PLAN_PHRASE[provider]}`;
|
|
1276
1461
|
console.log(`Model billing: ${label} \u2014 $0 model usage`);
|
|
1277
1462
|
}
|
|
1278
1463
|
var program = new Command();
|
|
@@ -1445,7 +1630,7 @@ function renderResource(r) {
|
|
|
1445
1630
|
const ref = r.checkout ? `@${r.checkout.type === "branch" ? r.checkout.name : r.checkout.sha}` : "";
|
|
1446
1631
|
return `${r.id} repo ${r.mount_path} ${r.url}${ref}`;
|
|
1447
1632
|
}
|
|
1448
|
-
session.command("create <agent>").description("create a session (starts provisioning by default)").option("--title <title>", "session title").option("--message <text>", "start the first turn immediately, provisioning even with --deferred").option("--deferred", "leave the session idle without a pod until its first turn").option("--vcpus <n>", "machine vCPUs: 1, 2, 4 or 8 (default 2)").option("--memory <mb>", "machine memory in MB, 256MB steps (default 4096)").option("--file <path...>", "mount local files read-only in the working directory: path[:/mount] (uploaded first)").option("--repo <url...>", "clone GitHub repositories into the working directory: https://github.com/{owner}/{repo}[@branch|@sha]").option("--repo-token <token>", "token for the --repo clones; compiled into the sandbox's egress policy, never sent to it").action(
|
|
1633
|
+
session.command("create <agent>").description("create a session (starts provisioning by default)").option("--title <title>", "session title").option("--message <text>", "start the first turn immediately, provisioning even with --deferred").option("--deferred", "leave the session idle without a pod until its first turn").option("--vcpus <n>", "machine vCPUs: 1, 2, 4 or 8 (default 2)").option("--memory <mb>", "machine memory in MB, 256MB steps (default 4096)").option("--file <path...>", "mount local files read-only in the working directory: path[:/mount] (uploaded first)").option("--repo <url...>", "clone GitHub repositories into the working directory: https://github.com/{owner}/{repo}[@branch|@sha]").option("--repo-token <token>", "token for the --repo clones; compiled into the sandbox's egress policy, never sent to it").option("--json", "print the created session as JSON").action(
|
|
1449
1634
|
run(
|
|
1450
1635
|
async (agentRef, opts) => {
|
|
1451
1636
|
const resources = await resourceParams(opts);
|
|
@@ -1458,6 +1643,10 @@ session.command("create <agent>").description("create a session (starts provisio
|
|
|
1458
1643
|
...resources.length ? { resources } : {},
|
|
1459
1644
|
...opts.message ? { initial_events: [{ type: "user.message", content: [{ type: "text", text: opts.message }] }] } : {}
|
|
1460
1645
|
});
|
|
1646
|
+
if (opts.json) {
|
|
1647
|
+
console.log(JSON.stringify(created));
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1461
1650
|
console.log(`Created ${created.id} (${created.agent} \xB7 ${created.status})${created.default ? " [default]" : ""}`);
|
|
1462
1651
|
printModelBilling(created);
|
|
1463
1652
|
for (const r of created.resources ?? []) console.log(` ${renderResource(r)}`);
|
|
@@ -1534,6 +1723,21 @@ session.command("interrupt <ref>").description("abort the in-flight turn").actio
|
|
|
1534
1723
|
console.log(res.status === "no_turn" ? "nothing in flight" : "interrupting");
|
|
1535
1724
|
})
|
|
1536
1725
|
);
|
|
1726
|
+
session.command("read <ref>").description("what the agent has said since the last message it was sent").option("--wait", "wait until the agent finishes its turn").option("--timeout <seconds>", "how long --wait waits (default 600)").option("--json", "print { finished, messages, errors } as JSON").action(
|
|
1727
|
+
run(async (ref, opts) => {
|
|
1728
|
+
const reading = await readTurn(await resolveSessionRef(ref), {
|
|
1729
|
+
wait: opts.wait,
|
|
1730
|
+
...opts.timeout !== void 0 ? { timeoutSeconds: Number(opts.timeout) } : {}
|
|
1731
|
+
});
|
|
1732
|
+
if (opts.json) {
|
|
1733
|
+
console.log(JSON.stringify(reading));
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
for (const message of reading.messages) console.log(message);
|
|
1737
|
+
for (const error of reading.errors) console.error(`error: ${error}`);
|
|
1738
|
+
if (!reading.finished) console.error("The agent is still working. Run this again to read more.");
|
|
1739
|
+
})
|
|
1740
|
+
);
|
|
1537
1741
|
var sessionResources = session.command("resources").description("files and GitHub repositories mounted into a session's working directory");
|
|
1538
1742
|
var resourcesPath = (id) => `/sessions/${encodeURIComponent(id)}/resources`;
|
|
1539
1743
|
sessionResources.command("list <ref>").description("the session's resources, oldest first").action(
|
|
@@ -1688,6 +1892,40 @@ async function chatLoop(sessionId, opts = {}) {
|
|
|
1688
1892
|
await new Promise(() => {
|
|
1689
1893
|
});
|
|
1690
1894
|
}
|
|
1895
|
+
program.command("catalog").description("the agents that can be started by handle").command("search [words...]").description("find an agent for a piece of work; no words lists every agent").option("--category <category>", "only this category").option("--json", "print the full listings as JSON").action(
|
|
1896
|
+
run(async (words, opts) => {
|
|
1897
|
+
const query = new URLSearchParams();
|
|
1898
|
+
if (words.length) query.set("q", words.join(" "));
|
|
1899
|
+
if (opts.category) query.set("category", opts.category);
|
|
1900
|
+
const { agents } = await api("GET", `/catalog/agents${query.size ? `?${query}` : ""}`);
|
|
1901
|
+
if (opts.json) {
|
|
1902
|
+
console.log(JSON.stringify(agents));
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
if (!agents.length) {
|
|
1906
|
+
console.log("No agent matches. `sky catalog search` with no words lists every agent.");
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
for (const a of agents) console.log(`@${a.handle.padEnd(24)} ${a.name.padEnd(20)} ${a.tagline}`);
|
|
1910
|
+
console.log(`
|
|
1911
|
+
Start one: sky session create @<handle> --message "<the job>"`);
|
|
1912
|
+
})
|
|
1913
|
+
);
|
|
1914
|
+
program.command("skill").description("the AgentSky skill for the agents on this machine").command("install").description("add the AgentSky skill to each installed agent (Claude Code, Codex, Cursor)").option("--agent <id...>", "only these agents: claude_code | codex | cursor").option("--dry-run", "say what would be written; write nothing").option("--json", "print the outcome per agent as JSON").action(
|
|
1915
|
+
run(async (opts) => {
|
|
1916
|
+
const installs = selectLocalAgents(opts.agent).map((a) => installSkill(a, { dryRun: opts.dryRun }));
|
|
1917
|
+
if (opts.json) {
|
|
1918
|
+
console.log(JSON.stringify(installs));
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if (!installs.length) {
|
|
1922
|
+
console.log("No agent found on this machine (looked for Claude Code, Codex and Cursor).");
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
const verb = { installed: opts.dryRun ? "would install" : "installed", updated: opts.dryRun ? "would update" : "updated", current: "up to date" };
|
|
1926
|
+
for (const i of installs) console.log(`${i.agent.padEnd(12)} ${verb[i.outcome].padEnd(14)} ${i.path}`);
|
|
1927
|
+
})
|
|
1928
|
+
);
|
|
1691
1929
|
var secrets = program.command("secrets").description("agent secrets (values write-only)");
|
|
1692
1930
|
secrets.command("set <id> <pairs...>").description("set KEY=VALUE pairs on the agent").action(
|
|
1693
1931
|
run(async (id, pairs) => {
|
|
@@ -1723,7 +1961,7 @@ secrets.command("unset <id> <key>").action(
|
|
|
1723
1961
|
program.command("launch").description("scaffold ./agent.toml if absent, create the agent, 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)").action(
|
|
1724
1962
|
run(async (opts) => {
|
|
1725
1963
|
const path = resolve3(opts.file);
|
|
1726
|
-
if (!
|
|
1964
|
+
if (!existsSync6(path)) {
|
|
1727
1965
|
const name = basename3(process.cwd()).replace(/[^a-zA-Z0-9 _-]/g, "") || "my-agent";
|
|
1728
1966
|
scaffoldAgentFile(path, name);
|
|
1729
1967
|
console.log(`Scaffolded ${opts.file} \u2014 edit it anytime; re-apply with \`sky deploy\`.`);
|
|
@@ -1921,7 +2159,7 @@ files.command("rm <id>").description("delete a file (a session that already rece
|
|
|
1921
2159
|
files.command("download <id>").description("download a session file's bytes").requiredOption("-o, --out <path>", "where to write the bytes").action(
|
|
1922
2160
|
run(async (id, opts) => {
|
|
1923
2161
|
const { bytes } = await downloadFile(id);
|
|
1924
|
-
|
|
2162
|
+
writeFileSync5(opts.out, bytes);
|
|
1925
2163
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
1926
2164
|
})
|
|
1927
2165
|
);
|
package/dist/products.js
CHANGED