stackai 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/dist/cli.js +174 -36
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -441,7 +441,7 @@ var AgentSession = class {
441
441
  import { promises as fs2 } from "fs";
442
442
  import os from "os";
443
443
  import path2 from "path";
444
- var DEFAULT_API_URL = "https://stack-ai-web-one.vercel.app";
444
+ var DEFAULT_API_URL = "https://stackaiapi-production.up.railway.app";
445
445
  var CONFIG_DIR = path2.join(os.homedir(), ".stackai");
446
446
  var CONFIG_PATH = path2.join(CONFIG_DIR, "config.json");
447
447
  async function readConfig() {
@@ -462,6 +462,9 @@ async function writeConfig(config) {
462
462
  await fs2.mkdir(CONFIG_DIR, { recursive: true });
463
463
  await fs2.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2), "utf8");
464
464
  }
465
+ async function clearConfig() {
466
+ await fs2.rm(CONFIG_PATH, { force: true });
467
+ }
465
468
 
466
469
  // src/api.ts
467
470
  var ApiClient = class {
@@ -594,7 +597,12 @@ import { Box as Box3, Text as Text3, useApp as useApp2 } from "ink";
594
597
  import Spinner2 from "ink-spinner";
595
598
  import TextInput from "ink-text-input";
596
599
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
597
- function Interactive({ session, cwd }) {
600
+ var ACCENT = "#e8ff47";
601
+ var LOGO = [
602
+ "\u2588\u2580\u2580 \u2580\u2588\u2580 \u2588\u2580\u2588 \u2588\u2580\u2580 \u2588\u2584\u2580 \u2588\u2580\u2588 \u2588",
603
+ "\u2584\u2584\u2588 \u2588 \u2588\u2580\u2588 \u2588\u2584\u2584 \u2588\u2580\u2584 \u2588\u2580\u2588 \u2588"
604
+ ];
605
+ function Interactive({ session, cwd, version }) {
598
606
  const { exit } = useApp2();
599
607
  const [history, setHistory] = useState2([]);
600
608
  const [input, setInput] = useState2("");
@@ -619,11 +627,10 @@ function Interactive({ session, cwd }) {
619
627
  setHistory((prev) => {
620
628
  const last = prev[prev.length - 1];
621
629
  if (!last || last.kind !== "agent") return prev;
622
- const updated = {
623
- kind: "agent",
624
- entries: applyStep(last.entries, step)
625
- };
626
- return [...prev.slice(0, -1), updated];
630
+ return [
631
+ ...prev.slice(0, -1),
632
+ { kind: "agent", entries: applyStep(last.entries, step) }
633
+ ];
627
634
  });
628
635
  };
629
636
  try {
@@ -635,19 +642,37 @@ function Interactive({ session, cwd }) {
635
642
  }
636
643
  }
637
644
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", paddingY: 1, children: [
638
- /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
639
- /* @__PURE__ */ jsxs3(Text3, { color: "#e8ff47", bold: true, children: [
640
- "StackAI",
641
- " "
642
- ] }),
643
- /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
644
- "\u2014 ",
645
- cwd
646
- ] })
647
- ] }),
645
+ /* @__PURE__ */ jsxs3(
646
+ Box3,
647
+ {
648
+ flexDirection: "column",
649
+ borderStyle: "round",
650
+ borderColor: ACCENT,
651
+ paddingX: 2,
652
+ paddingY: 1,
653
+ children: [
654
+ LOGO.map((line, i) => /* @__PURE__ */ jsx3(Text3, { color: ACCENT, bold: true, children: line }, i)),
655
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
656
+ "v",
657
+ version,
658
+ " \xB7 MiMo v2.5 Pro \xB7 1M context"
659
+ ] }) }),
660
+ /* @__PURE__ */ jsx3(Text3, { color: "gray", children: cwd })
661
+ ]
662
+ }
663
+ ),
664
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
665
+ "Describe what you want to build \xB7 type",
666
+ " ",
667
+ /* @__PURE__ */ jsx3(Text3, { color: ACCENT, children: "/exit" }),
668
+ " to quit"
669
+ ] }) }),
648
670
  history.map(
649
671
  (block, i) => block.kind === "user" ? /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, children: [
650
- /* @__PURE__ */ jsx3(Text3, { color: "#e8ff47", children: "\u203A " }),
672
+ /* @__PURE__ */ jsxs3(Text3, { color: ACCENT, bold: true, children: [
673
+ "\u203A",
674
+ " "
675
+ ] }),
651
676
  /* @__PURE__ */ jsx3(Text3, { children: block.text })
652
677
  ] }, i) : /* @__PURE__ */ jsx3(EntryLines, { entries: block.entries }, i)
