@boole-digital/cli 0.1.0 → 0.1.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 +104 -78
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -372,6 +372,22 @@ function onboardingNotice() {
|
|
|
372
372
|
log(` Deploy your first trading computer there, then come back and run ${c.cyan("boole connect")}.`);
|
|
373
373
|
log("");
|
|
374
374
|
}
|
|
375
|
+
function operatingBrief() {
|
|
376
|
+
log("");
|
|
377
|
+
log(c.bold("How to operate this computer"));
|
|
378
|
+
log(" Trades and strategies go through the gateway gate \u2014 automatically tracked on your dashboard.");
|
|
379
|
+
log("");
|
|
380
|
+
log(` ${c.dim("# buy $100 of BTC (market)")}`);
|
|
381
|
+
log(c.cyan(" boole strategy spawn --template order_template.js --name btc-buy \\"));
|
|
382
|
+
log(c.cyan(" --param EXCHANGE=hyperliquid --param MARKET=BTC --param SIDE=buy \\"));
|
|
383
|
+
log(c.cyan(" --param ORDER_TYPE=market --param TOTAL_USD=100 --param LIMIT_PRICE=0"));
|
|
384
|
+
log("");
|
|
385
|
+
log(` Sell with ${c.dim("SIDE=sell")}. Other templates: ${c.dim("grid, twap, scale, stop, loop")}.`);
|
|
386
|
+
log(` Inspect: ${c.cyan("boole balances")} \xB7 ${c.cyan("boole strategy ls")} \xB7 ${c.cyan("boole logs <name>")} \xB7 ${c.cyan('boole ssh "<read cmd>"')}`);
|
|
387
|
+
log(` ${c.yellow("Never")} write files or run pm2 by hand \u2014 always use the gate (that is what keeps tracking correct).`);
|
|
388
|
+
log(` Drop the full rules into your coding agent: ${c.cyan("boole init")} ${c.dim("\u2192 CLAUDE.md / AGENTS.md / GEMINI.md")}`);
|
|
389
|
+
log("");
|
|
390
|
+
}
|
|
375
391
|
function printAgents(droplets) {
|
|
376
392
|
if (!droplets.length) {
|
|
377
393
|
onboardingNotice();
|
|
@@ -414,13 +430,27 @@ async function summary() {
|
|
|
414
430
|
ok(`Logged in as ${c.bold(creds.user.email || creds.user.id)}${creds.user.role ? c.dim(` \xB7 ${creds.user.role}`) : ""}`);
|
|
415
431
|
const api = new BooleApi();
|
|
416
432
|
let droplets = [];
|
|
433
|
+
let listErr = "";
|
|
417
434
|
try {
|
|
418
435
|
droplets = await api.listDroplets();
|
|
419
436
|
} catch (e) {
|
|
420
|
-
|
|
421
|
-
return;
|
|
437
|
+
listErr = e?.message || String(e);
|
|
422
438
|
}
|
|
423
439
|
if (!droplets.length) {
|
|
440
|
+
const sess = loadSession();
|
|
441
|
+
if (sess?.ip) {
|
|
442
|
+
log("");
|
|
443
|
+
ok(`Connected to ${c.bold(sess.agent || sess.ip)} ${c.dim(`(${sess.ip})`)} ${c.dim("\xB7 cached session")}`);
|
|
444
|
+
if (listErr) log(c.dim(` (couldn't reach the account API: ${listErr})`));
|
|
445
|
+
else log(c.dim(` This account has no computer on file, but \`boole ssh\` + \`boole strategy \u2026\` work against the connected box.`));
|
|
446
|
+
log(c.dim(` If you expected a computer here, you may be logged in as a different account than the one that owns it.`));
|
|
447
|
+
operatingBrief();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (listErr) {
|
|
451
|
+
warn(`Could not list trading computers: ${listErr}`);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
424
454
|
onboardingNotice();
|
|
425
455
|
return;
|
|
426
456
|
}
|
|
@@ -428,17 +458,18 @@ async function summary() {
|
|
|
428
458
|
log(c.bold(`Trading computers (${droplets.length})`));
|
|
429
459
|
printAgents(droplets);
|
|
430
460
|
const pick = pickAgentId(droplets);
|
|
431
|
-
if (
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
461
|
+
if (pick) {
|
|
462
|
+
log("");
|
|
463
|
+
log(c.bold(`Snapshot \u2014 ${pick.name}`));
|
|
464
|
+
try {
|
|
465
|
+
const health = await api.getHealth(pick.id);
|
|
466
|
+
ok(`online${health.defaultModel ? c.dim(` \xB7 model ${health.defaultModel}`) : ""}`);
|
|
467
|
+
await printBalances(api, pick.id, "hyperliquid");
|
|
468
|
+
} catch {
|
|
469
|
+
warn("trading computer unreachable (tunnel may be waking up \u2014 retry in a moment)");
|
|
470
|
+
}
|
|
440
471
|
}
|
|
441
|
-
|
|
472
|
+
operatingBrief();
|
|
442
473
|
}
|
|
443
474
|
async function printBalances(api, id, exchange) {
|
|
444
475
|
try {
|
|
@@ -718,80 +749,75 @@ async function strategyDoctor(name) {
|
|
|
718
749
|
// src/rules.ts
|
|
719
750
|
import { writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
|
|
720
751
|
import { join as join2, resolve } from "node:path";
|
|
721
|
-
var OPERATING_RULES = `# Boole Trading Computer \u2014 Operating Rules (READ FIRST
|
|
722
|
-
|
|
723
|
-
You operate
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
752
|
+
var OPERATING_RULES = `# Boole Trading Computer \u2014 Operating Rules (READ FIRST)
|
|
753
|
+
|
|
754
|
+
You operate the customer's **live** crypto trading computer by working ON the box
|
|
755
|
+
(over \`boole ssh\`) and using its on-box **harness** \u2014 the gateway's spawn GATE,
|
|
756
|
+
which places and TRACKS every order and strategy on the dashboard. Real money is
|
|
757
|
+
at risk, so be deliberate \u2014 but the user asked you to operate their computer, so
|
|
758
|
+
OPERATE IT. Place the trades they ask for; don't refuse or interrogate over
|
|
759
|
+
routine orders.
|
|
760
|
+
|
|
761
|
+
## What "the harness" is (and why you go through it)
|
|
762
|
+
The box runs a gateway that exposes a spawn GATE. You place trades and run
|
|
763
|
+
strategies by spawning a known-good TEMPLATE through that gate \u2014 NEVER by writing
|
|
764
|
+
files or starting processes yourself. The gate registers the run, wires up
|
|
765
|
+
tracking, sets STRATEGY_NAME/RUN_ID, and starts it, so it always shows on the
|
|
766
|
+
dashboard with accounting. \`boole strategy spawn\` is simply how you call that
|
|
767
|
+
gate over SSH. Going around it (hand-writing a file, raw \`pm2 start\`) makes the
|
|
768
|
+
order **silently** untracked \u2014 that is the one thing you must never do.
|
|
769
|
+
|
|
770
|
+
## Boot (every session)
|
|
771
|
+
1. \`boole status\` \u2014 see who you're logged in as.
|
|
772
|
+
2. \`boole ssh "whoami"\` \u2014 if it connects, you HAVE a usable box; proceed. A
|
|
773
|
+
connected session is enough. Do NOT refuse to work just because \`status\`
|
|
774
|
+
doesn't list a computer for this account \u2014 that only means the web API has
|
|
775
|
+
none on file, not that you can't operate the connected box. If \`boole ssh\`
|
|
776
|
+
fails, tell the user to run \`boole connect\`.
|
|
777
|
+
|
|
778
|
+
## Placing a trade \u2014 just do it
|
|
779
|
+
"buy/sell $X of <coin>" is one market order. Place it through the gate with
|
|
780
|
+
order_template. Do NOT quiz the user about venue/leverage for a routine order \u2014
|
|
781
|
+
use the defaults and report the fill:
|
|
782
|
+
|
|
783
|
+
boole strategy spawn --template order_template.js --name <coin>-buy \\
|
|
784
|
+
--param EXCHANGE=hyperliquid --param MARKET=<COIN> --param SIDE=buy \\
|
|
785
|
+
--param ORDER_TYPE=market --param TOTAL_USD=<X> --param LIMIT_PRICE=0
|
|
786
|
+
|
|
787
|
+
Defaults when unspecified: EXCHANGE=hyperliquid, ORDER_TYPE=market, LIMIT_PRICE=0,
|
|
788
|
+
no leverage. Sell with SIDE=sell. Limit order: ORDER_TYPE=limit + LIMIT_PRICE=<p>.
|
|
789
|
+
Pick a unique --name (if the gate says it exists, add a suffix). After it returns,
|
|
790
|
+
tell the user what filled. Ask FIRST only if genuinely ambiguous (which coin? which
|
|
791
|
+
account has funds?) or clearly risky (size far beyond their balance, leverage they
|
|
792
|
+
didn't request) \u2014 a plain market buy the user requested is NOT one of those.
|
|
793
|
+
|
|
794
|
+
## Running a strategy \u2014 same gate, different template
|
|
795
|
+
boole strategy spawn --template <template.js> --name <name> --param KEY=VALUE ...
|
|
796
|
+
|
|
797
|
+
Templates (required params):
|
|
754
798
|
- order_template.js \u2014 single order: EXCHANGE, MARKET, SIDE(buy|sell), ORDER_TYPE(market|limit), TOTAL_USD, LIMIT_PRICE(0 for market)
|
|
755
799
|
- grid_template.js \u2014 grid: EXCHANGE, SYMBOL, LEVELS_PER_SIDE, ORDER_SIZE_USD, LEVERAGE, MAX_EXPOSURE_USD
|
|
756
800
|
- twap_template.js \u2014 TWAP: EXCHANGE, MARKET, SIDE, TOTAL_USD, DURATION_MIN, SLICES
|
|
757
801
|
- scale_template.js \u2014 ladder: EXCHANGE, MARKET, SIDE, TOTAL_USD, PRICE_LOW, PRICE_HIGH, LEVELS
|
|
758
802
|
- stop_template.js \u2014 conditional (no position yet): EXCHANGE, MARKET, SIDE, STOP_KIND(stop_market|stop_limit|tp_market|tp_limit), TOTAL_USD, TRIGGER_PRICE, LIMIT_PRICE(0 for *_market)
|
|
759
|
-
- loop_template.js \u2014
|
|
760
|
-
|
|
761
|
-
Example:
|
|
762
|
-
|
|
763
|
-
boole strategy spawn --template loop_template.js --name btc-watch \\
|
|
764
|
-
--param EXCHANGE=hyperliquid --param MARKET=BTC --param POLL_SEC=10
|
|
803
|
+
- loop_template.js \u2014 poll loop / price watcher: EXCHANGE, MARKET, POLL_SEC
|
|
765
804
|
|
|
766
|
-
If
|
|
767
|
-
|
|
768
|
-
another from the list or ask the user.
|
|
769
|
-
Only use a template above. Do NOT hand-roll custom strategy files. If you need
|
|
770
|
-
something no template covers, STOP and ask the user.
|
|
805
|
+
If the gate names a missing param, add it and retry. If it says a template is not
|
|
806
|
+
found, that one isn't installed on this box \u2014 pick another or ask.
|
|
771
807
|
|
|
772
|
-
##
|
|
808
|
+
## Inspect (read-only) anytime
|
|
773
809
|
- \`boole status\` / \`boole balances [--venue <v>]\` \u2014 identity, equity, positions
|
|
774
|
-
- \`boole strategy ls\` \u2014 running strategies
|
|
775
|
-
- \`boole strategy doctor <name>\` \u2014 health + tracking check
|
|
810
|
+
- \`boole strategy ls\` / \`boole strategy doctor <name>\` \u2014 running strategies + tracking
|
|
776
811
|
- \`boole logs <name>\` \u2014 tail a strategy's logs
|
|
777
|
-
- \`boole ssh "<read-only
|
|
778
|
-
|
|
779
|
-
##
|
|
780
|
-
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
-
|
|
784
|
-
-
|
|
785
|
-
|
|
786
|
-
## Safety (real money)
|
|
787
|
-
- Trading is live. Prefer capital preservation. Confirm exchange state before acting.
|
|
788
|
-
- Never print or exfiltrate .env, API keys, or credentials.
|
|
789
|
-
- Never restart the gateway.
|
|
790
|
-
- Ask the user before destructive actions (closing positions, stopping strategies).
|
|
791
|
-
|
|
792
|
-
## Notes
|
|
793
|
-
- Some gateway internals are intentionally not readable from your account \u2014 by design. Use the \`boole\` verbs; you don't need them.
|
|
794
|
-
- A commit is not done until \`boole strategy doctor\` confirms it. If it did not register, fix it before moving on.
|
|
812
|
+
- \`boole ssh "<read-only cmd>"\` \u2014 cat / ls / pm2 list / curl localhost:3000/health
|
|
813
|
+
|
|
814
|
+
## The hard lines (protect real money + tracking)
|
|
815
|
+
- Place trades + strategies ONLY through the gate (\`boole strategy spawn\`). NEVER
|
|
816
|
+
write strategy files over SSH or \`pm2 start\` by hand \u2014 that bypasses tracking and
|
|
817
|
+
the order won't appear on the dashboard.
|
|
818
|
+
- Never print or exfiltrate .env, keys, or credentials. Never restart the gateway.
|
|
819
|
+
- Ask before genuinely destructive actions (closing positions, stopping a running
|
|
820
|
+
strategy). A plain market buy the user asked for is NOT destructive \u2014 place it.
|
|
795
821
|
`;
|
|
796
822
|
var FILES = ["CLAUDE.md", "AGENTS.md", "GEMINI.md"];
|
|
797
823
|
function init(opts = {}) {
|
|
@@ -818,7 +844,7 @@ function init(opts = {}) {
|
|
|
818
844
|
}
|
|
819
845
|
|
|
820
846
|
// src/index.ts
|
|
821
|
-
var VERSION = "0.1.
|
|
847
|
+
var VERSION = "0.1.1";
|
|
822
848
|
function parse(argv) {
|
|
823
849
|
const _ = [];
|
|
824
850
|
const flags = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boole-digital/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Boole — install, sign in, and operate your trading computer from the terminal (Claude Code, Codex, Gemini).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": { "boole": "dist/index.js" },
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"files": ["dist/index.js", "README.md", "LICENSE"],
|
|
9
9
|
"license": "SEE LICENSE IN LICENSE",
|
|
10
10
|
"engines": { "node": ">=18" },
|
|
11
|
-
"repository": { "type": "git", "url": "github
|
|
11
|
+
"repository": { "type": "git", "url": "git+https://github.com/Boole-Digital/portara-desktop.git" },
|
|
12
12
|
"homepage": "https://trade.boole.markets",
|
|
13
13
|
"publishConfig": { "access": "public" },
|
|
14
14
|
"keywords": ["boole", "trading", "cli", "claude-code", "codex", "gemini"],
|