@agentsky/sky 0.2.0 → 0.2.1
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.
|
@@ -14607,9 +14607,6 @@ var messageSchema = external_exports.object({
|
|
|
14607
14607
|
parts: external_exports.array(messagePartSchema).default([]),
|
|
14608
14608
|
metadata: external_exports.record(external_exports.string(), external_exports.unknown()).default({})
|
|
14609
14609
|
});
|
|
14610
|
-
function textParts(text) {
|
|
14611
|
-
return [{ type: "text", index: 0, text }];
|
|
14612
|
-
}
|
|
14613
14610
|
|
|
14614
14611
|
// ../../packages/spec/src/clone.ts
|
|
14615
14612
|
var CREDENTIAL_PATTERNS = [
|
|
@@ -14819,7 +14816,6 @@ var allowedLlms = {
|
|
|
14819
14816
|
"claude-opus-5",
|
|
14820
14817
|
"claude-fable-5",
|
|
14821
14818
|
"claude-sonnet-4-6",
|
|
14822
|
-
"kimi-k3",
|
|
14823
14819
|
"claude-opus-4-8"
|
|
14824
14820
|
],
|
|
14825
14821
|
codex: ["gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.5"],
|
|
@@ -14948,7 +14944,6 @@ export {
|
|
|
14948
14944
|
splitMcpServers,
|
|
14949
14945
|
mcpConfigInstall,
|
|
14950
14946
|
messagePartSchema,
|
|
14951
|
-
textParts,
|
|
14952
14947
|
AGENT_TYPES,
|
|
14953
14948
|
capabilitiesSchema,
|
|
14954
14949
|
skillRefSchema,
|
package/dist/index.js
CHANGED
|
@@ -16,15 +16,19 @@ import {
|
|
|
16
16
|
mcpConfigInstall,
|
|
17
17
|
skillRefSchema,
|
|
18
18
|
splitMcpServers
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-L5LLCKZW.js";
|
|
20
20
|
import "./chunk-MLKGABMK.js";
|
|
21
21
|
|
|
22
22
|
// src/index.ts
|
|
23
|
-
import { existsSync as
|
|
23
|
+
import { existsSync as existsSync4 } from "fs";
|
|
24
24
|
import { basename as basename2, resolve as resolve3 } from "path";
|
|
25
|
-
import { createInterface as
|
|
25
|
+
import { createInterface as createInterface3 } from "readline";
|
|
26
26
|
import { Command } from "commander";
|
|
27
27
|
|
|
28
|
+
// src/version.ts
|
|
29
|
+
var CLI_VERSION = "0.2.1";
|
|
30
|
+
var USER_AGENT = `sky-cli/${CLI_VERSION} (${process.platform}; node/${process.versions.node})`;
|
|
31
|
+
|
|
28
32
|
// src/api.ts
|
|
29
33
|
var ApiError = class extends Error {
|
|
30
34
|
constructor(status, code, message) {
|
|
@@ -62,6 +66,7 @@ async function api(method, path, body, opts = {}) {
|
|
|
62
66
|
const res = await fetch(`${apiBase()}${path}`, {
|
|
63
67
|
method,
|
|
64
68
|
headers: {
|
|
69
|
+
"user-agent": USER_AGENT,
|
|
65
70
|
...opts.auth === false ? {} : authHeaders(),
|
|
66
71
|
...body !== void 0 ? { "content-type": "application/json" } : {}
|
|
67
72
|
},
|
|
@@ -89,11 +94,11 @@ async function resolveSessionRef(ref) {
|
|
|
89
94
|
return agent2.defaultSessionId;
|
|
90
95
|
}
|
|
91
96
|
async function* streamEvents(sessionId, signal) {
|
|
92
|
-
const { parseSseStream } = await import("./src-
|
|
97
|
+
const { parseSseStream } = await import("./src-Y2XOFL3Z.js");
|
|
93
98
|
const res = await fetch(
|
|
94
99
|
`${apiBase()}/api/v1/sessions/${encodeURIComponent(sessionId)}/stream`,
|
|
95
100
|
{
|
|
96
|
-
headers: { ...authHeaders(), accept: "text/event-stream" },
|
|
101
|
+
headers: { "user-agent": USER_AGENT, ...authHeaders(), accept: "text/event-stream" },
|
|
97
102
|
signal
|
|
98
103
|
}
|
|
99
104
|
);
|
|
@@ -550,7 +555,8 @@ async function headlessLogin(verifier, challenge) {
|
|
|
550
555
|
while (Date.now() < deadline) {
|
|
551
556
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
552
557
|
const res = await fetch(
|
|
553
|
-
`${apiBase()}/api/v1/cli/poll?request=${request}&verifier=${encodeURIComponent(verifier)}&clientName=${encodeURIComponent(`cli ${hostname()}`)}
|
|
558
|
+
`${apiBase()}/api/v1/cli/poll?request=${request}&verifier=${encodeURIComponent(verifier)}&clientName=${encodeURIComponent(`cli ${hostname()}`)}`,
|
|
559
|
+
{ headers: { "user-agent": USER_AGENT } }
|
|
554
560
|
);
|
|
555
561
|
if (!res.ok) {
|
|
556
562
|
const body2 = await res.json().catch(() => null);
|
|
@@ -610,16 +616,167 @@ function renderEvent(event, data) {
|
|
|
610
616
|
}
|
|
611
617
|
}
|
|
612
618
|
|
|
619
|
+
// src/subscriptions.ts
|
|
620
|
+
import { spawn as spawn3 } from "child_process";
|
|
621
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
622
|
+
import { homedir as homedir2 } from "os";
|
|
623
|
+
import { join as join2 } from "path";
|
|
624
|
+
import { createInterface as createInterface2 } from "readline";
|
|
625
|
+
var ALIASES = {
|
|
626
|
+
claude: "anthropic",
|
|
627
|
+
anthropic: "anthropic",
|
|
628
|
+
chatgpt: "openai",
|
|
629
|
+
openai: "openai",
|
|
630
|
+
codex: "openai"
|
|
631
|
+
};
|
|
632
|
+
function providerFor(name) {
|
|
633
|
+
const provider = ALIASES[name.toLowerCase()];
|
|
634
|
+
if (!provider) {
|
|
635
|
+
throw new ApiError(400, "unknown_provider", `unknown provider "${name}" \u2014 use claude or chatgpt`);
|
|
636
|
+
}
|
|
637
|
+
return provider;
|
|
638
|
+
}
|
|
639
|
+
function ask(question) {
|
|
640
|
+
return new Promise((done) => {
|
|
641
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
642
|
+
rl.question(question, (answer) => {
|
|
643
|
+
rl.close();
|
|
644
|
+
done(answer.trim());
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function confirm2(question) {
|
|
649
|
+
return new Promise((done) => {
|
|
650
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
651
|
+
rl.question(`${question} [y/N] `, (answer) => {
|
|
652
|
+
rl.close();
|
|
653
|
+
done(/^y(es)?$/i.test(answer.trim()));
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
function mintClaudeToken() {
|
|
658
|
+
return new Promise((done) => {
|
|
659
|
+
let child;
|
|
660
|
+
try {
|
|
661
|
+
child = spawn3("claude", ["setup-token"], { stdio: ["inherit", "pipe", "inherit"] });
|
|
662
|
+
} catch {
|
|
663
|
+
done(null);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
let buffer = "";
|
|
667
|
+
child.stdout?.on("data", (chunk) => {
|
|
668
|
+
buffer += chunk.toString();
|
|
669
|
+
process.stdout.write(chunk);
|
|
670
|
+
});
|
|
671
|
+
child.on("error", () => done(null));
|
|
672
|
+
child.on("close", () => {
|
|
673
|
+
const match = buffer.match(/sk-ant-oat[A-Za-z0-9_-]+/);
|
|
674
|
+
done(match ? match[0] : null);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
async function put(provider, credential) {
|
|
679
|
+
const { modelSubscription } = await api(
|
|
680
|
+
"PUT",
|
|
681
|
+
`/api/v1/model-subscriptions/${provider}`,
|
|
682
|
+
{ credential }
|
|
683
|
+
);
|
|
684
|
+
return modelSubscription;
|
|
685
|
+
}
|
|
686
|
+
async function connectClaude() {
|
|
687
|
+
let token = await mintClaudeToken();
|
|
688
|
+
if (token) {
|
|
689
|
+
console.log("\nCaptured the minted token \u2014 uploading.");
|
|
690
|
+
} else {
|
|
691
|
+
console.log("Couldn't mint a token via `claude setup-token` \u2014 paste one instead.");
|
|
692
|
+
console.log("(Run `claude setup-token` on a machine with Claude Code and paste its sk-ant-oat\u2026 output.)");
|
|
693
|
+
token = await ask("Token: ");
|
|
694
|
+
}
|
|
695
|
+
if (!token) throw new ApiError(400, "no_token", "no token provided");
|
|
696
|
+
const sub = await put("anthropic", token);
|
|
697
|
+
const expiry = sub.expiresAt ? ` (expires ~${sub.expiresAt.slice(0, 10)})` : "";
|
|
698
|
+
console.log(`Connected Claude subscription${expiry}. Powers new eligible agents.`);
|
|
699
|
+
}
|
|
700
|
+
async function connectChatgpt(opts) {
|
|
701
|
+
const codexHome = process.env.CODEX_HOME || join2(homedir2(), ".codex");
|
|
702
|
+
const path = join2(codexHome, "auth.json");
|
|
703
|
+
if (!existsSync3(path)) {
|
|
704
|
+
throw new ApiError(404, "no_codex_auth", `no ${path} \u2014 run \`codex login\` first`);
|
|
705
|
+
}
|
|
706
|
+
const raw = readFileSync3(path, "utf8");
|
|
707
|
+
let accountId;
|
|
708
|
+
try {
|
|
709
|
+
const parsed = JSON.parse(raw);
|
|
710
|
+
accountId = parsed.tokens?.account_id;
|
|
711
|
+
} catch {
|
|
712
|
+
throw new ApiError(400, "invalid_codex_auth", `${path} isn't valid JSON \u2014 re-run \`codex login\``);
|
|
713
|
+
}
|
|
714
|
+
console.log(`Found Codex sign-in at ${path}${accountId ? ` (account ${accountId})` : ""}.`);
|
|
715
|
+
if (!opts.yes) {
|
|
716
|
+
const ok = await confirm2("Upload it so your cloud Codex agents run on your ChatGPT plan?");
|
|
717
|
+
if (!ok) {
|
|
718
|
+
console.log("Aborted \u2014 nothing uploaded.");
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
await put("openai", raw);
|
|
723
|
+
console.log("Connected ChatGPT plan. Powers new eligible agents.");
|
|
724
|
+
}
|
|
725
|
+
async function listSubscriptions() {
|
|
726
|
+
const { modelSubscriptions } = await api(
|
|
727
|
+
"GET",
|
|
728
|
+
"/api/v1/model-subscriptions"
|
|
729
|
+
);
|
|
730
|
+
if (modelSubscriptions.length === 0) {
|
|
731
|
+
console.log("No model subscriptions connected. Try `sky auth connect claude` or `sky auth connect chatgpt`.");
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
for (const s of modelSubscriptions) {
|
|
735
|
+
const bits = [
|
|
736
|
+
s.provider === "anthropic" ? "claude" : "chatgpt",
|
|
737
|
+
s.status,
|
|
738
|
+
s.expiresAt ? `expires ~${s.expiresAt.slice(0, 10)}` : null,
|
|
739
|
+
s.lastUsedAt ? `last used ${s.lastUsedAt.slice(0, 10)}` : null,
|
|
740
|
+
`${s.agents.length} agent${s.agents.length === 1 ? "" : "s"}`,
|
|
741
|
+
s.useForNewAgents ? "used for new agents" : "not used for new agents"
|
|
742
|
+
].filter(Boolean);
|
|
743
|
+
console.log(bits.join(" \xB7 "));
|
|
744
|
+
for (const a of s.agents) console.log(` ${a.slug ?? a.id} \u2014 ${a.name}`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
async function disconnect(name, opts) {
|
|
748
|
+
const provider = providerFor(name);
|
|
749
|
+
const label = provider === "anthropic" ? "Claude" : "ChatGPT";
|
|
750
|
+
if (!opts.yes) {
|
|
751
|
+
const ok = await confirm2(`Disconnect ${label}? Agents running on it will fail until reconnected or switched to Platform.`);
|
|
752
|
+
if (!ok) {
|
|
753
|
+
console.log("Aborted.");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
const { affectedAgents } = await api(
|
|
758
|
+
"DELETE",
|
|
759
|
+
`/api/v1/model-subscriptions/${provider}`
|
|
760
|
+
);
|
|
761
|
+
console.log(`Disconnected ${label}.`);
|
|
762
|
+
if (affectedAgents.length > 0) {
|
|
763
|
+
console.log(
|
|
764
|
+
`${affectedAgents.length} agent${affectedAgents.length === 1 ? "" : "s"} still point at it and will fail: ` + affectedAgents.map((a) => a.slug ?? a.id).join(", ")
|
|
765
|
+
);
|
|
766
|
+
console.log("Switch them to Platform in each agent's Configure tab (or reconnect).");
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
613
770
|
// src/index.ts
|
|
614
771
|
var program = new Command();
|
|
615
|
-
program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version(
|
|
772
|
+
program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version(CLI_VERSION);
|
|
616
773
|
function fail(error) {
|
|
617
774
|
if (error instanceof ApiError) console.error(`sky: ${error.message} (${error.code})`);
|
|
618
775
|
else console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
|
|
619
776
|
process.exit(1);
|
|
620
777
|
}
|
|
621
778
|
var run = (fn) => (...args) => fn(...args).catch(fail);
|
|
622
|
-
var auth = program.command("auth").description("login, logout, whoami");
|
|
779
|
+
var auth = program.command("auth").description("login, logout, whoami, model subscriptions");
|
|
623
780
|
auth.command("login").description("authorize this machine via the browser").option("--no-browser", "print a URL and poll instead of opening a browser").action(run(async (opts) => login({ noBrowser: opts.browser === false })));
|
|
624
781
|
auth.command("logout").description("forget the stored token (revoke it in Settings \u2192 API tokens)").action(
|
|
625
782
|
run(async () => {
|
|
@@ -635,6 +792,15 @@ auth.command("whoami").description("who the current token acts as").action(
|
|
|
635
792
|
);
|
|
636
793
|
})
|
|
637
794
|
);
|
|
795
|
+
auth.command("connect <provider>").description("connect a model subscription: claude (setup-token) or chatgpt (Codex sign-in)").option("-y, --yes", "skip the consent prompt").action(
|
|
796
|
+
run(async (name, opts) => {
|
|
797
|
+
const provider = providerFor(name);
|
|
798
|
+
if (provider === "anthropic") await connectClaude();
|
|
799
|
+
else await connectChatgpt(opts);
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
auth.command("accounts").description("list connected model subscriptions and the agents they power").action(run(async () => listSubscriptions()));
|
|
803
|
+
auth.command("disconnect <provider>").description("disconnect a model subscription (agents on it fail until switched)").option("-y, --yes", "skip the confirmation prompt").action(run(async (name, opts) => disconnect(name, opts)));
|
|
638
804
|
var universe = program.command("universe").description("grouping boundary for agents");
|
|
639
805
|
universe.command("list").action(
|
|
640
806
|
run(async () => {
|
|
@@ -807,11 +973,15 @@ session.command("logs <ref>").option("-f, --follow", "follow (SSE)").option("--s
|
|
|
807
973
|
for (const entry of lines) console.log(`${entry.at} ${entry.line}`);
|
|
808
974
|
return;
|
|
809
975
|
}
|
|
810
|
-
const { parseSseStream } = await import("./src-
|
|
976
|
+
const { parseSseStream } = await import("./src-Y2XOFL3Z.js");
|
|
811
977
|
const { apiBase: apiBase2 } = await import("./config-HRDRNTUU.js");
|
|
812
978
|
const token = apiToken();
|
|
813
979
|
const res = await fetch(`${apiBase2()}/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`, {
|
|
814
|
-
headers: {
|
|
980
|
+
headers: {
|
|
981
|
+
"user-agent": USER_AGENT,
|
|
982
|
+
authorization: `Bearer ${token}`,
|
|
983
|
+
accept: "text/event-stream"
|
|
984
|
+
}
|
|
815
985
|
});
|
|
816
986
|
if (!res.ok || !res.body) throw new ApiError(res.status, "logs_failed", await res.text());
|
|
817
987
|
for await (const frame of parseSseStream(res.body)) {
|
|
@@ -850,7 +1020,7 @@ async function sendAndFollow(sessionId, text, detach) {
|
|
|
850
1020
|
async function chatLoop(sessionId) {
|
|
851
1021
|
console.log(`Chatting with ${sessionId} \u2014 Ctrl-C to leave.`);
|
|
852
1022
|
const controller = new AbortController();
|
|
853
|
-
const rl =
|
|
1023
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout, prompt: "> " });
|
|
854
1024
|
void (async () => {
|
|
855
1025
|
try {
|
|
856
1026
|
for await (const frame of streamEvents(sessionId, controller.signal)) {
|
|
@@ -917,7 +1087,7 @@ secrets.command("unset <slug> <key>").action(
|
|
|
917
1087
|
program.command("launch").description("scaffold ./agent.toml if absent, create the agent, print its address").option("-f, --file <path>", "agent file", "agent.toml").action(
|
|
918
1088
|
run(async (opts) => {
|
|
919
1089
|
const path = resolve3(opts.file);
|
|
920
|
-
if (!
|
|
1090
|
+
if (!existsSync4(path)) {
|
|
921
1091
|
const name = basename2(process.cwd()).replace(/[^a-zA-Z0-9 _-]/g, "") || "my-agent";
|
|
922
1092
|
scaffoldAgentFile(path, name);
|
|
923
1093
|
console.log(`Scaffolded ${opts.file} \u2014 edit it anytime; re-apply with \`sky deploy\`.`);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
external_exports,
|
|
3
|
-
messagePartSchema
|
|
4
|
-
|
|
5
|
-
} from "./chunk-DTVZOF77.js";
|
|
3
|
+
messagePartSchema
|
|
4
|
+
} from "./chunk-L5LLCKZW.js";
|
|
6
5
|
import "./chunk-MLKGABMK.js";
|
|
7
6
|
|
|
8
7
|
// ../../packages/chat/src/stream.ts
|
|
@@ -117,22 +116,13 @@ async function postTurn(baseUrl, body, options = {}) {
|
|
|
117
116
|
throw new Error(`pod unreachable${suffix}`);
|
|
118
117
|
}
|
|
119
118
|
if (!res.ok) throw new Error(`pod message failed ${res.status}: ${await res.text()}`);
|
|
120
|
-
const data = await res.json();
|
|
121
|
-
return data.messages ?? [];
|
|
122
119
|
}
|
|
123
120
|
async function sendAgentTurn(baseUrl, parts, options = {}) {
|
|
124
|
-
|
|
125
|
-
return messages.flatMap((m) => m.parts ?? []).map((part, index) => ({ ...part, index }));
|
|
126
|
-
}
|
|
127
|
-
async function sendAgentMessage(baseUrl, text, options = {}) {
|
|
128
|
-
return textFromParts(await sendAgentTurn(baseUrl, textParts(text), options));
|
|
121
|
+
await postTurn(baseUrl, { parts }, options);
|
|
129
122
|
}
|
|
130
123
|
function textFromParts(parts) {
|
|
131
124
|
return parts.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join(" ").trim();
|
|
132
125
|
}
|
|
133
|
-
function replyParts(reply) {
|
|
134
|
-
return textParts(reply || "(no reply)");
|
|
135
|
-
}
|
|
136
126
|
async function postChatProxy(args) {
|
|
137
127
|
const url = new URL(
|
|
138
128
|
`/api/v1/sessions/${encodeURIComponent(args.agentRouteId)}/messages`,
|
|
@@ -179,8 +169,6 @@ export {
|
|
|
179
169
|
chatProxyRequestSchema,
|
|
180
170
|
parseSseStream,
|
|
181
171
|
postChatProxy,
|
|
182
|
-
replyParts,
|
|
183
|
-
sendAgentMessage,
|
|
184
172
|
sendAgentTurn,
|
|
185
173
|
streamAgentEvents,
|
|
186
174
|
textFromParts
|