653
678
  ),
@@ -655,38 +680,118 @@ function Interactive({ session, cwd }) {
655
680
  "Error: ",
656
681
  error
657
682
  ] }) }),
658
- /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: busy ? /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
659
- /* @__PURE__ */ jsx3(Spinner2, { type: "dots" }),
660
- " working\u2026"
661
- ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
662
- /* @__PURE__ */ jsx3(Text3, { color: "#e8ff47", children: "\u203A " }),
663
- /* @__PURE__ */ jsx3(
664
- TextInput,
683
+ /* @__PURE__ */ jsx3(
684
+ Box3,
685
+ {
686
+ marginTop: 1,
687
+ borderStyle: "round",
688
+ borderColor: busy ? "gray" : ACCENT,
689
+ paddingX: 1,
690
+ children: busy ? /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
691
+ /* @__PURE__ */ jsx3(Spinner2, { type: "dots" }),
692
+ " working\u2026"
693
+ ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
694
+ /* @__PURE__ */ jsx3(Text3, { color: ACCENT, children: "\u203A " }),
695
+ /* @__PURE__ */ jsx3(
696
+ TextInput,
697
+ {
698
+ value: input,
699
+ onChange: setInput,
700
+ onSubmit,
701
+ placeholder: "message StackAI\u2026"
702
+ }
703
+ )
704
+ ] })
705
+ }
706
+ )
707
+ ] });
708
+ }
709
+
710
+ // src/ui/login-view.tsx
711
+ import { useState as useState3 } from "react";
712
+ import { Box as Box4, Text as Text4, useApp as useApp3 } from "ink";
713
+ import TextInput2 from "ink-text-input";
714
+ import Spinner3 from "ink-spinner";
715
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
716
+ function LoginView() {
717
+ const { exit } = useApp3();
718
+ const [value, setValue] = useState3("");
719
+ const [phase, setPhase] = useState3("input");
720
+ const [message, setMessage] = useState3("");
721
+ async function submit(raw) {
722
+ const key = raw.trim();
723
+ if (!key) return;
724
+ setPhase("checking");
725
+ try {
726
+ await writeConfig({ apiKey: key, apiUrl: DEFAULT_API_URL });
727
+ const verify = await new ApiClient({
728
+ apiKey: key,
729
+ apiUrl: DEFAULT_API_URL
730
+ }).verify();
731
+ setMessage(`Logged in as @${verify.user.username} \xB7 ${verify.user.tier} tier`);
732
+ setPhase("done");
733
+ } catch (err) {
734
+ setMessage(err instanceof Error ? err.message : String(err));
735
+ setPhase("error");
736
+ } finally {
737
+ setTimeout(() => exit(), 60);
738
+ }
739
+ }
740
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingY: 1, children: [
741
+ /* @__PURE__ */ jsxs4(Box4, { children: [
742
+ /* @__PURE__ */ jsxs4(Text4, { color: "#e8ff47", bold: true, children: [
743
+ "StackAI",
744
+ " "
745
+ ] }),
746
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "login" })
747
+ ] }),
748
+ phase === "input" && /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
749
+ /* @__PURE__ */ jsx4(Text4, { children: "API key " }),
750
+ /* @__PURE__ */ jsx4(Text4, { color: "#e8ff47", children: "\u203A " }),
751
+ /* @__PURE__ */ jsx4(
752
+ TextInput2,
665
753
  {
666
- value: input,
667
- onChange: setInput,
668
- onSubmit,
669
- placeholder: "type a message, /exit to quit"
754
+ value,
755
+ onChange: setValue,
756
+ onSubmit: submit,
757
+ mask: "*",
758
+ placeholder: "sk_live_..."
670
759
  }
671
760
  )
