@agentsky/sky 0.1.0 → 0.2.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.
package/dist/index.js CHANGED
@@ -70,10 +70,28 @@ async function api(method, path, body, opts = {}) {
70
70
  if (!res.ok) await parseError(res);
71
71
  return await res.json();
72
72
  }
73
- async function* streamEvents(agentSlug, signal) {
74
- const { parseSseStream } = await import("./src-KNBIGOZP.js");
73
+ async function resolveSessionRef(ref) {
74
+ if (ref.startsWith("sess-")) return ref;
75
+ const { agent: agent2 } = await api(
76
+ "GET",
77
+ `/api/v1/agents/${encodeURIComponent(ref)}`
78
+ ).catch(async () => {
79
+ await api("GET", `/api/v1/sessions/${encodeURIComponent(ref)}`);
80
+ return { agent: { slug: ref, defaultSessionId: ref } };
81
+ });
82
+ if (!agent2.defaultSessionId) {
83
+ throw new ApiError(
84
+ 404,
85
+ "no_sessions",
86
+ `agent ${agent2.slug} has no sessions \u2014 create one: sky session create ${agent2.slug}`
87
+ );
88
+ }
89
+ return agent2.defaultSessionId;
90
+ }
91
+ async function* streamEvents(sessionId, signal) {
92
+ const { parseSseStream } = await import("./src-CNT7GXZH.js");
75
93
  const res = await fetch(
76
- `${apiBase()}/api/v1/agents/${encodeURIComponent(agentSlug)}/stream`,
94
+ `${apiBase()}/api/v1/sessions/${encodeURIComponent(sessionId)}/stream`,
77
95
  {
78
96
  headers: { ...authHeaders(), accept: "text/event-stream" },
79
97
  signal
@@ -362,6 +380,7 @@ async function createClone(local, opts) {
362
380
  throw error;
363
381
  }
364
382
  }
383
+ await api("POST", "/api/v1/sessions", { agent: created.slug });
365
384
  const now = (/* @__PURE__ */ new Date()).toISOString();
366
385
  writeLink(local.configRoot, {
367
386
  baseUrl: apiBase(),
@@ -593,7 +612,7 @@ function renderEvent(event, data) {
593
612
 
594
613
  // src/index.ts
595
614
  var program = new Command();
596
- program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version("0.1.0");
615
+ program.name("sky").description("Launch and talk to long-lived agents \u2014 agentsky.dev").version("0.2.0");
597
616
  function fail(error) {
598
617
  if (error instanceof ApiError) console.error(`sky: ${error.message} (${error.code})`);
599
618
  else console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
@@ -653,8 +672,8 @@ universe.command("show").action(
653
672
  }
654
673
  })
655
674
  );
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(
675
+ var agent = program.command("agent").description("agent specs: create, inspect, talk (via the default session)");
676
+ 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
677
  run(async (opts) => {
659
678
  const spec = opts.file ? readAgentFile(opts.file).spec : {
660
679
  name: opts.name ?? "My agent",
@@ -662,11 +681,9 @@ agent.command("create").description("create an agent (flags-only; bare create =
662
681
  llm: opts.llm,
663
682
  displayName: opts.name
664
683
  };
665
- if (opts.vcpus !== void 0) spec.vcpus = Number(opts.vcpus);
666
- if (opts.memory !== void 0) spec.memoryMb = Number(opts.memory);
667
684
  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"`);
685
+ console.log(`Created ${created.slug} (${created.agentType} \xB7 ${created.llm}) \u2014 spec only.`);
686
+ console.log(`Start it: sky session create ${created.slug}`);
670
687
  })
671
688
  );
672
689
  agent.command("list").action(
@@ -677,8 +694,9 @@ agent.command("list").action(
677
694
  return;
678
695
  }
679
696
  for (const a of agents) {
697
+ const state = a.archived ? "archived" : `${a.sessionCount} session${a.sessionCount === 1 ? "" : "s"}`;
680
698
  console.log(
681
- `${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${a.status.toLowerCase()}`
699
+ `${a.slug.padEnd(24)} ${a.displayName.padEnd(20)} ${a.agentType}/${a.llm} ${state}`
682
700
  );
683
701
  }
684
702
  })
@@ -686,35 +704,113 @@ agent.command("list").action(
686
704
  agent.command("show <slug>").action(
687
705
  run(async (slug) => {
688
706
  const { agent: a } = await api("GET", `/api/v1/agents/${encodeURIComponent(slug)}`);
689
- console.log(`${a.slug} \u2014 ${a.displayName}`);
707
+ console.log(`${a.slug} \u2014 ${a.displayName}${a.archived ? " (archived)" : ""}`);
690
708
  console.log(` type ${a.agentType} \xB7 ${a.llm}`);
691
- console.log(` status ${a.status.toLowerCase()}`);
709
+ console.log(` version ${a.version}`);
710
+ console.log(` sessions ${a.sessionCount}`);
692
711
  console.log(` universe ${a.universe}`);
693
712
  if (a.capabilities.length) console.log(` caps ${a.capabilities.join(", ")}`);
694
713
  if (a.prompt) console.log(` prompt ${a.prompt.split("\n")[0]?.slice(0, 80)}\u2026`);
695
714
  })
696
715
  );
697
- agent.command("destroy <slug>").description("tear down the pod and delete the agent (admin scope)").action(
716
+ agent.command("archive <slug>").description("retire the spec \u2014 read-only, running sessions unaffected (admin scope)").action(
717
+ run(async (slug) => {
718
+ await api("POST", `/api/v1/agents/${encodeURIComponent(slug)}/archive`);
719
+ console.log(`Archived ${slug} \u2014 sessions keep running; new sessions are rejected.`);
720
+ })
721
+ );
722
+ agent.command("destroy <slug>").description("delete the spec; requires all sessions destroyed first (admin scope)").action(
698
723
  run(async (slug) => {
699
724
  await api("DELETE", `/api/v1/agents/${encodeURIComponent(slug)}`);
700
725
  console.log(`Destroyed ${slug}`);
701
726
  })
702
727
  );
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) => {
728
+ 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(
729
+ run(
730
+ async (slug, text, opts) => sendAndFollow(await resolveSessionRef(slug), text, Boolean(opts.detach))
731
+ )
732
+ );
733
+ agent.command("chat <slug>").description("interactive REPL with the default session").action(run(async (slug) => chatLoop(await resolveSessionRef(slug))));
734
+ var session = program.command("session").description("sessions: the running instances of an agent");
735
+ 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(
736
+ run(async (agentRef, opts) => {
737
+ const { session: created } = await api("POST", "/api/v1/sessions", {
738
+ agent: agentRef,
739
+ ...opts.title ? { title: opts.title } : {},
740
+ ...opts.vcpus !== void 0 ? { vcpus: Number(opts.vcpus) } : {},
741
+ ...opts.memory !== void 0 ? { memoryMb: Number(opts.memory) } : {},
742
+ ...opts.message ? { initial_events: [{ type: "user.message", parts: [{ type: "text", index: 0, text: opts.message }] }] } : {}
743
+ });
744
+ console.log(`Created ${created.id} (${created.agent} \xB7 ${created.status})${created.default ? " [default]" : ""}`);
745
+ console.log(` sky agent message ${created.agent} "hello"`);
746
+ })
747
+ );
748
+ session.command("list [agent]").action(
749
+ run(async (agentRef) => {
750
+ const qs = agentRef ? `?agent=${encodeURIComponent(agentRef)}` : "";
751
+ const { sessions } = await api("GET", `/api/v1/sessions${qs}`);
752
+ if (!sessions.length) {
753
+ console.log("No sessions. `sky session create <agent>` to start one.");
754
+ return;
755
+ }
756
+ for (const s of sessions) {
757
+ console.log(
758
+ `${s.id.padEnd(24)} ${(s.agent ?? "-").padEnd(20)} ${(s.title ?? "").padEnd(16)} ${s.status}${s.default ? " *" : ""}`
759
+ );
760
+ }
761
+ })
762
+ );
763
+ session.command("show <id>").action(
764
+ run(async (id) => {
765
+ const { session: s } = await api(
766
+ "GET",
767
+ `/api/v1/sessions/${encodeURIComponent(id)}`
768
+ );
769
+ console.log(`${s.id}${s.default ? " [default]" : ""}`);
770
+ console.log(` agent ${s.agent ?? "-"}`);
771
+ console.log(` title ${s.title ?? "-"}`);
772
+ console.log(` status ${s.status}`);
773
+ console.log(` model ${s.agentType} \xB7 ${s.llm}`);
774
+ })
775
+ );
776
+ session.command("destroy <id>").description("end the session and tear down its pod (admin scope)").action(
777
+ run(async (id) => {
778
+ await api("DELETE", `/api/v1/sessions/${encodeURIComponent(id)}`);
779
+ console.log(`Destroyed ${id}`);
780
+ })
781
+ );
782
+ 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(
783
+ run(
784
+ async (ref, text, opts) => sendAndFollow(await resolveSessionRef(ref), text, Boolean(opts.detach))
785
+ )
786
+ );
787
+ session.command("chat <ref>").description("interactive REPL over the standing stream").action(run(async (ref) => chatLoop(await resolveSessionRef(ref))));
788
+ session.command("interrupt <ref>").description("abort the in-flight turn").action(
789
+ run(async (ref) => {
790
+ const id = await resolveSessionRef(ref);
791
+ const res = await api(
792
+ "POST",
793
+ `/api/v1/sessions/${encodeURIComponent(id)}/interrupt`
794
+ );
795
+ console.log(res.status === "no_turn" ? "nothing in flight" : "interrupting");
796
+ })
797
+ );
798
+ session.command("logs <ref>").option("-f, --follow", "follow (SSE)").option("--since <duration>", "how far back, e.g. 1h, 30m", "1h").action(
799
+ run(async (ref, opts) => {
800
+ const id = await resolveSessionRef(ref);
705
801
  const qs = `?since=${encodeURIComponent(opts.since)}${opts.follow ? "&follow=true" : ""}`;
706
802
  if (!opts.follow) {
707
803
  const { lines } = await api(
708
804
  "GET",
709
- `/api/v1/agents/${encodeURIComponent(slug)}/logs${qs}`
805
+ `/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`
710
806
  );
711
807
  for (const entry of lines) console.log(`${entry.at} ${entry.line}`);
712
808
  return;
713
809
  }
714
- const { parseSseStream } = await import("./src-KNBIGOZP.js");
810
+ const { parseSseStream } = await import("./src-CNT7GXZH.js");
715
811
  const { apiBase: apiBase2 } = await import("./config-HRDRNTUU.js");
716
812
  const token = apiToken();
717
- const res = await fetch(`${apiBase2()}/api/v1/agents/${encodeURIComponent(slug)}/logs${qs}`, {
813
+ const res = await fetch(`${apiBase2()}/api/v1/sessions/${encodeURIComponent(id)}/logs${qs}`, {
718
814
  headers: { authorization: `Bearer ${token}`, accept: "text/event-stream" }
719
815
  });
720
816
  if (!res.ok || !res.body) throw new ApiError(res.status, "logs_failed", await res.text());
@@ -727,12 +823,12 @@ agent.command("logs <slug>").option("-f, --follow", "follow (SSE)").option("--si
727
823
  }
728
824
  })
729
825
  );
730
- async function sendAndFollow(slug, text, detach) {
826
+ async function sendAndFollow(sessionId, text, detach) {
731
827
  const controller = new AbortController();
732
828
  let opened = null;
733
829
  if (!detach) {
734
830
  opened = (async () => {
735
- for await (const frame of streamEvents(slug, controller.signal)) {
831
+ for await (const frame of streamEvents(sessionId, controller.signal)) {
736
832
  renderEvent(frame.event, frame.data);
737
833
  if (frame.event === "turn.status_idle" || frame.event === "turn.interrupted") {
738
834
  controller.abort();
@@ -742,68 +838,50 @@ async function sendAndFollow(slug, text, detach) {
742
838
  })();
743
839
  await new Promise((r) => setTimeout(r, 300));
744
840
  }
745
- const { turnId } = await api(
746
- "POST",
747
- `/api/v1/agents/${encodeURIComponent(slug)}/messages`,
748
- { parts: [{ type: "text", index: 0, text }] }
749
- );
841
+ await api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
842
+ parts: [{ type: "text", index: 0, text }]
843
+ });
750
844
  if (detach) {
751
- console.log(`accepted ${turnId}`);
845
+ console.log("accepted");
752
846
  return;
753
847
  }
754
848
  await opened;
755
849
  }
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;
850
+ async function chatLoop(sessionId) {
851
+ console.log(`Chatting with ${sessionId} \u2014 Ctrl-C to leave.`);
852
+ const controller = new AbortController();
853
+ const rl = createInterface2({ input: process.stdin, output: process.stdout, prompt: "> " });
854
+ void (async () => {
855
+ try {
856
+ for await (const frame of streamEvents(sessionId, controller.signal)) {
857
+ renderEvent(frame.event, frame.data);
858
+ if (frame.event === "turn.status_idle") rl.prompt();
782
859
  }
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(() => {
860
+ } catch (error) {
861
+ fail(error);
862
+ }
863
+ })();
864
+ rl.prompt();
865
+ rl.on("line", (line) => {
866
+ const text = line.trim();
867
+ if (!text) {
868
+ rl.prompt();
869
+ return;
870
+ }
871
+ void api("POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`, {
872
+ parts: [{ type: "text", index: 0, text }]
873
+ }).catch((error) => {
874
+ console.error(`sky: ${error instanceof Error ? error.message : String(error)}`);
875
+ rl.prompt();
795
876
  });
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
- );
877
+ });
878
+ rl.on("close", () => {
879
+ controller.abort();
880
+ process.exit(0);
881
+ });
882
+ await new Promise(() => {
883
+ });
884
+ }
807
885
  var secrets = program.command("secrets").description("agent secrets (values write-only)");
808
886
  secrets.command("set <slug> <pairs...>").description("set KEY=VALUE pairs on the agent").action(
809
887
  run(async (slug, pairs) => {
@@ -849,7 +927,13 @@ program.command("launch").description("scaffold ./agent.toml if absent, create t
849
927
  console.log(`${file.slug} already launched \u2014 use \`sky deploy\` to re-apply.`);
850
928
  return;
851
929
  }
852
- const { agent: created } = await api("POST", "/api/v1/agents", spec);
930
+ const { vcpus, memoryMb, ...specBody } = spec;
931
+ const { agent: created } = await api("POST", "/api/v1/agents", specBody);
932
+ await api("POST", "/api/v1/sessions", {
933
+ agent: created.slug,
934
+ ...vcpus !== void 0 ? { vcpus } : {},
935
+ ...memoryMb !== void 0 ? { memoryMb } : {}
936
+ });
853
937
  stampSlug(path, created.slug);
854
938
  console.log(`Launched ${created.slug} (${created.agentType} \xB7 ${created.llm})`);
855
939
  console.log(` sky agent message ${created.slug} "hello"`);
@@ -862,7 +946,13 @@ program.command("deploy").description("re-apply ./agent.toml to the existing age
862
946
  const { file, spec } = readAgentFile(path);
863
947
  if (!file.slug) {
864
948
  console.log("No slug in the file yet \u2014 running launch instead.");
865
- const { agent: created } = await api("POST", "/api/v1/agents", spec);
949
+ const { vcpus, memoryMb, ...specBody } = spec;
950
+ const { agent: created } = await api("POST", "/api/v1/agents", specBody);
951
+ await api("POST", "/api/v1/sessions", {
952
+ agent: created.slug,
953
+ ...vcpus !== void 0 ? { vcpus } : {},
954
+ ...memoryMb !== void 0 ? { memoryMb } : {}
955
+ });
866
956
  stampSlug(path, created.slug);
867
957
  console.log(`Launched ${created.slug}`);
868
958
  return;
@@ -135,7 +135,7 @@ function replyParts(reply) {
135
135
  }
136
136
  async function postChatProxy(args) {
137
137
  const url = new URL(
138
- `/api/v1/agents/${encodeURIComponent(args.agentRouteId)}/messages`,
138
+ `/api/v1/sessions/${encodeURIComponent(args.agentRouteId)}/messages`,
139
139
  normalizeBaseUrl(args.baseUrl)
140
140
  );
141
141
  const headers = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsky/sky",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
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",