@boole-digital/cli 0.2.4 → 0.3.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.
Files changed (2) hide show
  1. package/dist/index.js +79 -3
  2. package/package.json +28 -8
package/dist/index.js CHANGED
@@ -356,8 +356,23 @@ var BooleApi = class {
356
356
  method: "POST",
357
357
  body: JSON.stringify({ accessCode: (accessCode || "").trim() })
358
358
  });
359
- const pw = body?.password ?? body?.ssh_password ?? body?.data?.password ?? body?.data?.ssh_password;
360
- if (!pw) throw new Error("SSH password not present in API response (check field name in api.ts:getSshPassword).");
359
+ const cand = [
360
+ body?.data?.droplet_password,
361
+ body?.data?.password,
362
+ body?.data?.ssh_password,
363
+ body?.data?.sshPassword,
364
+ body?.droplet_password,
365
+ body?.password,
366
+ body?.ssh_password,
367
+ body?.sshPassword,
368
+ body?.result?.password
369
+ ];
370
+ const pw = cand.find((v) => typeof v === "string" && v.length > 0);
371
+ if (!pw) {
372
+ throw new Error(
373
+ "SSH password not present. topKeys=" + JSON.stringify(Object.keys(body || {})) + " dataKeys=" + JSON.stringify(Object.keys(body?.data || {}))
374
+ );
375
+ }
361
376
  return String(pw);
362
377
  }
363
378
  // ---- talk to the gateway on the box (via the ownership-checked proxy) ---
@@ -670,6 +685,28 @@ function open(s) {
670
685
  });
671
686
  });
672
687
  }
688
+ async function runRemote(command) {
689
+ const s = requireSession();
690
+ const conn = await open(s);
691
+ try {
692
+ return await new Promise((resolve2, reject) => {
693
+ conn.exec(command, (err2, stream) => {
694
+ if (err2) return reject(new Error(friendly(err2)));
695
+ let stdout = "";
696
+ let stderr = "";
697
+ stream.on("close", (code) => resolve2({ code: code ?? 0, stdout, stderr }));
698
+ stream.on("data", (d) => {
699
+ stdout += d.toString();
700
+ });
701
+ stream.stderr.on("data", (d) => {
702
+ stderr += d.toString();
703
+ });
704
+ });
705
+ });
706
+ } finally {
707
+ conn.end();
708
+ }
709
+ }
673
710
  async function runRemoteInherit(command) {
674
711
  const s = requireSession();
675
712
  const conn = await open(s);
@@ -750,8 +787,43 @@ function init(opts = {}) {
750
787
  log(` Your agent reads these rules and operates your trading computer through ${c.cyan("boole")}.`);
751
788
  }
752
789
 
790
+ // src/plan.ts
791
+ async function plan({ request }) {
792
+ const req = (request || "").trim();
793
+ if (!req) die('Usage: boole plan "<what you want to build>"');
794
+ if (req.length > 4e3) die("Request too long (max 4000 chars). Trim it down.");
795
+ info("Asking your box how to build this \u2014 the harness has the full picture (this can take up to a minute)\u2026");
796
+ const payload = Buffer.from(JSON.stringify({ request: req })).toString("base64");
797
+ const cmd = `printf %s '${payload}' | base64 -d | curl -s --max-time 175 -X POST http://localhost:3000/api/plan -H 'content-type: application/json' -d @-`;
798
+ const { code, stdout, stderr } = await runRemote(cmd);
799
+ if (!stdout) die(`Could not reach the planner on your box${code ? ` (exit ${code})` : ""}. ${stderr || ""}`.trim());
800
+ let res;
801
+ try {
802
+ res = JSON.parse(stdout);
803
+ } catch {
804
+ die(`Planner returned an unexpected response: ${stdout.slice(0, 300) || stderr || "empty"}`);
805
+ }
806
+ if (res?.error) die(`Planner error: ${res.error}`);
807
+ const planText = String(res?.plan || "").trim();
808
+ if (!planText) die("Planner returned no plan. Try again in a moment.");
809
+ if (res?.degraded) {
810
+ log();
811
+ warn(c.bold("Your Boole account is out of credit \u2014 this plan came from a fallback model."));
812
+ log(c.yellow(" Boole does not consider this model capable of this planning task; treat the plan below with caution."));
813
+ log(c.yellow(" To restore full-quality planning, either:"));
814
+ log(c.yellow(" \u2022 top up a small amount of credit, or"));
815
+ log(c.yellow(" \u2022 connect your GPT account for subscription-based usage."));
816
+ log(c.yellow(` Do this in the Boole web app under ${c.bold("Usage & model settings")} (/usage).`));
817
+ }
818
+ log();
819
+ log(planText);
820
+ log();
821
+ info("Build it over SSH exactly as above \u2014 the paths + calls are the ones your box actually exposes.");
822
+ if (res?.model) log(c.dim(` planner model: ${res.model}${res?.degraded ? " (fallback)" : ""}`));
823
+ }
824
+
753
825
  // src/index.ts
754
- var VERSION = "0.2.4";
826
+ var VERSION = "0.3.0";
755
827
  function parse(argv) {
756
828
  const _ = [];
757
829
  const flags = {};
@@ -788,6 +860,7 @@ ${c.bold("Getting started")}
788
860
  logout Sign out and clear the cached session
789
861
 
790
862
  ${c.bold("Operate the box")}
863
+ plan "<goal>" Ask the box's harness how to build something (returns an implementation plan)
791
864
  ssh "<command>" Run a command on the connected box (this is how you operate it)
792
865
  logs [name] Tail a strategy's logs
793
866
  balances [--venue <v>] Equity + open positions
@@ -843,6 +916,9 @@ async function main() {
843
916
  case "init":
844
917
  init({ dir: _[1], force: !!flags.force });
845
918
  break;
919
+ case "plan":
920
+ await plan({ request: _.slice(1).join(" ") });
921
+ break;
846
922
  case "ssh": {
847
923
  const command = _.slice(1).join(" ");
848
924
  if (!command) die('Usage: boole ssh "<command>"');
package/package.json CHANGED
@@ -1,17 +1,37 @@
1
1
  {
2
2
  "name": "@boole-digital/cli",
3
- "version": "0.2.4",
4
- "description": "Boole install, sign in, and operate your trading computer from the terminal (Claude Code, Codex, Gemini).",
3
+ "version": "0.3.0",
4
+ "description": "Boole \u2014 install, sign in, and operate your trading computer from the terminal (Claude Code, Codex, Gemini).",
5
5
  "type": "module",
6
- "bin": { "boole": "dist/index.js" },
6
+ "bin": {
7
+ "boole": "dist/index.js"
8
+ },
7
9
  "main": "dist/index.js",
8
- "files": ["dist/index.js", "README.md", "LICENSE"],
10
+ "files": [
11
+ "dist/index.js",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
9
15
  "license": "SEE LICENSE IN LICENSE",
10
- "engines": { "node": ">=18" },
11
- "repository": { "type": "git", "url": "git+https://github.com/Boole-Digital/portara-desktop.git" },
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/Boole-Digital/portara-desktop.git"
22
+ },
12
23
  "homepage": "https://trade.boole.markets",
13
- "publishConfig": { "access": "public" },
14
- "keywords": ["boole", "trading", "cli", "claude-code", "codex", "gemini"],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "keywords": [
28
+ "boole",
29
+ "trading",
30
+ "cli",
31
+ "claude-code",
32
+ "codex",
33
+ "gemini"
34
+ ],
15
35
  "dependencies": {
16
36
  "ssh2": "^1.16.0"
17
37
  },