761
+ ] }),
762
+ phase === "checking" && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text4, { color: "gray", children: [
763
+ /* @__PURE__ */ jsx4(Spinner3, { type: "dots" }),
764
+ " verifying\u2026"
765
+ ] }) }),
766
+ phase === "done" && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text4, { color: "green", children: [
767
+ "\u2713 ",
768
+ message
769
+ ] }) }),
770
+ phase === "error" && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
771
+ "\u2717 ",
772
+ message
672
773
  ] }) })
673
774
  ] });
674
775
  }
675
776
 
676
777
  // src/cli.tsx
677
- import { jsx as jsx4 } from "react/jsx-runtime";
678
- var VERSION = "0.1.0";
778
+ import { jsx as jsx5 } from "react/jsx-runtime";
779
+ var VERSION = "0.1.2";
679
780
  var HELP = `
680
781
  StackAI \u2014 AI coding agent in your terminal
681
782
 
682
783
  Usage
683
784
  $ stackai Start an interactive chat session
684
785
  $ stackai <prompt> Run the agent once, then exit
685
- $ stackai auth <api_key> Save your API key
686
- $ stackai auth <key> <url> ...with a custom API URL
786
+ $ stackai login Log in (prompts for your API key)
787
+ $ stackai login <api_key> Log in directly
687
788
  $ stackai whoami Show current user + usage
789
+ $ stackai logout Remove your saved API key
688
790
  $ stackai --help
689
791
  $ stackai --version
792
+
793
+ Advanced
794
+ $ stackai auth <key> [url] Save key with a custom API URL
690
795
  `;
691
796
  async function main() {
692
797
  const args = process.argv.slice(2);
@@ -699,6 +804,37 @@ async function main() {
699
804
  console.log(VERSION);
700
805
  return;
701
806
  }
807
+ if (first === "login") {
808
+ const key = args[1];
809
+ if (key) {
810
+ await writeConfig({ apiKey: key, apiUrl: DEFAULT_API_URL });
811
+ try {
812
+ const verify = await new ApiClient({
813
+ apiKey: key,
814
+ apiUrl: DEFAULT_API_URL
815
+ }).verify();
816
+ console.log(
817
+ `\u2713 Logged in as @${verify.user.username} \xB7 ${verify.user.tier} tier`
818
+ );
819
+ } catch (err) {
820
+ console.error(`\u2717 ${err instanceof Error ? err.message : String(err)}`);
821
+ process.exitCode = 1;
822
+ }
823
+ return;
824
+ }
825
+ if (!process.stdin.isTTY) {
826
+ console.error("Run: stackai login <api_key>");
827
+ process.exitCode = 1;
828
+ return;
829
+ }
830
+ render(/* @__PURE__ */ jsx5(LoginView, {}));
831
+ return;
832
+ }
833
+ if (first === "logout") {
834
+ await clearConfig();
835
+ console.log("\u2713 Logged out");
836
+ return;
837
+ }
702
838
  if (first === "auth") {
703
839
  const key = args[1];
704
840
  if (!key) {
@@ -713,7 +849,7 @@ async function main() {
713
849
  }
714
850
  const config = await readConfig();
715
851
  if (!config) {
716
- console.error("Not authenticated. Run: stackai auth <api_key>");
852
+ console.error("Not logged in. Run: stackai login");
717
853
  process.exitCode = 1;
718
854
  return;
719
855
  }
@@ -744,11 +880,13 @@ async function main() {
744
880
  process.exitCode = 1;
745
881
  return;
746
882
  }
747
- render(/* @__PURE__ */ jsx4(Interactive, { session: runner.session(cwd), cwd }));
883
+ render(
884
+ /* @__PURE__ */ jsx5(Interactive, { session: runner.session(cwd), cwd, version: VERSION })
885
+ );
748
886
  return;
749
887
  }
750
888
  const prompt = args.join(" ");
751
- render(/* @__PURE__ */ jsx4(RunView, { runner, prompt, cwd }));
889
+ render(/* @__PURE__ */ jsx5(RunView, { runner, prompt, cwd }));
752
890
  }
753
891
  main().catch((err) => {
754
892
  console.error(err instanceof Error ? err.message : String(err));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackai",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "StackAI — AI coding agent in your terminal. Read, write, and edit code with AI.",
5
5
  "type": "module",
6
6
  "bin": {