openbroker 1.9.4 → 1.9.5
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/CHANGELOG.md +5 -0
- package/README.md +15 -0
- package/SKILL.md +1 -1
- package/bin/cli.ts +4 -2
- package/dist/setup/install.js +100 -3
- package/dist/setup/package-catalog.d.ts +12 -0
- package/dist/setup/package-catalog.d.ts.map +1 -0
- package/dist/setup/package-catalog.js +36 -0
- package/dist/setup/package-catalog.test.d.ts +2 -0
- package/dist/setup/package-catalog.test.d.ts.map +1 -0
- package/dist/setup/package-catalog.test.js +31 -0
- package/package.json +4 -3
- package/scripts/setup/install.ts +110 -3
- package/scripts/setup/package-catalog.test.ts +50 -0
- package/scripts/setup/package-catalog.ts +49 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Open Broker will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Added an allowlisted `openbroker install <package>` command for optional companion packages, initially supporting `monitoring` (`openbroker-monitoring`) and `extended` (`openbroker-extended`). Re-running installs the latest release; `--tag`, `--dry`, and `--list` are supported.
|
|
9
|
+
|
|
5
10
|
## [1.9.3] - 2026-06-23
|
|
6
11
|
|
|
7
12
|
### Changed
|
package/README.md
CHANGED
|
@@ -8,6 +8,18 @@ Hyperliquid trading CLI. Execute orders, manage positions, and run trading strat
|
|
|
8
8
|
npm install -g openbroker
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
### Companion packages
|
|
12
|
+
|
|
13
|
+
OpenBroker manages optional, allowlisted companion packages through the same CLI:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
openbroker install --list # Show supported packages
|
|
17
|
+
openbroker install monitoring # Local automation dashboard
|
|
18
|
+
openbroker install extended # Extended Exchange CLI
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The command installs globally through npm so each package's executable is available on your `PATH`. Re-run the same command to upgrade to the latest release, or pin a release with `--tag <version>`. Use `--dry` to preview the npm command.
|
|
22
|
+
|
|
11
23
|
### Codex: one-command install
|
|
12
24
|
|
|
13
25
|
Install the Codex skill, persistent CLI, and restricted API-wallet onboarding flow:
|
|
@@ -38,6 +50,9 @@ openbroker search --query GOLD # Find markets
|
|
|
38
50
|
|
|
39
51
|
```bash
|
|
40
52
|
npx openbroker@latest install --codex # Codex skill + CLI + API-wallet onboarding
|
|
53
|
+
openbroker install --list # List optional companion packages
|
|
54
|
+
openbroker install monitoring # Install or upgrade openbroker-monitoring
|
|
55
|
+
openbroker install extended # Install or upgrade openbroker-extended
|
|
41
56
|
openbroker setup --api-wallet # Recommended: restricted agent wallet + browser approval
|
|
42
57
|
openbroker setup # Interactive; API wallet is the default
|
|
43
58
|
```
|
package/SKILL.md
CHANGED
|
@@ -301,7 +301,7 @@ Use `--no-ws` only for debugging or networks that cannot maintain WebSockets. In
|
|
|
301
301
|
`openbroker-monitoring` is optional but useful for long-running automations, live debugging, and post-run inspection.
|
|
302
302
|
|
|
303
303
|
```bash
|
|
304
|
-
|
|
304
|
+
openbroker install monitoring
|
|
305
305
|
openbroker auto run ./my-automation.ts --id my-auto
|
|
306
306
|
openbroker-monitoring serve --host 127.0.0.1 --port 3001
|
|
307
307
|
```
|
package/bin/cli.ts
CHANGED
|
@@ -11,7 +11,7 @@ const scriptsDir = path.resolve(__dirname, '../scripts');
|
|
|
11
11
|
|
|
12
12
|
const commands: Record<string, { script: string; description: string }> = {
|
|
13
13
|
// Setup
|
|
14
|
-
'install': { script: 'setup/install.ts', description: 'Install
|
|
14
|
+
'install': { script: 'setup/install.ts', description: 'Install companion packages or an agent harness' },
|
|
15
15
|
'setup': { script: 'setup/onboard.ts', description: 'Interactive setup wizard' },
|
|
16
16
|
'onboard': { script: 'setup/onboard.ts', description: 'Interactive setup wizard' },
|
|
17
17
|
'approve-builder': { script: 'setup/approve-builder.ts', description: 'Approve builder fee' },
|
|
@@ -69,7 +69,7 @@ Open Broker - Hyperliquid Trading CLI
|
|
|
69
69
|
Usage: openbroker <command> [options]
|
|
70
70
|
|
|
71
71
|
Setup:
|
|
72
|
-
install Install OpenBroker for
|
|
72
|
+
install Install companion packages or OpenBroker for an agent harness
|
|
73
73
|
setup One-command setup (wallet + config + builder approval)
|
|
74
74
|
|
|
75
75
|
Info Commands:
|
|
@@ -139,6 +139,8 @@ Utility:
|
|
|
139
139
|
|
|
140
140
|
Examples:
|
|
141
141
|
npx openbroker@latest install --codex # Install skill + CLI + API-wallet setup
|
|
142
|
+
openbroker install monitoring # Install or upgrade the automation dashboard
|
|
143
|
+
openbroker install extended # Install or upgrade the Extended Exchange CLI
|
|
142
144
|
openbroker setup --api-wallet # Recommended restricted API-wallet setup
|
|
143
145
|
openbroker account # View account info
|
|
144
146
|
openbroker buy --coin ETH --size 0.1 # Market buy 0.1 ETH
|
package/dist/setup/install.js
CHANGED
|
@@ -5,19 +5,54 @@ import * as path from 'path';
|
|
|
5
5
|
import { homedir } from 'os';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { spawnSync } from 'child_process';
|
|
8
|
+
import { INSTALLABLE_PACKAGES, packageSpec, resolveInstallablePackage, } from './package-catalog.js';
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
10
11
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
11
|
-
const
|
|
12
|
+
const rawArgs = process.argv.slice(2);
|
|
13
|
+
const args = new Set(rawArgs);
|
|
14
|
+
function positionalArgs() {
|
|
15
|
+
const positionals = [];
|
|
16
|
+
for (let index = 0; index < rawArgs.length; index++) {
|
|
17
|
+
const arg = rawArgs[index];
|
|
18
|
+
if (arg === '--tag') {
|
|
19
|
+
index++;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!arg.startsWith('-'))
|
|
23
|
+
positionals.push(arg);
|
|
24
|
+
}
|
|
25
|
+
return positionals;
|
|
26
|
+
}
|
|
27
|
+
function optionValue(flag) {
|
|
28
|
+
const index = rawArgs.indexOf(flag);
|
|
29
|
+
if (index < 0)
|
|
30
|
+
return null;
|
|
31
|
+
const value = rawArgs[index + 1];
|
|
32
|
+
if (!value || value.startsWith('-'))
|
|
33
|
+
fail(`${flag} requires a value`);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
12
36
|
function printUsage() {
|
|
13
37
|
console.log(`
|
|
14
|
-
OpenBroker
|
|
15
|
-
|
|
38
|
+
OpenBroker Installer
|
|
39
|
+
====================
|
|
16
40
|
|
|
17
41
|
Usage:
|
|
42
|
+
openbroker install <package> [--tag <version>] [--dry]
|
|
43
|
+
openbroker install --list
|
|
18
44
|
openbroker install --codex [options]
|
|
19
45
|
npx openbroker@latest install --codex [options]
|
|
20
46
|
|
|
47
|
+
Companion packages:
|
|
48
|
+
monitoring Install the local automation dashboard
|
|
49
|
+
extended Install the Extended Exchange CLI
|
|
50
|
+
|
|
51
|
+
Package options:
|
|
52
|
+
--tag <tag> Install a release tag or exact version (default: latest)
|
|
53
|
+
--dry Print the npm command without installing
|
|
54
|
+
--list List supported companion packages
|
|
55
|
+
|
|
21
56
|
Harnesses:
|
|
22
57
|
--codex Install the OpenBroker skill for Codex
|
|
23
58
|
|
|
@@ -74,6 +109,55 @@ function installGlobalCli() {
|
|
|
74
109
|
fail('global CLI installation failed. Fix the npm permission error, then rerun with --skip-cli.');
|
|
75
110
|
}
|
|
76
111
|
}
|
|
112
|
+
function printInstallablePackages() {
|
|
113
|
+
console.log('Installable OpenBroker packages:\n');
|
|
114
|
+
for (const entry of INSTALLABLE_PACKAGES) {
|
|
115
|
+
console.log(` ${entry.key.padEnd(12)} ${entry.packageName.padEnd(26)} ${entry.description}`);
|
|
116
|
+
}
|
|
117
|
+
console.log('\nInstall or upgrade with: openbroker install <package>');
|
|
118
|
+
}
|
|
119
|
+
function installCompanionPackage(target) {
|
|
120
|
+
const entry = resolveInstallablePackage(target);
|
|
121
|
+
if (!entry) {
|
|
122
|
+
printInstallablePackages();
|
|
123
|
+
fail(`unknown installable package: ${target}`);
|
|
124
|
+
}
|
|
125
|
+
const allowedFlags = new Set(['--tag', '--dry']);
|
|
126
|
+
const unsupported = rawArgs.filter((arg, index) => (arg.startsWith('-')
|
|
127
|
+
&& !allowedFlags.has(arg)
|
|
128
|
+
&& rawArgs[index - 1] !== '--tag'));
|
|
129
|
+
if (unsupported.length > 0)
|
|
130
|
+
fail(`unsupported package option: ${unsupported[0]}`);
|
|
131
|
+
const tag = optionValue('--tag') ?? 'latest';
|
|
132
|
+
let spec;
|
|
133
|
+
try {
|
|
134
|
+
spec = packageSpec(entry, tag);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
138
|
+
}
|
|
139
|
+
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
140
|
+
const npmArgs = ['install', '--global', spec];
|
|
141
|
+
console.log(`OpenBroker — Install ${entry.key}`);
|
|
142
|
+
console.log('================================\n');
|
|
143
|
+
console.log(`Package: ${spec}`);
|
|
144
|
+
console.log(`Command: ${npmCommand} ${npmArgs.join(' ')}`);
|
|
145
|
+
if (args.has('--dry')) {
|
|
146
|
+
console.log('\nDry run only; nothing was installed.');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const result = spawnSync(npmCommand, npmArgs, { stdio: 'inherit' });
|
|
150
|
+
if (result.error)
|
|
151
|
+
fail(`could not start npm: ${result.error.message}`);
|
|
152
|
+
if (result.status !== 0) {
|
|
153
|
+
fail(`installation failed for ${entry.packageName}; resolve the npm error and retry`);
|
|
154
|
+
}
|
|
155
|
+
console.log(`\n✅ ${entry.packageName} installed successfully.`);
|
|
156
|
+
console.log(`Available command: ${entry.command}`);
|
|
157
|
+
console.log('\nNext steps:');
|
|
158
|
+
for (const step of entry.nextSteps)
|
|
159
|
+
console.log(` ${step}`);
|
|
160
|
+
}
|
|
77
161
|
function runApiWalletSetup() {
|
|
78
162
|
const onboardPath = path.join(packageRoot, 'scripts', 'setup', 'onboard.ts');
|
|
79
163
|
console.log('\nStarting restricted API-wallet onboarding...\n');
|
|
@@ -94,6 +178,19 @@ function main() {
|
|
|
94
178
|
printUsage();
|
|
95
179
|
return;
|
|
96
180
|
}
|
|
181
|
+
if (args.has('--list')) {
|
|
182
|
+
printInstallablePackages();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const positionals = positionalArgs();
|
|
186
|
+
if (positionals.length > 0) {
|
|
187
|
+
if (positionals.length > 1)
|
|
188
|
+
fail(`expected one package name, received: ${positionals.join(' ')}`);
|
|
189
|
+
if (args.has('--codex'))
|
|
190
|
+
fail('choose either a companion package or the --codex harness installer');
|
|
191
|
+
installCompanionPackage(positionals[0]);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
97
194
|
if (!args.has('--codex')) {
|
|
98
195
|
printUsage();
|
|
99
196
|
fail('choose a supported harness flag such as --codex');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface InstallablePackage {
|
|
2
|
+
key: string;
|
|
3
|
+
aliases: string[];
|
|
4
|
+
packageName: string;
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
nextSteps: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare const INSTALLABLE_PACKAGES: InstallablePackage[];
|
|
10
|
+
export declare function resolveInstallablePackage(input: string): InstallablePackage | null;
|
|
11
|
+
export declare function packageSpec(entry: InstallablePackage, tag?: string): string;
|
|
12
|
+
//# sourceMappingURL=package-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-catalog.d.ts","sourceRoot":"","sources":["../../scripts/setup/package-catalog.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,oBAAoB,EAAE,kBAAkB,EAuBpD,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOlF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,SAAW,GAAG,MAAM,CAK7E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const INSTALLABLE_PACKAGES = [
|
|
2
|
+
{
|
|
3
|
+
key: 'monitoring',
|
|
4
|
+
aliases: ['openbroker-monitoring'],
|
|
5
|
+
packageName: 'openbroker-monitoring',
|
|
6
|
+
command: 'openbroker-monitoring',
|
|
7
|
+
description: 'Local automation dashboard and optional audit observer',
|
|
8
|
+
nextSteps: [
|
|
9
|
+
'openbroker-monitoring serve --host 127.0.0.1 --port 3001',
|
|
10
|
+
'Open http://127.0.0.1:3001',
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: 'extended',
|
|
15
|
+
aliases: ['openbroker-extended'],
|
|
16
|
+
packageName: 'openbroker-extended',
|
|
17
|
+
command: 'openbroker-ex',
|
|
18
|
+
description: 'Extended Exchange trading CLI and library',
|
|
19
|
+
nextSteps: [
|
|
20
|
+
'openbroker-ex --help',
|
|
21
|
+
'openbroker-ex setup',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
export function resolveInstallablePackage(input) {
|
|
26
|
+
const normalized = input.trim().toLowerCase();
|
|
27
|
+
return INSTALLABLE_PACKAGES.find((entry) => (entry.key === normalized
|
|
28
|
+
|| entry.packageName === normalized
|
|
29
|
+
|| entry.aliases.includes(normalized))) ?? null;
|
|
30
|
+
}
|
|
31
|
+
export function packageSpec(entry, tag = 'latest') {
|
|
32
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(tag)) {
|
|
33
|
+
throw new Error(`invalid package tag or version: ${tag}`);
|
|
34
|
+
}
|
|
35
|
+
return `${entry.packageName}@${tag}`;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-catalog.test.d.ts","sourceRoot":"","sources":["../../scripts/setup/package-catalog.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { INSTALLABLE_PACKAGES, packageSpec, resolveInstallablePackage, } from './package-catalog.js';
|
|
6
|
+
const installScript = fileURLToPath(new URL('./install.ts', import.meta.url));
|
|
7
|
+
test('resolves companion packages by short name and npm package name', () => {
|
|
8
|
+
assert.equal(resolveInstallablePackage('monitoring')?.packageName, 'openbroker-monitoring');
|
|
9
|
+
assert.equal(resolveInstallablePackage('openbroker-monitoring')?.key, 'monitoring');
|
|
10
|
+
assert.equal(resolveInstallablePackage('EXTENDED')?.command, 'openbroker-ex');
|
|
11
|
+
assert.equal(resolveInstallablePackage('unknown'), null);
|
|
12
|
+
});
|
|
13
|
+
test('builds pinned or latest npm package specs without accepting arbitrary specs', () => {
|
|
14
|
+
const monitoring = INSTALLABLE_PACKAGES.find((entry) => entry.key === 'monitoring');
|
|
15
|
+
assert.ok(monitoring);
|
|
16
|
+
assert.equal(packageSpec(monitoring), 'openbroker-monitoring@latest');
|
|
17
|
+
assert.equal(packageSpec(monitoring, '1.4.2'), 'openbroker-monitoring@1.4.2');
|
|
18
|
+
assert.throws(() => packageSpec(monitoring, 'npm:unrelated-package'));
|
|
19
|
+
assert.throws(() => packageSpec(monitoring, '../local-package'));
|
|
20
|
+
});
|
|
21
|
+
test('installer dry run prints the global npm operation without writing', () => {
|
|
22
|
+
const result = spawnSync(process.execPath, ['--import', 'tsx', installScript, 'monitoring', '--tag', '1.4.2', '--dry'], { encoding: 'utf8' });
|
|
23
|
+
assert.equal(result.status, 0, result.stderr);
|
|
24
|
+
assert.match(result.stdout, /npm install --global openbroker-monitoring@1\.4\.2/);
|
|
25
|
+
assert.match(result.stdout, /nothing was installed/i);
|
|
26
|
+
});
|
|
27
|
+
test('installer rejects packages outside the catalog', () => {
|
|
28
|
+
const result = spawnSync(process.execPath, ['--import', 'tsx', installScript, 'unrelated-package', '--dry'], { encoding: 'utf8' });
|
|
29
|
+
assert.equal(result.status, 1);
|
|
30
|
+
assert.match(result.stderr, /unknown installable package/i);
|
|
31
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbroker",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.5",
|
|
4
4
|
"description": "Hyperliquid trading CLI - execute orders, manage positions, and run trading strategies",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -51,10 +51,11 @@
|
|
|
51
51
|
"funding-scan": "tsx scripts/info/funding-scan.ts",
|
|
52
52
|
"outcomes": "tsx scripts/info/outcomes.ts",
|
|
53
53
|
"build": "tsc",
|
|
54
|
-
"prepublishOnly": "npm run build && npm run test:guardrails && npm run test:realtime && npm run test:cli",
|
|
54
|
+
"prepublishOnly": "npm run build && npm run test:guardrails && npm run test:realtime && npm run test:install && npm run test:cli",
|
|
55
55
|
"test:cli": "node --import tsx bin/cli.ts --help",
|
|
56
56
|
"test:guardrails": "node --import tsx --test scripts/auto/guardrails.test.ts",
|
|
57
|
-
"test:realtime": "node --import tsx --test scripts/auto/realtime.test.ts"
|
|
57
|
+
"test:realtime": "node --import tsx --test scripts/auto/realtime.test.ts",
|
|
58
|
+
"test:install": "node --import tsx --test scripts/setup/package-catalog.test.ts"
|
|
58
59
|
},
|
|
59
60
|
"dependencies": {
|
|
60
61
|
"@nktkas/hyperliquid": "^0.30.3",
|
package/scripts/setup/install.ts
CHANGED
|
@@ -6,21 +6,59 @@ import * as path from 'path';
|
|
|
6
6
|
import { homedir } from 'os';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { spawnSync } from 'child_process';
|
|
9
|
+
import {
|
|
10
|
+
INSTALLABLE_PACKAGES,
|
|
11
|
+
packageSpec,
|
|
12
|
+
resolveInstallablePackage,
|
|
13
|
+
} from './package-catalog.js';
|
|
9
14
|
|
|
10
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
16
|
const __dirname = path.dirname(__filename);
|
|
12
17
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
13
|
-
const
|
|
18
|
+
const rawArgs = process.argv.slice(2);
|
|
19
|
+
const args = new Set(rawArgs);
|
|
20
|
+
|
|
21
|
+
function positionalArgs(): string[] {
|
|
22
|
+
const positionals: string[] = [];
|
|
23
|
+
for (let index = 0; index < rawArgs.length; index++) {
|
|
24
|
+
const arg = rawArgs[index];
|
|
25
|
+
if (arg === '--tag') {
|
|
26
|
+
index++;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (!arg.startsWith('-')) positionals.push(arg);
|
|
30
|
+
}
|
|
31
|
+
return positionals;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function optionValue(flag: string): string | null {
|
|
35
|
+
const index = rawArgs.indexOf(flag);
|
|
36
|
+
if (index < 0) return null;
|
|
37
|
+
const value = rawArgs[index + 1];
|
|
38
|
+
if (!value || value.startsWith('-')) fail(`${flag} requires a value`);
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
14
41
|
|
|
15
42
|
function printUsage(): void {
|
|
16
43
|
console.log(`
|
|
17
|
-
OpenBroker
|
|
18
|
-
|
|
44
|
+
OpenBroker Installer
|
|
45
|
+
====================
|
|
19
46
|
|
|
20
47
|
Usage:
|
|
48
|
+
openbroker install <package> [--tag <version>] [--dry]
|
|
49
|
+
openbroker install --list
|
|
21
50
|
openbroker install --codex [options]
|
|
22
51
|
npx openbroker@latest install --codex [options]
|
|
23
52
|
|
|
53
|
+
Companion packages:
|
|
54
|
+
monitoring Install the local automation dashboard
|
|
55
|
+
extended Install the Extended Exchange CLI
|
|
56
|
+
|
|
57
|
+
Package options:
|
|
58
|
+
--tag <tag> Install a release tag or exact version (default: latest)
|
|
59
|
+
--dry Print the npm command without installing
|
|
60
|
+
--list List supported companion packages
|
|
61
|
+
|
|
24
62
|
Harnesses:
|
|
25
63
|
--codex Install the OpenBroker skill for Codex
|
|
26
64
|
|
|
@@ -93,6 +131,62 @@ function installGlobalCli(): void {
|
|
|
93
131
|
}
|
|
94
132
|
}
|
|
95
133
|
|
|
134
|
+
function printInstallablePackages(): void {
|
|
135
|
+
console.log('Installable OpenBroker packages:\n');
|
|
136
|
+
for (const entry of INSTALLABLE_PACKAGES) {
|
|
137
|
+
console.log(` ${entry.key.padEnd(12)} ${entry.packageName.padEnd(26)} ${entry.description}`);
|
|
138
|
+
}
|
|
139
|
+
console.log('\nInstall or upgrade with: openbroker install <package>');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function installCompanionPackage(target: string): void {
|
|
143
|
+
const entry = resolveInstallablePackage(target);
|
|
144
|
+
if (!entry) {
|
|
145
|
+
printInstallablePackages();
|
|
146
|
+
fail(`unknown installable package: ${target}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const allowedFlags = new Set(['--tag', '--dry']);
|
|
150
|
+
const unsupported = rawArgs.filter((arg, index) => (
|
|
151
|
+
arg.startsWith('-')
|
|
152
|
+
&& !allowedFlags.has(arg)
|
|
153
|
+
&& rawArgs[index - 1] !== '--tag'
|
|
154
|
+
));
|
|
155
|
+
if (unsupported.length > 0) fail(`unsupported package option: ${unsupported[0]}`);
|
|
156
|
+
|
|
157
|
+
const tag = optionValue('--tag') ?? 'latest';
|
|
158
|
+
let spec: string;
|
|
159
|
+
try {
|
|
160
|
+
spec = packageSpec(entry, tag);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
166
|
+
const npmArgs = ['install', '--global', spec];
|
|
167
|
+
|
|
168
|
+
console.log(`OpenBroker — Install ${entry.key}`);
|
|
169
|
+
console.log('================================\n');
|
|
170
|
+
console.log(`Package: ${spec}`);
|
|
171
|
+
console.log(`Command: ${npmCommand} ${npmArgs.join(' ')}`);
|
|
172
|
+
|
|
173
|
+
if (args.has('--dry')) {
|
|
174
|
+
console.log('\nDry run only; nothing was installed.');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const result = spawnSync(npmCommand, npmArgs, { stdio: 'inherit' });
|
|
179
|
+
if (result.error) fail(`could not start npm: ${result.error.message}`);
|
|
180
|
+
if (result.status !== 0) {
|
|
181
|
+
fail(`installation failed for ${entry.packageName}; resolve the npm error and retry`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(`\n✅ ${entry.packageName} installed successfully.`);
|
|
185
|
+
console.log(`Available command: ${entry.command}`);
|
|
186
|
+
console.log('\nNext steps:');
|
|
187
|
+
for (const step of entry.nextSteps) console.log(` ${step}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
96
190
|
function runApiWalletSetup(): void {
|
|
97
191
|
const onboardPath = path.join(packageRoot, 'scripts', 'setup', 'onboard.ts');
|
|
98
192
|
|
|
@@ -121,6 +215,19 @@ function main(): void {
|
|
|
121
215
|
return;
|
|
122
216
|
}
|
|
123
217
|
|
|
218
|
+
if (args.has('--list')) {
|
|
219
|
+
printInstallablePackages();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const positionals = positionalArgs();
|
|
224
|
+
if (positionals.length > 0) {
|
|
225
|
+
if (positionals.length > 1) fail(`expected one package name, received: ${positionals.join(' ')}`);
|
|
226
|
+
if (args.has('--codex')) fail('choose either a companion package or the --codex harness installer');
|
|
227
|
+
installCompanionPackage(positionals[0]);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
124
231
|
if (!args.has('--codex')) {
|
|
125
232
|
printUsage();
|
|
126
233
|
fail('choose a supported harness flag such as --codex');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import {
|
|
6
|
+
INSTALLABLE_PACKAGES,
|
|
7
|
+
packageSpec,
|
|
8
|
+
resolveInstallablePackage,
|
|
9
|
+
} from './package-catalog.js';
|
|
10
|
+
|
|
11
|
+
const installScript = fileURLToPath(new URL('./install.ts', import.meta.url));
|
|
12
|
+
|
|
13
|
+
test('resolves companion packages by short name and npm package name', () => {
|
|
14
|
+
assert.equal(resolveInstallablePackage('monitoring')?.packageName, 'openbroker-monitoring');
|
|
15
|
+
assert.equal(resolveInstallablePackage('openbroker-monitoring')?.key, 'monitoring');
|
|
16
|
+
assert.equal(resolveInstallablePackage('EXTENDED')?.command, 'openbroker-ex');
|
|
17
|
+
assert.equal(resolveInstallablePackage('unknown'), null);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('builds pinned or latest npm package specs without accepting arbitrary specs', () => {
|
|
21
|
+
const monitoring = INSTALLABLE_PACKAGES.find((entry) => entry.key === 'monitoring');
|
|
22
|
+
assert.ok(monitoring);
|
|
23
|
+
assert.equal(packageSpec(monitoring), 'openbroker-monitoring@latest');
|
|
24
|
+
assert.equal(packageSpec(monitoring, '1.4.2'), 'openbroker-monitoring@1.4.2');
|
|
25
|
+
assert.throws(() => packageSpec(monitoring, 'npm:unrelated-package'));
|
|
26
|
+
assert.throws(() => packageSpec(monitoring, '../local-package'));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('installer dry run prints the global npm operation without writing', () => {
|
|
30
|
+
const result = spawnSync(
|
|
31
|
+
process.execPath,
|
|
32
|
+
['--import', 'tsx', installScript, 'monitoring', '--tag', '1.4.2', '--dry'],
|
|
33
|
+
{ encoding: 'utf8' },
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
assert.equal(result.status, 0, result.stderr);
|
|
37
|
+
assert.match(result.stdout, /npm install --global openbroker-monitoring@1\.4\.2/);
|
|
38
|
+
assert.match(result.stdout, /nothing was installed/i);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('installer rejects packages outside the catalog', () => {
|
|
42
|
+
const result = spawnSync(
|
|
43
|
+
process.execPath,
|
|
44
|
+
['--import', 'tsx', installScript, 'unrelated-package', '--dry'],
|
|
45
|
+
{ encoding: 'utf8' },
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
assert.equal(result.status, 1);
|
|
49
|
+
assert.match(result.stderr, /unknown installable package/i);
|
|
50
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface InstallablePackage {
|
|
2
|
+
key: string;
|
|
3
|
+
aliases: string[];
|
|
4
|
+
packageName: string;
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
nextSteps: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const INSTALLABLE_PACKAGES: InstallablePackage[] = [
|
|
11
|
+
{
|
|
12
|
+
key: 'monitoring',
|
|
13
|
+
aliases: ['openbroker-monitoring'],
|
|
14
|
+
packageName: 'openbroker-monitoring',
|
|
15
|
+
command: 'openbroker-monitoring',
|
|
16
|
+
description: 'Local automation dashboard and optional audit observer',
|
|
17
|
+
nextSteps: [
|
|
18
|
+
'openbroker-monitoring serve --host 127.0.0.1 --port 3001',
|
|
19
|
+
'Open http://127.0.0.1:3001',
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
key: 'extended',
|
|
24
|
+
aliases: ['openbroker-extended'],
|
|
25
|
+
packageName: 'openbroker-extended',
|
|
26
|
+
command: 'openbroker-ex',
|
|
27
|
+
description: 'Extended Exchange trading CLI and library',
|
|
28
|
+
nextSteps: [
|
|
29
|
+
'openbroker-ex --help',
|
|
30
|
+
'openbroker-ex setup',
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export function resolveInstallablePackage(input: string): InstallablePackage | null {
|
|
36
|
+
const normalized = input.trim().toLowerCase();
|
|
37
|
+
return INSTALLABLE_PACKAGES.find((entry) => (
|
|
38
|
+
entry.key === normalized
|
|
39
|
+
|| entry.packageName === normalized
|
|
40
|
+
|| entry.aliases.includes(normalized)
|
|
41
|
+
)) ?? null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function packageSpec(entry: InstallablePackage, tag = 'latest'): string {
|
|
45
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(tag)) {
|
|
46
|
+
throw new Error(`invalid package tag or version: ${tag}`);
|
|
47
|
+
}
|
|
48
|
+
return `${entry.packageName}@${tag}`;
|
|
49
|
+
}
|