@agentsky/sky 0.1.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
  },
@@ -70,12 +75,30 @@ async function api(method, path, body, opts = {}) {
70
75
  if (!res.ok) await parseError(res);
71
76
  return await res.json();
72
77
  }
73
- async function* streamEvents(agentSlug, signal) {
74
- const { parseSseStream } = await import("./src-KNBIGOZP.js");
78
+ async function resolveSessionRef(ref) {
79
+ if (ref.startsWith("sess-")) return ref;
80
+ const { agent: agent2 } = await api(
81
+ "GET",
82
+ `/api/v1/agents/${encodeURIComponent(ref)}`
83
+ ).catch(async () => {
84
+ await api("GET", `/api/v1/sessions/${encodeURIComponent(ref)}`);
85
+ return { agent: { slug: ref, defaultSessionId: ref } };
86
+ });
87
+ if (!agent2.defaultSessionId) {
88
+ throw new ApiError(
89
+ 404,
90
+ "no_sessions",
91
+ `agent ${agent2.slug} has no sessions \u2014 create one: sky session create ${agent2.slug}`
92
+ );
93
+ }
94
+ return agent2.defaultSessionId;
95
+ }
96
+ async function* streamEvents(sessionId, signal) {
97
+ const { parseSseStream } = await import("./src-Y2XOFL3Z.js");
75
98
  const res = await fetch(
76
- `${apiBase()}/api/v1/agents/${encodeURIComponent(agentSlug)}/stream`,
99
+ `${apiBase()}/api/v1/sessions/${encodeURIComponent(sessionId)}/stream`,
77
100
  {
78
- headers: { ...authHeaders(), accept: "text/event-stream" },
101
+ headers: { "user-agent": USER_AGENT, ...authHeaders(), accept: "text/event-stream" },
79
102
  signal
80
103
  }
81
104
  );
@@ -362,6 +385,7 @@ async function createClone(local, opts) {
362
385
  throw error;
363
386
  }
364
387
  }
388
+ await api("POST", "/api/v1/sessions", { agent: created.slug });
365
389
  const now = (/* @__PURE__ */ new Date()).toISOString();
366
390
  writeLink(local.configRoot, {
367
391
  baseUrl: apiBase(),
@@ -531,7 +555,8 @@ async function headlessLogin(verifier, challenge) {
531
555
  while (Date.now() < deadline) {
532
556
  await new Promise((r) => setTimeout(r, 3e3));
533
557
  const res = await fetch(
534
- `${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 } }
535
560
  );
536
561
  if (!res.ok) {
537
562
  const body2 = await res.json().catch(() => null);
@@ -591,16 +616,167 @@ function renderEvent(event, data) {
591
616
  }
592
617
  }
593
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
+
594
770
  // src/index.ts
595
771
  var program = new Command();
596
- program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version("0.1.0");
772
+ program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version(CLI_VERSION);
597
773
  function fail(error) {
598
774
  if (error instanceof ApiError) console.error(`sky: ${error.message} (${error.code})`);
599
775
  else console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
600
776
  process.exit(1);
601
777
  }
602
778
  var run = (fn) => (...args) => fn(...args).catch(fail);
603
- var auth = program.command("auth").description("login, logout, whoami");
779
+ var auth = program.command("auth").description("login, logout, whoami, model subscriptions");
604
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 })));
605
781
  auth.command("logout").description("forget the stored token (revoke it in Settings \u2192 API tokens)").action(
606
782
  run(async () => {
@@ -616,6 +792,15 @@ auth.command("whoami").description("who the current token acts as").action(
616
792
  );
617
793
  })
618
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)));
619
804
  var universe = program.command("universe").description("grouping boundary for agents");
620
805
  universe.command("list").action(
621
806
  run(async () => {
@@ -653,8 +838,8 @@ universe.command("show").action(
653
838
  }
654
839
  })
655
840
  );
656
- var agent = program.command("agent").description("create, inspect, talk to agents");
657
- agent.command("create").description("create an agent (flags-only; bare create = instant default)").option("--type <type>", "hermes | claude_code | codex | openclaw").option("--llm <llm>", "model id (defaults per type)").option("--name <name>", "agent name").option("--vcpus <n>", "machine vCPUs: 1, 2, 4 or 8 (default 2)").option("--memory <mb>", "machine memory in MB, 256MB steps (default 4096)").option("-f, --file <path>", "create from an agent.toml").action(
841
+ var agent = program.command("agent").description("agent specs: create, inspect, talk (via the default session)");
842
+ agent.command("create").description("create an agent spec \u2014 no runtime; `sky session create` starts one").option("--type <type>", "hermes | claude_code | codex | openclaw").option("--llm <llm>", "model id (defaults per type)").option("--name <name>", "agent name").option("-f, --file <path>", "create from an agent.toml").action(
658
843
  run(async (opts) => {
659
844
  const spec = opts.file ? readAgentFile(opts.file).spec : {
660
845
  name: opts.name ?? "My agent",
@@ -662,11 +847,9 @@ agent.command("create").description("create an agent (flags-only; bare create =
662
847
  llm: opts.llm,
663
848
  displayName: opts.name
664
849
  };
665
- if (opts.vcpus !== void 0) spec.vcpus = Number(opts.vcpus);
666
- if (opts.memory !== void 0) spec.memoryMb = Number(opts.memory);
667
850
  const { agent: created } = await api("POST", "/api/v1/agents", spec);
668
- console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm})`);
669
- console.log(`Talk to it: sky agent message ${created.slug} "hello"`);
851
+ console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm}) \u2014 spec only.`);
852
+ console.log(`Start it: sky session create ${created.slug}`);
670
853
  })
671
854
  );
672
855
  agent.command("list").action(
@@ -677,8 +860,9 @@ agent.command("list").action(
677
860
  return;
678
861
  }
679
862
  for (const a of agents) {
863
+ const state = a.archived ? "archived" : `${a.sessionCount} session${a.sessionCount === 1 ? "" : "s"}`;
680
864
  console.log(
681
- `${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${a.status.toLowerCase()}`
865
+ `${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${state}`
682
866
  );
683
867
  }
684
868
  })
@@ -686,36 +870,118 @@ agent.command("list").action(
686
870
  agent.command("show <slug>").action(
687
871
  run(async (slug) => {
688
872
  const { agent: a } = await api("GET", `/api/v1/agents/${encodeURIComponent(slug)}`);
689
- console.log(`${a.slug} \u2014 ${a.displayName}`);
873
+ console.log(`${a.slug} \u2014 ${a.displayName}${a.archived ? " (archived)" : ""}`);
690
874
  console.log(` type ${a.agentType} \xB7 ${a.llm}`);
691
- console.log(` status ${a.status.toLowerCase()}`);
875
+ console.log(` version ${a.version}`);
876
+ console.log(` sessions ${a.sessionCount}`);
692
877
  console.log(` universe ${a.universe}`);
693
878
  if (a.capabilities.length) console.log(` caps ${a.capabilities.join(", ")}`);
694
879
  if (a.prompt) console.log(` prompt ${a.prompt.split("\n")[0]?.slice(0, 80)}\u2026`);
695
880
  })
696
881
  );
697
- agent.command("destroy <slug>").description("tear down the pod and delete the agent (admin scope)").action(
882
+ agent.command("archive <slug>").description("retire the spec \u2014 read-only, running sessions unaffected (admin scope)").action(
883
+ run(async (slug) => {
884
+ await api("POST", `/api/v1/agents/${encodeURIComponent(slug)}/archive`);
885
+ console.log(`Archived ${slug} \u2014 sessions keep running; new sessions are rejected.`);
886
+ })
887
+ );
888
+ agent.command("destroy <slug>").description("delete the spec; requires all sessions destroyed first (admin scope)").action(
698
889
  run(async (slug) => {
699
890
  await api("DELETE", `/api/v1/agents/${encodeURIComponent(slug)}`);
700
891
  console.log(`Destroyed ${slug}`);
701
892
  })
702
893
  );
703
- agent.command("logs <slug>").option("-f, --follow", "follow (SSE)").option("--since <duration>", "how far back, e.g. 1h, 30m", "1h").action(
704
- run(async (slug, opts) => {
894
+ agent.command("message <slug> <text>").description("send one message to the default session and stream the turn until idle").option("--detach", "don't follow the stream; exit after the 202").action(
895
+ run(
896
+ async (slug, text, opts) => sendAndFollow(await resolveSessionRef(slug), text, Boolean(opts.detach))
897
+ )
898
+ );
899
+ agent.command("chat <slug>").description("interactive REPL with the default session").action(run(async (slug) => chatLoop(await resolveSessionRef(slug))));
900
+ var session = program.command("session").description("sessions: the running instances of an agent");
901
+ session.command("create <agent>").description("create a session (cheap \u2014 the pod starts on the first message)").option("--title <title>", "session title").option("--message <text>", "seed the session and start 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)").action(
902
+ run(async (agentRef, opts) => {
903
+ const { session: created } = await api("POST", "/api/v1/sessions", {
904
+ agent: agentRef,
905
+ ...opts.title ? { title: opts.title } : {},
906
+ ...opts.vcpus !== void 0 ? { vcpus: Number(opts.vcpus) } : {},
907
+ ...opts.memory !== void 0 ? { memoryMb: Number(opts.memory) } : {},
908
+ ...opts.message ? { initial_events: [{ type: "user.message", parts: [{ type: "text", index: 0, text: opts.message }] }] } : {}
909
+ });
910
+ console.log(`Created ${created.id} (${created.agent} \xB7 ${created.status})${created.default ? " [default]" : ""}`);
911
+ console.log(` sky agent message ${created.agent} "hello"`);
912
+ })
913
+ );
914
+ session.command("list [agent]").action(
915
+ run(async (agentRef) => {
916
+ const qs = agentRef ? `?agent=${encodeURIComponent(agentRef)}` : "";
917
+ const { sessions } = await api("GET", `/api/v1/sessions${qs}`);
918
+ if (!sessions.length) {
919
+ console.log("No sessions. `sky session create <agent>` to start one.");
920
+ return;
921
+ }
922
+ for (const s of sessions) {
923
+ console.log(
924
+ `${s.id.padEnd(24)} ${(s.agent ?? "-").padEnd(20)} ${(s.title ?? "").padEnd(16)} ${s.status}${s.default ? " *" : ""}`
925
+ );
926
+ }
927
+ })
928
+ );
929
+ session.command("show <id>").action(
930
+ run(async (id) => {
931
+ const { session: s } = await api(
932
+ "GET",
933
+ `/api/v1/sessions/${encodeURIComponent(id)}`
934
+ );
935
+ console.log(`${s.id}${s.default ? " [default]" : ""}`);
936
+ console.log(` agent ${s.agent ?? "-"}`);
937
+ console.log(` title ${s.title ?? "-"}`);
938
+ console.log(` status ${s.status}`);
939
+ console.log(` model ${s.agentType} \xB7 ${s.llm}`);
940
+ })
941
+ );
942
+ session.command("destroy <id>").description("end the session and tear down its pod (admin scope)").action(
943
+ run(async (id) => {
944
+ await api("DELETE", `/api/v1/sessions/${encodeURIComponent(id)}`);
945
+ console.log(`Destroyed ${id}`);
946
+ })
947
+ );
948
+ session.command("message <ref> <text>").description("send one message (session id, or agent slug = its default session)").option("--detach", "don't follow the stream; exit after the 202").action(
949
+ run(
950
+ async (ref, text, opts) => sendAndFollow(await resolveSessionRef(ref), text, Boolean(opts.detach))
951
+ )
952
+ );
953
+ session.command("chat <ref>").description("interactive REPL over the standing stream").action(run(async (ref) => chatLoop(await resolveSessionRef(ref))));
954
+ session.command("interrupt <ref>").description("abort the in-flight turn").action(
955
+ run(async (ref) => {
956
+ const id = await resolveSessionRef(ref);
957
+ const res = await api(
958
+ "POST",
959
+ `/api/v1/sessions/${encodeURIComponent(id)}/interrupt`
960
+ );
961
+ console.log(res.status === "no_turn" ? "nothing in flight" : "interrupting");
962
+ })
963
+ );
964
+ session.command("logs <ref>").option("-f, --follow", "follow (SSE)").option("--since <duration>", "how far back, e.g. 1h, 30m", "1h").action(
965
+ run(async (ref, opts) => {
966
+ const id = await resolveSessionRef(ref);
705
967
  const qs = `?since=${encodeURIComponent(opts.since)}${opts.follow ? "&follow=true" : ""}`;
706
968
  if (!opts.follow) {
707
969
  const { lines } = await api(
708
970
  "GET",
709
- `/api/v1/agents/${encodeURIComponent(slug)}/logs${qs}`
971
+ `/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`
710
972
  );
711
973
  for (const entry of lines) console.log(`${entry.at} ${entry.line}`);
712
974
  return;
713
975
  }
714
- const { parseSseStream } = await import("./src-KNBIGOZP.js");
976
+ const { parseSseStream } = await import("./src-Y2XOFL3Z.js");
715
977
  const { apiBase: apiBase2 } = await import("./config-HRDRNTUU.js");
716
978
  const token = apiToken();
717
- const res = await fetch(`${apiBase2()}/api/v1/agents/${encodeURIComponent(slug)}/logs${qs}`, {
718
- headers: { authorization: `Bearer ${token}`, accept: "text/event-stream" }
979
+ const res = await fetch(`${apiBase2()}/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`, {
980
+ headers: {
981
+ "user-agent": USER_AGENT,
982
+ authorization: `Bearer ${token}`,
983
+ accept: "text/event-stream"
984
+ }
719
985
  });
720
986
  if (!res.ok || !res.body) throw new ApiError(res.status, "logs_failed", await res.text());
721
987
  for await (const frame of parseSseStream(res.body)) {
@@ -727,12 +993,12 @@ agent.command("logs <slug>").option("-f, --follow", "follow (SSE)").option("--si
727
993
  }
728
994
  })
729
995
  );
730
- async function sendAndFollow(slug, text, detach) {
996
+ async function sendAndFollow(sessionId, text, detach) {
731
997
  const controller = new AbortController();
732
998
  let opened = null;
733
999
  if (!detach) {
734
1000
  opened = (async () => {
735
- for await (const frame of streamEvents(slug, controller.signal)) {
1001
+ for await (const frame of streamEvents(sessionId, controller.signal)) {
736
1002
  renderEvent(frame.event, frame.data);
737
1003
  if (frame.event === "turn.status_idle" || frame.event === "turn.interrupted") {
738
1004
  controller.abort();
@@ -742,68 +1008,50 @@ async function sendAndFollow(slug, text, detach) {
742
1008
  })();
743
1009
  await new Promise((r) => setTimeout(r, 300));
744
1010
  }
745
- const { turnId } = await api(
746
- "POST",
747
- `/api/v1/agents/${encodeURIComponent(slug)}/messages`,
748
- { parts: [{ type: "text", index: 0, text }] }
749
- );
1011
+ await api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
1012
+ parts: [{ type: "text", index: 0, text }]
1013
+ });
750
1014
  if (detach) {
751
- console.log(`accepted ${turnId}`);
1015
+ console.log("accepted");
752
1016
  return;
753
1017
  }
754
1018
  await opened;
755
1019
  }
756
- agent.command("message <slug> <text>").description("send one message and stream the turn until idle").option("--detach", "don't follow the stream; print the turnId and exit").action(
757
- run(
758
- async (slug, text, opts) => sendAndFollow(slug, text, Boolean(opts.detach))
759
- )
760
- );
761
- agent.command("chat <slug>").description("interactive REPL over the standing stream").action(
762
- run(async (slug) => {
763
- console.log(`Chatting with ${slug} \u2014 Ctrl-C to leave.`);
764
- const controller = new AbortController();
765
- const rl = createInterface2({ input: process.stdin, output: process.stdout, prompt: "> " });
766
- void (async () => {
767
- try {
768
- for await (const frame of streamEvents(slug, controller.signal)) {
769
- renderEvent(frame.event, frame.data);
770
- if (frame.event === "turn.status_idle") rl.prompt();
771
- }
772
- } catch (error) {
773
- fail(error);
774
- }
775
- })();
776
- rl.prompt();
777
- rl.on("line", (line) => {
778
- const text = line.trim();
779
- if (!text) {
780
- rl.prompt();
781
- return;
1020
+ async function chatLoop(sessionId) {
1021
+ console.log(`Chatting with ${sessionId} \u2014 Ctrl-C to leave.`);
1022
+ const controller = new AbortController();
1023
+ const rl = createInterface3({ input: process.stdin, output: process.stdout, prompt: "> " });
1024
+ void (async () => {
1025
+ try {
1026
+ for await (const frame of streamEvents(sessionId, controller.signal)) {
1027
+ renderEvent(frame.event, frame.data);
1028
+ if (frame.event === "turn.status_idle") rl.prompt();
782
1029
  }
783
- void api("POST", `/api/v1/agents/${encodeURIComponent(slug)}/messages`, {
784
- parts: [{ type: "text", index: 0, text }]
785
- }).catch((error) => {
786
- console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
787
- rl.prompt();
788
- });
789
- });
790
- rl.on("close", () => {
791
- controller.abort();
792
- process.exit(0);
793
- });
794
- await new Promise(() => {
1030
+ } catch (error) {
1031
+ fail(error);
1032
+ }
1033
+ })();
1034
+ rl.prompt();
1035
+ rl.on("line", (line) => {
1036
+ const text = line.trim();
1037
+ if (!text) {
1038
+ rl.prompt();
1039
+ return;
1040
+ }
1041
+ void api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
1042
+ parts: [{ type: "text", index: 0, text }]
1043
+ }).catch((error) => {
1044
+ console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
1045
+ rl.prompt();
795
1046
  });
796
- })
797
- );
798
- agent.command("interrupt <slug>").description("abort the in-flight turn").action(
799
- run(async (slug) => {
800
- const res = await api(
801
- "POST",
802
- `/api/v1/agents/${encodeURIComponent(slug)}/interrupt`
803
- );
804
- console.log(res.status === "no_turn" ? "nothing in flight" : `interrupting ${res.turnId}`);
805
- })
806
- );
1047
+ });
1048
+ rl.on("close", () => {
1049
+ controller.abort();
1050
+ process.exit(0);
1051
+ });
1052
+ await new Promise(() => {
1053
+ });
1054
+ }
807
1055
  var secrets = program.command("secrets").description("agent secrets (values write-only)");
808
1056
  secrets.command("set <slug> <pairs...>").description("set KEY=VALUE pairs on the agent").action(
809
1057
  run(async (slug, pairs) => {
@@ -839,7 +1087,7 @@ secrets.command("unset <slug> <key>").action(
839
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(
840
1088
  run(async (opts) => {
841
1089
  const path = resolve3(opts.file);
842
- if (!existsSync3(path)) {
1090
+ if (!existsSync4(path)) {
843
1091
  const name = basename2(process.cwd()).replace(/[^a-zA-Z0-9 _-]/g, "") || "my-agent";
844
1092
  scaffoldAgentFile(path, name);
845
1093
  console.log(`Scaffolded ${opts.file} \u2014 edit it anytime; re-apply with \`sky deploy\`.`);
@@ -849,7 +1097,13 @@ program.command("launch").description("scaffold ./agent.toml if absent, create t
849
1097
  console.log(`${file.slug} already launched \u2014 use \`sky deploy\` to re-apply.`);
850
1098
  return;
851
1099
  }
852
- const { agent: created } = await api("POST", "/api/v1/agents", spec);
1100
+ const { vcpus, memoryMb, ...specBody } = spec;
1101
+ const { agent: created } = await api("POST", "/api/v1/agents", specBody);
1102
+ await api("POST", "/api/v1/sessions", {
1103
+ agent: created.slug,
1104
+ ...vcpus !== void 0 ? { vcpus } : {},
1105
+ ...memoryMb !== void 0 ? { memoryMb } : {}
1106
+ });
853
1107
  stampSlug(path, created.slug);
854
1108
  console.log(`Launched ${created.slug} (${created.agentType} \xB7 ${created.llm})`);
855
1109
  console.log(` sky agent message ${created.slug} "hello"`);
@@ -862,7 +1116,13 @@ program.command("deploy").description("re-apply ./agent.toml to the existing age
862
1116
  const { file, spec } = readAgentFile(path);
863
1117
  if (!file.slug) {
864
1118
  console.log("No slug in the file yet \u2014 running launch instead.");
865
- const { agent: created } = await api("POST", "/api/v1/agents", spec);
1119
+ const { vcpus, memoryMb, ...specBody } = spec;
1120
+ const { agent: created } = await api("POST", "/api/v1/agents", specBody);
1121
+ await api("POST", "/api/v1/sessions", {
1122
+ agent: created.slug,
1123
+ ...vcpus !== void 0 ? { vcpus } : {},
1124
+ ...memoryMb !== void 0 ? { memoryMb } : {}
1125
+ });
866
1126
  stampSlug(path, created.slug);
867
1127
  console.log(`Launched ${created.slug}`);
868
1128
  return;
@@ -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,25 +116,16 @@ 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
- `/api/v1/agents/${encodeURIComponent(args.agentRouteId)}/messages`,
128
+ `/api/v1/sessions/${encodeURIComponent(args.agentRouteId)}/messages`,
139
129
  normalizeBaseUrl(args.baseUrl)
140
130
  );
141
131
  const headers = {
@@ -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.1.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",