openbroker 1.9.1 → 1.9.3
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 +10 -0
- package/README.md +11 -0
- package/SKILL.md +58 -1
- package/bin/cli.ts +3 -0
- package/dist/auto/cli.js +3 -0
- package/dist/auto/examples/dca.d.ts +2 -1
- package/dist/auto/examples/dca.d.ts.map +1 -1
- package/dist/auto/examples/dca.js +19 -1
- package/dist/auto/examples/funding-arb.d.ts +2 -1
- package/dist/auto/examples/funding-arb.d.ts.map +1 -1
- package/dist/auto/examples/funding-arb.js +19 -2
- package/dist/auto/examples/grid.d.ts +2 -1
- package/dist/auto/examples/grid.d.ts.map +1 -1
- package/dist/auto/examples/grid.js +18 -2
- package/dist/auto/examples/mm-maker.d.ts +2 -1
- package/dist/auto/examples/mm-maker.d.ts.map +1 -1
- package/dist/auto/examples/mm-maker.js +18 -2
- package/dist/auto/examples/mm-spread.d.ts +2 -1
- package/dist/auto/examples/mm-spread.d.ts.map +1 -1
- package/dist/auto/examples/mm-spread.js +18 -2
- package/dist/auto/examples/price-alert.d.ts +2 -1
- package/dist/auto/examples/price-alert.d.ts.map +1 -1
- package/dist/auto/examples/price-alert.js +1 -0
- package/dist/auto/guardrails.d.ts +19 -0
- package/dist/auto/guardrails.d.ts.map +1 -0
- package/dist/auto/guardrails.js +575 -0
- package/dist/auto/guardrails.test.d.ts +2 -0
- package/dist/auto/guardrails.test.d.ts.map +1 -0
- package/dist/auto/guardrails.test.js +173 -0
- package/dist/auto/loader.d.ts +3 -3
- package/dist/auto/loader.d.ts.map +1 -1
- package/dist/auto/loader.js +25 -3
- package/dist/auto/runtime.d.ts.map +1 -1
- package/dist/auto/runtime.js +38 -20
- package/dist/auto/types.d.ts +43 -0
- package/dist/auto/types.d.ts.map +1 -1
- package/dist/lib.d.ts +2 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/setup/install.d.ts +3 -0
- package/dist/setup/install.d.ts.map +1 -0
- package/dist/setup/install.js +113 -0
- package/package.json +4 -3
- package/scripts/auto/cli.ts +3 -0
- package/scripts/auto/examples/dca.ts +21 -2
- package/scripts/auto/examples/funding-arb.ts +21 -3
- package/scripts/auto/examples/grid.ts +20 -3
- package/scripts/auto/examples/mm-maker.ts +20 -3
- package/scripts/auto/examples/mm-spread.ts +20 -3
- package/scripts/auto/examples/price-alert.ts +3 -1
- package/scripts/auto/guardrails.test.ts +227 -0
- package/scripts/auto/guardrails.ts +700 -0
- package/scripts/auto/loader.ts +41 -4
- package/scripts/auto/runtime.ts +38 -22
- package/scripts/auto/types.ts +54 -0
- package/scripts/lib.ts +10 -0
- package/scripts/setup/install.ts +146 -0
package/scripts/auto/loader.ts
CHANGED
|
@@ -4,7 +4,14 @@ import { existsSync, readdirSync, mkdirSync } from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
|
-
import
|
|
7
|
+
import { resolveAutomationGuardrails } from './guardrails.js';
|
|
8
|
+
import type {
|
|
9
|
+
AutomationFactory,
|
|
10
|
+
AutomationConfig,
|
|
11
|
+
AutomationGuardrailContext,
|
|
12
|
+
AutomationGuardrailsExport,
|
|
13
|
+
LoadedAutomation,
|
|
14
|
+
} from './types.js';
|
|
8
15
|
|
|
9
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
17
|
const __dirname = path.dirname(__filename);
|
|
@@ -117,8 +124,27 @@ function resolveAutomationConfig(mod: Record<string, unknown>): AutomationConfig
|
|
|
117
124
|
return null;
|
|
118
125
|
}
|
|
119
126
|
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
function resolveGuardrailsExport(mod: Record<string, unknown>): AutomationGuardrailsExport | null {
|
|
128
|
+
const candidates = [
|
|
129
|
+
mod.guardrails,
|
|
130
|
+
(mod.default as Record<string, unknown> | undefined)?.guardrails,
|
|
131
|
+
(mod["module.exports"] as Record<string, unknown> | undefined)?.guardrails,
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
for (const candidate of candidates) {
|
|
135
|
+
if (candidate && (typeof candidate === 'object' || typeof candidate === 'function')) {
|
|
136
|
+
return candidate as AutomationGuardrailsExport;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Load an automation module and validate its factory plus required guardrails export. */
|
|
144
|
+
export async function loadAutomation(
|
|
145
|
+
scriptPath: string,
|
|
146
|
+
context: AutomationGuardrailContext = { config: {} },
|
|
147
|
+
): Promise<LoadedAutomation> {
|
|
122
148
|
const absolutePath = path.resolve(scriptPath);
|
|
123
149
|
|
|
124
150
|
// Dynamic import — tsx handles TypeScript transpilation
|
|
@@ -132,7 +158,18 @@ export async function loadAutomation(scriptPath: string): Promise<AutomationFact
|
|
|
132
158
|
);
|
|
133
159
|
}
|
|
134
160
|
|
|
135
|
-
|
|
161
|
+
const guardrailsExport = resolveGuardrailsExport(mod as Record<string, unknown>);
|
|
162
|
+
if (!guardrailsExport) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Automation script must export "guardrails".\n` +
|
|
165
|
+
`Use { mode: "read-only" } for monitoring-only scripts or a validated trading policy.`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
factory: factory as AutomationFactory,
|
|
171
|
+
guardrails: resolveAutomationGuardrails(guardrailsExport, context),
|
|
172
|
+
};
|
|
136
173
|
}
|
|
137
174
|
|
|
138
175
|
/** List available automation scripts in ~/.openbroker/automations/ */
|
package/scripts/auto/runtime.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { WebSocketManager } from '../core/ws.js';
|
|
14
14
|
import { AutomationEventBus } from './events.js';
|
|
15
15
|
import { loadAutomation } from './loader.js';
|
|
16
|
+
import { CLIENT_WRITE_METHODS, createGuardrailedClient } from './guardrails.js';
|
|
16
17
|
import { registerAutomation, unregisterAutomation, getRegisteredAutomations as getRegisteredFromFile } from './registry.js';
|
|
17
18
|
import { createAutomationAudit, toSerializable, type AutomationAuditSink } from './audit.js';
|
|
18
19
|
import { startKeepAwake, type KeepAwakeHandle } from './keep-awake.js';
|
|
@@ -29,6 +30,7 @@ import type {
|
|
|
29
30
|
PublishOptions,
|
|
30
31
|
ScheduledTask,
|
|
31
32
|
RunningAutomation,
|
|
33
|
+
LoadedAutomation,
|
|
32
34
|
} from './types.js';
|
|
33
35
|
|
|
34
36
|
// ── Observer fan-out ────────────────────────────────────────────────
|
|
@@ -105,13 +107,6 @@ function fanOutAgentAction(
|
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
const STATE_DIR = path.join(os.homedir(), '.openbroker', 'state');
|
|
108
|
-
const AUDITED_WRITE_METHODS = new Set([
|
|
109
|
-
'order', 'marketOrder', 'limitOrder', 'triggerOrder',
|
|
110
|
-
'takeProfit', 'stopLoss', 'cancel', 'cancelAll',
|
|
111
|
-
'spotOrder', 'spotMarketOrder', 'spotLimitOrder', 'spotCancel',
|
|
112
|
-
'updateLeverage', 'approveBuilderFee', 'twapOrder', 'twapCancel',
|
|
113
|
-
]);
|
|
114
|
-
|
|
115
110
|
// ── State persistence ───────────────────────────────────────────────
|
|
116
111
|
|
|
117
112
|
interface StateController {
|
|
@@ -202,19 +197,11 @@ function createLogger(id: string, verbose: boolean, audit?: AutomationAuditSink)
|
|
|
202
197
|
|
|
203
198
|
// ── Dry-run client proxy ────────────────────────────────────────────
|
|
204
199
|
|
|
205
|
-
const WRITE_METHODS = new Set([
|
|
206
|
-
'order', 'marketOrder', 'limitOrder', 'triggerOrder',
|
|
207
|
-
'takeProfit', 'stopLoss', 'cancel', 'cancelAll',
|
|
208
|
-
'updateLeverage', 'approveBuilderFee',
|
|
209
|
-
'spotOrder', 'spotMarketOrder', 'spotLimitOrder', 'spotCancel',
|
|
210
|
-
'twapOrder', 'twapCancel',
|
|
211
|
-
]);
|
|
212
|
-
|
|
213
200
|
function createDryClient(client: HyperliquidClient, log: AutomationLogger): HyperliquidClient {
|
|
214
201
|
return new Proxy(client, {
|
|
215
202
|
get(target, prop, receiver) {
|
|
216
203
|
const value = Reflect.get(target, prop, receiver);
|
|
217
|
-
if (typeof prop === 'string' &&
|
|
204
|
+
if (typeof prop === 'string' && CLIENT_WRITE_METHODS.has(prop) && typeof value === 'function') {
|
|
218
205
|
return (...args: unknown[]) => {
|
|
219
206
|
log.info(`[DRY] ${prop}(${args.map(a => JSON.stringify(a)).join(', ')})`);
|
|
220
207
|
return Promise.resolve({ status: 'ok', response: { type: 'dry_run' } });
|
|
@@ -234,7 +221,7 @@ function createAuditedClient(
|
|
|
234
221
|
return new Proxy(client, {
|
|
235
222
|
get(target, prop, receiver) {
|
|
236
223
|
const value = Reflect.get(target, prop, receiver);
|
|
237
|
-
if (typeof prop === 'string' &&
|
|
224
|
+
if (typeof prop === 'string' && CLIENT_WRITE_METHODS.has(prop) && typeof value === 'function') {
|
|
238
225
|
return async (...args: unknown[]) => {
|
|
239
226
|
const actionId = `${prop}:${Date.now()}:${Math.random().toString(16).slice(2)}`;
|
|
240
227
|
audit.recordAction({
|
|
@@ -531,8 +518,38 @@ export async function startAutomation(options: RuntimeOptions): Promise<RunningA
|
|
|
531
518
|
}
|
|
532
519
|
}
|
|
533
520
|
const observers = await loadConventionObservers(log);
|
|
521
|
+
let loaded: LoadedAutomation;
|
|
522
|
+
try {
|
|
523
|
+
log.info(`Loading automation: ${scriptPath}`);
|
|
524
|
+
loaded = await loadAutomation(scriptPath, { config: stateController.snapshot() });
|
|
525
|
+
} catch (err) {
|
|
526
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
527
|
+
audit.recordError('guardrail_validation', error);
|
|
528
|
+
await audit.stop({
|
|
529
|
+
status: 'error',
|
|
530
|
+
stopReason: 'guardrail_validation_error',
|
|
531
|
+
pollCount: 0,
|
|
532
|
+
eventsEmitted: 0,
|
|
533
|
+
});
|
|
534
|
+
keepAwake?.stop();
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
audit.recordNote('guardrails', loaded.guardrails);
|
|
534
538
|
const baseClient = dryRun ? createDryClient(rawClient, log) : rawClient;
|
|
535
|
-
const
|
|
539
|
+
const guardedClient = createGuardrailedClient(baseClient, {
|
|
540
|
+
policy: loaded.guardrails,
|
|
541
|
+
rawClient,
|
|
542
|
+
log,
|
|
543
|
+
onViolation: (error, method, args) => {
|
|
544
|
+
audit.recordNote('guardrail_block', {
|
|
545
|
+
code: error.code,
|
|
546
|
+
message: error.message,
|
|
547
|
+
method,
|
|
548
|
+
args: toSerializable(args),
|
|
549
|
+
});
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
const client = createAuditedClient(guardedClient, audit, dryRun, observers);
|
|
536
553
|
|
|
537
554
|
const startHooks: Array<() => void | Promise<void>> = [];
|
|
538
555
|
const stopHooks: Array<() => void | Promise<void>> = [];
|
|
@@ -565,13 +582,12 @@ export async function startAutomation(options: RuntimeOptions): Promise<RunningA
|
|
|
565
582
|
audit: auditApi,
|
|
566
583
|
id,
|
|
567
584
|
dryRun,
|
|
585
|
+
guardrails: loaded.guardrails,
|
|
568
586
|
};
|
|
569
587
|
|
|
570
588
|
try {
|
|
571
|
-
//
|
|
572
|
-
|
|
573
|
-
const factory = await loadAutomation(scriptPath);
|
|
574
|
-
await factory(api);
|
|
589
|
+
// Execute the already validated factory function (registers handlers).
|
|
590
|
+
await loaded.factory(api);
|
|
575
591
|
|
|
576
592
|
// Call onStart hooks
|
|
577
593
|
for (const hook of startHooks) {
|
package/scripts/auto/types.ts
CHANGED
|
@@ -8,6 +8,57 @@ import type { HyperliquidClient } from '../core/client.js';
|
|
|
8
8
|
/** What an automation .ts file exports */
|
|
9
9
|
export type AutomationFactory = (api: AutomationAPI) => void | Promise<void>;
|
|
10
10
|
|
|
11
|
+
/** Runtime-enforced policy exported by every automation module. */
|
|
12
|
+
export type AutomationGuardrails =
|
|
13
|
+
| ReadOnlyAutomationGuardrails
|
|
14
|
+
| TradingAutomationGuardrails;
|
|
15
|
+
|
|
16
|
+
export interface ReadOnlyAutomationGuardrails {
|
|
17
|
+
/** Read-only automations cannot call any client write method. */
|
|
18
|
+
mode: 'read-only';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TradingAutomationGuardrails {
|
|
22
|
+
mode: 'trading';
|
|
23
|
+
/** Canonical markets this automation may trade: `ETH`, `xyz:CL`, `spot:HYPE`, `#1230`. */
|
|
24
|
+
allowedMarkets: string[];
|
|
25
|
+
/** Maximum USD notional for one submitted order. */
|
|
26
|
+
maxOrderUsd: number;
|
|
27
|
+
/** Maximum absolute USD exposure in any one market after an order. */
|
|
28
|
+
maxPositionUsd: number;
|
|
29
|
+
/** Maximum absolute USD exposure across the account after an order. */
|
|
30
|
+
maxTotalExposureUsd: number;
|
|
31
|
+
/** Maximum leverage the automation may request or use when increasing perp exposure. */
|
|
32
|
+
maxLeverage: number;
|
|
33
|
+
/** Maximum account margin utilization allowed after a risk-increasing perp order. */
|
|
34
|
+
maxMarginUsedPct: number;
|
|
35
|
+
/** Maximum account-wide open orders after this automation submits an order. */
|
|
36
|
+
maxOpenOrders: number;
|
|
37
|
+
/** Maximum risk-increasing order submissions in a rolling 60-second window. */
|
|
38
|
+
maxOrdersPerMinute: number;
|
|
39
|
+
/** Maximum slippage passed to market-order helpers. */
|
|
40
|
+
maxSlippageBps: number;
|
|
41
|
+
/** Whether market-order helpers may be used. */
|
|
42
|
+
allowMarketOrders: boolean;
|
|
43
|
+
/** Whether `cancelAll()` without a market or an armed `scheduleCancel()` is allowed. */
|
|
44
|
+
allowAccountWideCancel: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface AutomationGuardrailContext {
|
|
48
|
+
/** Persisted automation state with current `--set` overrides applied. */
|
|
49
|
+
config: Readonly<Record<string, unknown>>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Guardrails may be static or derived from startup config, but the result is always validated. */
|
|
53
|
+
export type AutomationGuardrailsExport =
|
|
54
|
+
| AutomationGuardrails
|
|
55
|
+
| ((context: AutomationGuardrailContext) => AutomationGuardrails);
|
|
56
|
+
|
|
57
|
+
export interface LoadedAutomation {
|
|
58
|
+
factory: AutomationFactory;
|
|
59
|
+
guardrails: AutomationGuardrails;
|
|
60
|
+
}
|
|
61
|
+
|
|
11
62
|
/** Config field descriptor for example automations */
|
|
12
63
|
export interface AutomationConfigField {
|
|
13
64
|
type: 'string' | 'number' | 'boolean';
|
|
@@ -206,6 +257,9 @@ export interface AutomationAPI {
|
|
|
206
257
|
|
|
207
258
|
/** True if running in --dry mode (write methods are intercepted) */
|
|
208
259
|
dryRun: boolean;
|
|
260
|
+
|
|
261
|
+
/** Validated policy currently enforced by the runtime client proxy. */
|
|
262
|
+
guardrails: Readonly<AutomationGuardrails>;
|
|
209
263
|
}
|
|
210
264
|
|
|
211
265
|
// ── Runtime internals ───────────────────────────────────────────────
|
package/scripts/lib.ts
CHANGED
|
@@ -79,6 +79,16 @@ export {
|
|
|
79
79
|
loadAutomation,
|
|
80
80
|
} from './auto/loader.js';
|
|
81
81
|
|
|
82
|
+
export {
|
|
83
|
+
GuardrailViolation,
|
|
84
|
+
CLIENT_WRITE_METHODS,
|
|
85
|
+
canonicalMarket,
|
|
86
|
+
validateAutomationGuardrails,
|
|
87
|
+
resolveAutomationGuardrails,
|
|
88
|
+
createGuardrailedClient,
|
|
89
|
+
} from './auto/guardrails.js';
|
|
90
|
+
export type { GuardrailedClientOptions } from './auto/guardrails.js';
|
|
91
|
+
|
|
82
92
|
export {
|
|
83
93
|
registerAutomation,
|
|
84
94
|
unregisterAutomation,
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
// Harness-aware OpenBroker installer.
|
|
3
|
+
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { homedir } from 'os';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { spawnSync } from 'child_process';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const packageRoot = path.resolve(__dirname, '../..');
|
|
13
|
+
const args = new Set(process.argv.slice(2));
|
|
14
|
+
|
|
15
|
+
function printUsage(): void {
|
|
16
|
+
console.log(`
|
|
17
|
+
OpenBroker Harness Installer
|
|
18
|
+
============================
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
openbroker install --codex [options]
|
|
22
|
+
npx openbroker@latest install --codex [options]
|
|
23
|
+
|
|
24
|
+
Harnesses:
|
|
25
|
+
--codex Install the OpenBroker skill for Codex
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
--skip-cli Do not install the persistent global CLI
|
|
29
|
+
--skip-setup Install files without starting API-wallet onboarding
|
|
30
|
+
--help Show this help
|
|
31
|
+
|
|
32
|
+
The default Codex flow installs the global CLI, writes the skill under
|
|
33
|
+
$CODEX_HOME/skills/openbroker (default: ~/.codex/skills/openbroker), and starts
|
|
34
|
+
restricted API-wallet onboarding.
|
|
35
|
+
`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function fail(message: string): never {
|
|
39
|
+
console.error(`Error: ${message}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertOpenBrokerSkill(skillPath: string): void {
|
|
44
|
+
if (!fs.existsSync(skillPath)) return;
|
|
45
|
+
|
|
46
|
+
const existing = fs.readFileSync(skillPath, 'utf8');
|
|
47
|
+
if (!/^name:\s*openbroker\s*$/m.test(existing)) {
|
|
48
|
+
fail(`refusing to overwrite unrelated skill at ${skillPath}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function copyManagedFile(source: string, destination: string): void {
|
|
53
|
+
if (!fs.existsSync(source)) {
|
|
54
|
+
fail(`packaged installer asset is missing: ${source}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true, mode: 0o755 });
|
|
58
|
+
fs.copyFileSync(source, destination);
|
|
59
|
+
fs.chmodSync(destination, 0o644);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function installCodexSkill(): string {
|
|
63
|
+
const codexHome = process.env.CODEX_HOME || path.join(homedir(), '.codex');
|
|
64
|
+
const destination = path.join(codexHome, 'skills', 'openbroker');
|
|
65
|
+
const skillPath = path.join(destination, 'SKILL.md');
|
|
66
|
+
|
|
67
|
+
assertOpenBrokerSkill(skillPath);
|
|
68
|
+
copyManagedFile(path.join(packageRoot, 'SKILL.md'), skillPath);
|
|
69
|
+
copyManagedFile(
|
|
70
|
+
path.join(packageRoot, 'agents', 'openai.yaml'),
|
|
71
|
+
path.join(destination, 'agents', 'openai.yaml'),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
console.log(`✅ Codex skill installed: ${destination}`);
|
|
75
|
+
return destination;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function installGlobalCli(): void {
|
|
79
|
+
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
80
|
+
|
|
81
|
+
console.log('\nInstalling the persistent OpenBroker CLI...');
|
|
82
|
+
const result = spawnSync(npmCommand, ['install', '-g', 'openbroker@latest'], {
|
|
83
|
+
stdio: 'inherit',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (result.error) {
|
|
87
|
+
fail(`could not start npm: ${result.error.message}`);
|
|
88
|
+
}
|
|
89
|
+
if (result.status !== 0) {
|
|
90
|
+
fail(
|
|
91
|
+
'global CLI installation failed. Fix the npm permission error, then rerun with --skip-cli.',
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function runApiWalletSetup(): void {
|
|
97
|
+
const onboardPath = path.join(packageRoot, 'scripts', 'setup', 'onboard.ts');
|
|
98
|
+
|
|
99
|
+
console.log('\nStarting restricted API-wallet onboarding...\n');
|
|
100
|
+
const result = spawnSync(
|
|
101
|
+
process.execPath,
|
|
102
|
+
['--import', 'tsx', onboardPath, '--api-wallet'],
|
|
103
|
+
{
|
|
104
|
+
stdio: 'inherit',
|
|
105
|
+
cwd: packageRoot,
|
|
106
|
+
env: process.env,
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (result.error) {
|
|
111
|
+
fail(`could not start onboarding: ${result.error.message}`);
|
|
112
|
+
}
|
|
113
|
+
if (result.status !== 0) {
|
|
114
|
+
fail('API-wallet onboarding did not complete. Rerun `openbroker setup --api-wallet`.');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function main(): void {
|
|
119
|
+
if (args.has('--help') || args.has('-h')) {
|
|
120
|
+
printUsage();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!args.has('--codex')) {
|
|
125
|
+
printUsage();
|
|
126
|
+
fail('choose a supported harness flag such as --codex');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log('OpenBroker — Codex Installation');
|
|
130
|
+
console.log('================================\n');
|
|
131
|
+
|
|
132
|
+
installCodexSkill();
|
|
133
|
+
|
|
134
|
+
if (!args.has('--skip-cli')) {
|
|
135
|
+
installGlobalCli();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!args.has('--skip-setup')) {
|
|
139
|
+
runApiWalletSetup();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('\n✅ OpenBroker installation complete.');
|
|
143
|
+
console.log('Restart Codex or start a new thread, then invoke $openbroker.');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
main();
|