@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-DTVZOF77.js";
19
+ } from "./chunk-L5LLCKZW.js";
20
20
  import "./chunk-MLKGABMK.js";
21
21
 
22
22
  // src/index.ts
23
- import { existsSync as existsSync3 } from "fs";
23
+ import { existsSync as existsSync4 } from "fs";
24
24
  import { basename as basename2, resolve as resolve3 } from "path";
25
- import { createInterface as createInterface2 } from "readline";
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-CNT7GXZH.js");
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("0.2.0");
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-CNT7GXZH.js");
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: { authorization: `Bearer ${token}`, accept: "text/event-stream" }
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 = createInterface2({ input: process.stdin, output: process.stdout, prompt: "> " });
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 (!existsSync3(path)) {
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
- textParts
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
- const messages = await postTurn(baseUrl, { parts }, options);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsky/sky",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "sky — the AgentSky developer CLI: launch and talk to long-lived agents from your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",