@boole-digital/cli 0.2.5 → 0.3.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.
- package/dist/index.js +86 -1
- package/package.json +28 -8
package/dist/index.js
CHANGED
|
@@ -685,6 +685,28 @@ function open(s) {
|
|
|
685
685
|
});
|
|
686
686
|
});
|
|
687
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
|
+
}
|
|
688
710
|
async function runRemoteInherit(command) {
|
|
689
711
|
const s = requireSession();
|
|
690
712
|
const conn = await open(s);
|
|
@@ -721,6 +743,20 @@ here.
|
|
|
721
743
|
\`\`\`
|
|
722
744
|
3. Operate the box exactly as that guide says.
|
|
723
745
|
|
|
746
|
+
## Building anything non-trivial? PLAN FIRST.
|
|
747
|
+
Before you hand-write a strategy, spawn a template, or spelunk the box for *how* to
|
|
748
|
+
do something, ask the harness how to build it:
|
|
749
|
+
\`\`\`
|
|
750
|
+
boole plan "<the user's request, in plain English>"
|
|
751
|
+
\`\`\`
|
|
752
|
+
The harness holds the full picture \u2014 system prompt, tools, the real trading surface \u2014
|
|
753
|
+
that you CANNOT see from the outside. \`boole plan\` returns a concrete implementation
|
|
754
|
+
plan: the exact \`ti.*\` calls + signatures, file paths, and which template/gate to use,
|
|
755
|
+
grounded in what THIS box actually exposes. Follow it, then implement over \`boole ssh\`.
|
|
756
|
+
Do NOT guess API shapes, web-search, or hunt through template files \u2014 planning replaces
|
|
757
|
+
that. (If the box's gateway is older and doesn't support planning, \`boole plan\` will
|
|
758
|
+
say so \u2014 fall back to \`OPERATOR.md\`.)
|
|
759
|
+
|
|
724
760
|
## The model
|
|
725
761
|
- The box IS the gateway. You SSH into it with \`boole ssh\` and drive its **harness**.
|
|
726
762
|
- You take the user's request **in plain English** ("buy $100 of BTC") and carry
|
|
@@ -765,8 +801,53 @@ function init(opts = {}) {
|
|
|
765
801
|
log(` Your agent reads these rules and operates your trading computer through ${c.cyan("boole")}.`);
|
|
766
802
|
}
|
|
767
803
|
|
|
804
|
+
// src/plan.ts
|
|
805
|
+
async function plan({ request }) {
|
|
806
|
+
const req = (request || "").trim();
|
|
807
|
+
if (!req) die('Usage: boole plan "<what you want to build>"');
|
|
808
|
+
if (req.length > 4e3) die("Request too long (max 4000 chars). Trim it down.");
|
|
809
|
+
info("Asking your box how to build this \u2014 the harness has the full picture (this can take up to a minute)\u2026");
|
|
810
|
+
const payload = Buffer.from(JSON.stringify({ request: req })).toString("base64");
|
|
811
|
+
const MARK = "__BOOLE_HTTP__";
|
|
812
|
+
const cmd = `printf %s '${payload}' | base64 -d | curl -s --max-time 175 -w '\\n${MARK}%{http_code}' -X POST http://localhost:3000/api/plan -H 'content-type: application/json' -d @-`;
|
|
813
|
+
const { code, stdout, stderr } = await runRemote(cmd);
|
|
814
|
+
if (!stdout) die(`Could not reach the planner on your box${code ? ` (exit ${code})` : ""}. ${stderr || ""}`.trim());
|
|
815
|
+
let body = stdout, http = 0;
|
|
816
|
+
const mi = stdout.lastIndexOf(MARK);
|
|
817
|
+
if (mi >= 0) {
|
|
818
|
+
body = stdout.slice(0, mi).trimEnd();
|
|
819
|
+
http = parseInt(stdout.slice(mi + MARK.length), 10) || 0;
|
|
820
|
+
}
|
|
821
|
+
if (http === 404) {
|
|
822
|
+
die("This box's gateway doesn't support planning yet (no /api/plan). Update the gateway to a build that includes it, or build directly with `boole ssh`.");
|
|
823
|
+
}
|
|
824
|
+
let res;
|
|
825
|
+
try {
|
|
826
|
+
res = JSON.parse(body);
|
|
827
|
+
} catch {
|
|
828
|
+
die(`Planner returned an unexpected response${http ? ` (HTTP ${http})` : ""}: ${body.slice(0, 300) || stderr || "empty"}`);
|
|
829
|
+
}
|
|
830
|
+
if (res?.error) die(`Planner error: ${res.error}`);
|
|
831
|
+
const planText = String(res?.plan || "").trim();
|
|
832
|
+
if (!planText) die("Planner returned no plan. Try again in a moment.");
|
|
833
|
+
if (res?.degraded) {
|
|
834
|
+
log();
|
|
835
|
+
warn(c.bold("Your Boole account is out of credit \u2014 this plan came from a fallback model."));
|
|
836
|
+
log(c.yellow(" Boole does not consider this model capable of this planning task; treat the plan below with caution."));
|
|
837
|
+
log(c.yellow(" To restore full-quality planning, either:"));
|
|
838
|
+
log(c.yellow(" \u2022 top up a small amount of credit, or"));
|
|
839
|
+
log(c.yellow(" \u2022 connect your GPT account for subscription-based usage."));
|
|
840
|
+
log(c.yellow(` Do this in the Boole web app under ${c.bold("Usage & model settings")} (/usage).`));
|
|
841
|
+
}
|
|
842
|
+
log();
|
|
843
|
+
log(planText);
|
|
844
|
+
log();
|
|
845
|
+
info("Build it over SSH exactly as above \u2014 the paths + calls are the ones your box actually exposes.");
|
|
846
|
+
if (res?.model) log(c.dim(` planner model: ${res.model}${res?.degraded ? " (fallback)" : ""}`));
|
|
847
|
+
}
|
|
848
|
+
|
|
768
849
|
// src/index.ts
|
|
769
|
-
var VERSION = "0.
|
|
850
|
+
var VERSION = "0.3.1";
|
|
770
851
|
function parse(argv) {
|
|
771
852
|
const _ = [];
|
|
772
853
|
const flags = {};
|
|
@@ -803,6 +884,7 @@ ${c.bold("Getting started")}
|
|
|
803
884
|
logout Sign out and clear the cached session
|
|
804
885
|
|
|
805
886
|
${c.bold("Operate the box")}
|
|
887
|
+
plan "<goal>" Ask the box's harness how to build something (returns an implementation plan)
|
|
806
888
|
ssh "<command>" Run a command on the connected box (this is how you operate it)
|
|
807
889
|
logs [name] Tail a strategy's logs
|
|
808
890
|
balances [--venue <v>] Equity + open positions
|
|
@@ -858,6 +940,9 @@ async function main() {
|
|
|
858
940
|
case "init":
|
|
859
941
|
init({ dir: _[1], force: !!flags.force });
|
|
860
942
|
break;
|
|
943
|
+
case "plan":
|
|
944
|
+
await plan({ request: _.slice(1).join(" ") });
|
|
945
|
+
break;
|
|
861
946
|
case "ssh": {
|
|
862
947
|
const command = _.slice(1).join(" ");
|
|
863
948
|
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.
|
|
4
|
-
"description": "Boole
|
|
3
|
+
"version": "0.3.1",
|
|
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": {
|
|
6
|
+
"bin": {
|
|
7
|
+
"boole": "dist/index.js"
|
|
8
|
+
},
|
|
7
9
|
"main": "dist/index.js",
|
|
8
|
-
"files": [
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/index.js",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
9
15
|
"license": "SEE LICENSE IN LICENSE",
|
|
10
|
-
"engines": {
|
|
11
|
-
|
|
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": {
|
|
14
|
-
|
|
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
|
},
|