@thirdfy/agent-cli 0.2.18 → 0.2.21

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 CHANGED
@@ -4,6 +4,24 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.21] - 2026-07-05
8
+
9
+ ### Added
10
+
11
+ - `console-mandate` command group: `status`, `draft`, `activate`, `revoke` for Console delegated execution (daily cap + expiry). Uses `/api/v1/console/delegation/*` and is separate from certified-agent `delegation *` commands. Pairs with Thirdfy API **v3.10.2+**.
12
+
13
+ ## [0.2.20] - 2026-07-04
14
+
15
+ ### Added
16
+
17
+ - `brain` command group: `sections`, `suggest`, `preflight`, `graduate` for Console Brain read/preflight-first strategy lanes (pairs with Thirdfy API **v3.10.0** Brain routes).
18
+
19
+ ## [0.2.19] - 2026-07-04
20
+
21
+ ### Changed
22
+
23
+ - Release packaging and docs alignment (no Brain commands in this tag; use **v0.2.20** for `brain`).
24
+
7
25
  ## [0.2.18] - 2026-07-02
8
26
 
9
27
  ### Changed
package/README.md CHANGED
@@ -40,9 +40,11 @@ Run without global install:
40
40
  npx @thirdfy/agent-cli --help
41
41
  ```
42
42
 
43
- ## What's new in v0.2.18
43
+ ## What's new in v0.2.21
44
44
 
45
- - Credits commands show USD-first summaries when the API returns Phase 1 display fields: balance (`availableUsd`), model list (`estimatedUsdPerTurn`), and estimates (`chargedUsd`). Use `--json` for the full API payload. Pairs with Thirdfy API **v3.9.5+** and `thirdfy-mcp` **v0.0.67+**.
45
+ - **Console mandate:** `thirdfy-agent console-mandate status|draft|activate|revoke` for Console delegated execution with daily cap and expiry.
46
+ - Uses the same `/api/v1/console/delegation/*` routes as Console and Account. Separate from certified-agent `delegation *` commands.
47
+ - Pairs with Thirdfy API **v3.10.2+**. See [`docs/command-reference.md`](./docs/command-reference.md).
46
48
 
47
49
  Older versions: see [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
48
50
 
@@ -312,6 +314,7 @@ Provider and venue guides are kept outside `README` so this page stays stable as
312
314
  - Delegation operations: `delegation show`, `delegation inspect`, `delegation revoke`
313
315
  - Delegation execution helpers: `delegation balance`, `delegation redeem`
314
316
  - Account: `credits balance`
317
+ - Console Brain: `brain sections`, `brain suggest`, `brain preflight`, `brain graduate` (read/preflight-first; see [`docs/command-reference.md`](./docs/command-reference.md))
315
318
 
316
319
  ## CLI routing (Commander + runtime)
317
320
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.2.18",
3
+ "version": "0.2.21",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -92,6 +92,30 @@ export const CLI_MANIFEST = [
92
92
  options: ['auth', 'execution', 'polymarket'],
93
93
  description: 'Polymarket dry-run preflight',
94
94
  },
95
+ {
96
+ path: ['venue', 'readiness'],
97
+ handler: 'commandVenueReadiness',
98
+ options: ['auth', 'venue'],
99
+ description: 'Normalized venue readiness (polymarket, hyperliquid, lighter)',
100
+ args: { query: true },
101
+ tier: 'online',
102
+ },
103
+ {
104
+ path: ['venue', 'setup'],
105
+ handler: 'commandVenueSetup',
106
+ options: ['auth', 'venue'],
107
+ description: 'Prepare or complete venue onboarding via shared API contract',
108
+ args: { query: true },
109
+ tier: 'online',
110
+ },
111
+ {
112
+ path: ['venue', 'fund'],
113
+ handler: 'commandVenueFund',
114
+ options: ['auth', 'venue'],
115
+ description: 'Return venue funding plan (does not move funds implicitly)',
116
+ args: { query: true },
117
+ tier: 'online',
118
+ },
95
119
  {
96
120
  path: ['hummingbot', 'status'],
97
121
  handler: 'commandHummingbotStatus',
@@ -196,6 +220,56 @@ export const CLI_MANIFEST = [
196
220
  options: ['auth', 'execution'],
197
221
  description: 'Quote action-tier credits for a catalog action',
198
222
  },
223
+ {
224
+ path: ['chat', 'send'],
225
+ handler: 'commandChatSend',
226
+ tier: 'online',
227
+ options: ['auth', 'chat', 'chains'],
228
+ description: 'Send a Console chat message (streaming)',
229
+ args: { message: '[message...]' },
230
+ },
231
+ {
232
+ path: ['chat', 'threads'],
233
+ handler: 'commandChatThreads',
234
+ tier: 'online',
235
+ options: ['auth'],
236
+ description: 'List Console chat threads',
237
+ },
238
+ {
239
+ path: ['chat', 'models'],
240
+ handler: 'commandChatModels',
241
+ tier: 'online',
242
+ options: ['auth'],
243
+ description: 'List Console chat models from catalog',
244
+ },
245
+ {
246
+ path: ['brain', 'sections'],
247
+ handler: 'commandBrainSections',
248
+ tier: 'online',
249
+ options: ['auth', 'chains', 'brain'],
250
+ description: 'Read Console Brain sections for trading, yield, and prediction',
251
+ },
252
+ {
253
+ path: ['brain', 'suggest'],
254
+ handler: 'commandBrainSuggest',
255
+ tier: 'online',
256
+ options: ['auth', 'chains', 'brain'],
257
+ description: 'Return a structured Brain strategy draft from current signals',
258
+ },
259
+ {
260
+ path: ['brain', 'preflight'],
261
+ handler: 'commandBrainPreflight',
262
+ tier: 'online',
263
+ options: ['auth', 'chains', 'brain'],
264
+ description: 'Run read-only Brain preflight checks for a strategy',
265
+ },
266
+ {
267
+ path: ['brain', 'graduate'],
268
+ handler: 'commandBrainGraduate',
269
+ tier: 'online',
270
+ options: ['auth', 'brain'],
271
+ description: 'Prepare an EarnClaw handoff proposal without deploying',
272
+ },
199
273
  {
200
274
  path: ['data', 'summary'],
201
275
  handler: 'commandDataSummary',
@@ -303,6 +377,34 @@ export const CLI_MANIFEST = [
303
377
  options: ['auth', 'execution'],
304
378
  description: 'Redeem via delegation',
305
379
  },
380
+ {
381
+ path: ['console-mandate', 'status'],
382
+ handler: 'commandConsoleMandateStatus',
383
+ tier: 'online',
384
+ options: ['auth', 'delegation'],
385
+ description: 'Console delegated execution status',
386
+ },
387
+ {
388
+ path: ['console-mandate', 'draft'],
389
+ handler: 'commandConsoleMandateDraft',
390
+ tier: 'online',
391
+ options: ['auth', 'delegation'],
392
+ description: 'Create Console mandate draft',
393
+ },
394
+ {
395
+ path: ['console-mandate', 'activate'],
396
+ handler: 'commandConsoleMandateActivate',
397
+ tier: 'online',
398
+ options: ['auth', 'delegation'],
399
+ description: 'Activate signed Console mandate',
400
+ },
401
+ {
402
+ path: ['console-mandate', 'revoke'],
403
+ handler: 'commandConsoleMandateRevoke',
404
+ tier: 'online',
405
+ options: ['auth', 'delegation'],
406
+ description: 'Revoke Console mandate',
407
+ },
306
408
  {
307
409
  path: ['credentials', 'upsert'],
308
410
  handler: 'commandCredentialsUpsert',
@@ -0,0 +1,10 @@
1
+ export function attachBrainOptions(cmd) {
2
+ return cmd
3
+ .option('--strategy <id>', 'Brain strategy id (default base-usdc-yield)')
4
+ .option('--strategy-id <id>', 'alias for --strategy')
5
+ .option('--section <lane>', 'yield | trading | prediction')
6
+ .option('--capital-usd <amount>', 'optional capital size for strategy draft')
7
+ .option('--risk <level>', 'low | medium | high')
8
+ .option('--target <name>', 'handoff target (earnclaw)')
9
+ .option('--include-degraded', 'include degraded Brain sections', false);
10
+ }
@@ -0,0 +1,9 @@
1
+ export function attachChatOptions(cmd) {
2
+ return cmd
3
+ .option('--network <id>', 'network id (for example base-mainnet)')
4
+ .option('--model <key>', 'chat model key from catalog')
5
+ .option('--thread <id>', 'existing chat thread id')
6
+ .option('--continue', 'continue the last persisted thread')
7
+ .option('--persona <mode>', 'chat persona mode', 'thirdfy')
8
+ .option('--tool-domains <list>', 'comma-separated tool pack ids (prediction, earn, perps_hl, ...)');
9
+ }
@@ -12,6 +12,9 @@ import { attachHummingbotOptions } from './hummingbot.mjs';
12
12
  import { attachAgentRegisterOptions } from './agent.mjs';
13
13
  import { attachChainOptions } from './chains.mjs';
14
14
  import { attachCreditsOptions } from './credits.mjs';
15
+ import { attachChatOptions } from './chat.mjs';
16
+ import { attachVenueOptions } from './venue.mjs';
17
+ import { attachBrainOptions } from './brain.mjs';
15
18
 
16
19
  const BUNDLES = {
17
20
  auth: attachAuthOptions,
@@ -27,6 +30,9 @@ const BUNDLES = {
27
30
  agent: attachAgentRegisterOptions,
28
31
  chains: attachChainOptions,
29
32
  credits: attachCreditsOptions,
33
+ chat: attachChatOptions,
34
+ venue: attachVenueOptions,
35
+ brain: attachBrainOptions,
30
36
  };
31
37
 
32
38
  /** @param {import('commander').Command} cmd */
@@ -0,0 +1,12 @@
1
+ export function attachVenueOptions(cmd) {
2
+ return cmd
3
+ .option('--amount <usd>', 'Funding amount in USD')
4
+ .option('--amount-usd <usd>', 'Alias for --amount')
5
+ .option('--main-wallet-address <address>', 'Hyperliquid main wallet address')
6
+ .option('--api-wallet-address <address>', 'Hyperliquid API wallet address')
7
+ .option('--l1-address <address>', 'Lighter L1 address')
8
+ .option('--include-geoblock', 'Include Polymarket geoblock probes', true)
9
+ .option('--no-include-geoblock', 'Skip Polymarket geoblock probes')
10
+ .option('--complete', 'Run complete onboarding writes (setup command only)')
11
+ .option('--confirm-writes', 'Confirm onboarding writes');
12
+ }
@@ -50,6 +50,9 @@ function registerManifestEntry(program, entry, nodeByPath, deps) {
50
50
  if (entry.args?.query) {
51
51
  leaf.argument(entry.args.query);
52
52
  }
53
+ if (entry.args?.message) {
54
+ leaf.argument(entry.args.message);
55
+ }
53
56
 
54
57
  const handler = handlers[entry.handler];
55
58
  if (!handler) {
@@ -62,6 +65,11 @@ function registerManifestEntry(program, entry, nodeByPath, deps) {
62
65
 
63
66
  if (entry.args?.address) {
64
67
  extra.address = actionArgs[0];
68
+ } else if (entry.args?.message) {
69
+ const messageArg = actionArgs[0];
70
+ extra.message = Array.isArray(messageArg)
71
+ ? messageArg.join(' ')
72
+ : String(messageArg || '').trim();
65
73
  } else if (entry.args?.query) {
66
74
  const queryArg = actionArgs[0];
67
75
  extra.query = Array.isArray(queryArg) ? queryArg : queryArg !== undefined ? [queryArg] : [];
@@ -78,6 +86,8 @@ function registerManifestEntry(program, entry, nodeByPath, deps) {
78
86
  } else if (entry.handler === 'commandPrompt') {
79
87
  const tokens = Array.isArray(extra.query) ? extra.query : [];
80
88
  await handler(ctx, flags, capabilities, tokens);
89
+ } else if (entry.handler === 'commandChatSend') {
90
+ await handler(ctx, flags, capabilities, extra.message);
81
91
  } else {
82
92
  await handler(ctx, flags, capabilities);
83
93
  }
@@ -26,6 +26,8 @@ export function createBootstrapCommands(deps) {
26
26
  printEnvelope,
27
27
  extractAgentApiKey,
28
28
  extractAgentKey,
29
+ maskSecret,
30
+ buildOwnerAuthHeaders,
29
31
  buildOnboardingHelp,
30
32
  buildWalletChallengePayload,
31
33
  issueBootstrapToken,
@@ -162,12 +164,47 @@ async function commandHelpOnboarding(ctx, _flags) {
162
164
  }
163
165
 
164
166
 
165
- async function commandWhoami(ctx, _flags) {
167
+ async function commandWhoami(ctx, flags) {
166
168
  const config = loadProfileConfig();
167
169
  const auth = config.auth && typeof config.auth === 'object' ? config.auth : {};
168
170
  const agent = config.agent && typeof config.agent === 'object' ? config.agent : {};
169
171
  const wallets = config.wallets && typeof config.wallets === 'object' ? config.wallets : {};
172
+ const chat = config.chat && typeof config.chat === 'object' ? config.chat : {};
170
173
  const runMode = ctx.runMode || config.runMode || 'agent_wallet';
174
+
175
+ let mandateSummary = null;
176
+ let mandateSummaryError = null;
177
+ const hasPrivyAuth = Boolean(
178
+ auth.authToken ||
179
+ auth.ownerSessionToken ||
180
+ process.env.THIRDFY_AUTH_TOKEN ||
181
+ process.env.THIRDFY_OWNER_SESSION_TOKEN ||
182
+ flags.authToken,
183
+ );
184
+ const hasAgentApiKey = Boolean(agent.apiKey || process.env.THIRDFY_AGENT_API_KEY);
185
+
186
+ if (hasPrivyAuth) {
187
+ try {
188
+ const headers = buildOwnerAuthHeaders(
189
+ flags,
190
+ 'Missing credentials for mandate summary (auth token or owner session required).',
191
+ );
192
+ const chainId = Number(chat.chainId || flags.chainId || 8453);
193
+ const query = new URLSearchParams({ chainId: String(chainId) });
194
+ const walletAddress = String(
195
+ wallets.primaryEvmWallet || flags.walletAddress || '',
196
+ ).trim();
197
+ if (walletAddress) query.set('walletAddress', walletAddress);
198
+ mandateSummary = await apiGet(
199
+ ctx,
200
+ `/api/v1/console/mandate-summary?${query.toString()}`,
201
+ headers,
202
+ );
203
+ } catch (error) {
204
+ mandateSummaryError = error?.message || 'MANDATE_SUMMARY_FAILED';
205
+ }
206
+ }
207
+
171
208
  printEnvelope({
172
209
  success: true,
173
210
  code: 'WHOAMI_OK',
@@ -188,6 +225,14 @@ async function commandWhoami(ctx, _flags) {
188
225
  agentApiKey: maskSecret(agent.apiKey),
189
226
  agentKey: agent.agentKey || null,
190
227
  },
228
+ chat: {
229
+ lastThreadId: chat.lastThreadId || null,
230
+ defaultChatModel: chat.defaultChatModel || null,
231
+ chainId: chat.chainId || null,
232
+ },
233
+ mandateSummary,
234
+ mandateSummaryError,
235
+ mandateSummarySkipped: !hasPrivyAuth && hasAgentApiKey ? 'requires_privy_auth' : null,
191
236
  wallets: {
192
237
  userDid: wallets.userDid || config.identity?.userDid || null,
193
238
  primaryEvmWallet: wallets.primaryEvmWallet || null,
@@ -0,0 +1,135 @@
1
+ import { loadProfileConfig } from '../core/context.mjs';
2
+ import { apiGet } from '../core/http.mjs';
3
+
4
+ function buildAuthHeaders(flags) {
5
+ const config = loadProfileConfig();
6
+ const explicitOwner = String(flags.ownerSessionToken || '').trim();
7
+ const explicitAuth = String(flags.authToken || '').trim();
8
+ const ownerSession = String(
9
+ process.env.THIRDFY_OWNER_SESSION_TOKEN || config?.auth?.ownerSessionToken || '',
10
+ ).trim();
11
+ const authToken = String(process.env.THIRDFY_AUTH_TOKEN || config?.auth?.authToken || '').trim();
12
+
13
+ if (explicitOwner || ownerSession) {
14
+ return { 'x-owner-session-token': explicitOwner || ownerSession };
15
+ }
16
+ const token = explicitAuth || authToken;
17
+ if (token) {
18
+ return { Authorization: `Bearer ${token}` };
19
+ }
20
+ throw new Error(
21
+ 'Missing credentials: provide --auth-token, THIRDFY_AUTH_TOKEN, or --owner-session-token.',
22
+ );
23
+ }
24
+
25
+ function resolveChainId(flags, config) {
26
+ if (flags.chainId) {
27
+ const parsed = Number(flags.chainId);
28
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
29
+ }
30
+ const fromConfig = Number(config?.chat?.chainId || 0);
31
+ if (Number.isFinite(fromConfig) && fromConfig > 0) return fromConfig;
32
+ return 8453;
33
+ }
34
+
35
+ function resolveWalletAddress(flags, config) {
36
+ const explicit = String(flags.walletAddress || '').trim();
37
+ if (explicit) return explicit;
38
+ const wallets = config?.wallets && typeof config.wallets === 'object' ? config.wallets : {};
39
+ return String(wallets.primaryEvmWallet || '').trim() || undefined;
40
+ }
41
+
42
+ function buildQuery(params) {
43
+ const search = new URLSearchParams();
44
+ for (const [key, value] of Object.entries(params)) {
45
+ if (value == null || value === '') continue;
46
+ search.set(key, String(value));
47
+ }
48
+ const query = search.toString();
49
+ return query ? `?${query}` : '';
50
+ }
51
+
52
+ function printBrainEnvelope(printEnvelope, flags, code, message, data) {
53
+ printEnvelope(
54
+ {
55
+ success: true,
56
+ code,
57
+ message,
58
+ data,
59
+ meta: { readOnly: true },
60
+ },
61
+ flags,
62
+ );
63
+ }
64
+
65
+ export function createBrainCommands({ printEnvelope }) {
66
+ async function commandBrainSections(ctx, flags) {
67
+ const config = loadProfileConfig();
68
+ const chainId = resolveChainId(flags, config);
69
+ const walletAddress = resolveWalletAddress(flags, config);
70
+ const query = buildQuery({
71
+ chainId,
72
+ walletAddress,
73
+ includeDegraded: flags.includeDegraded === false ? 'false' : 'true',
74
+ });
75
+ const data = await apiGet(ctx, `/api/v1/console/brain-sections${query}`, buildAuthHeaders(flags));
76
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain sections loaded', data);
77
+ return data;
78
+ }
79
+
80
+ async function commandBrainSuggest(ctx, flags) {
81
+ const config = loadProfileConfig();
82
+ const chainId = resolveChainId(flags, config);
83
+ const walletAddress = resolveWalletAddress(flags, config);
84
+ const strategyId = String(flags.strategy || flags.strategyId || '').trim();
85
+ const section = String(flags.section || '').trim();
86
+ const queryParams = {
87
+ capitalUsd: flags.capitalUsd,
88
+ risk: flags.risk,
89
+ chainId,
90
+ walletAddress,
91
+ };
92
+ if (strategyId) {
93
+ queryParams.strategyId = strategyId;
94
+ } else if (section) {
95
+ queryParams.section = section;
96
+ } else {
97
+ queryParams.strategyId = 'base-usdc-yield';
98
+ }
99
+ const query = buildQuery(queryParams);
100
+ const data = await apiGet(ctx, `/api/v1/console/brain/suggest${query}`, buildAuthHeaders(flags));
101
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain strategy draft loaded', data);
102
+ return data;
103
+ }
104
+
105
+ async function commandBrainPreflight(ctx, flags) {
106
+ const config = loadProfileConfig();
107
+ const chainId = resolveChainId(flags, config);
108
+ const walletAddress = resolveWalletAddress(flags, config);
109
+ const query = buildQuery({
110
+ strategyId: flags.strategy || flags.strategyId || 'base-usdc-yield',
111
+ chainId,
112
+ walletAddress,
113
+ });
114
+ const data = await apiGet(ctx, `/api/v1/console/brain/preflight${query}`, buildAuthHeaders(flags));
115
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain preflight loaded', data);
116
+ return data;
117
+ }
118
+
119
+ async function commandBrainGraduate(ctx, flags) {
120
+ const query = buildQuery({
121
+ strategyId: flags.strategy || flags.strategyId || 'base-usdc-yield',
122
+ target: flags.target || 'earnclaw',
123
+ });
124
+ const data = await apiGet(ctx, `/api/v1/console/brain/graduate${query}`, buildAuthHeaders(flags));
125
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain EarnClaw handoff proposal loaded', data);
126
+ return data;
127
+ }
128
+
129
+ return {
130
+ commandBrainSections,
131
+ commandBrainSuggest,
132
+ commandBrainPreflight,
133
+ commandBrainGraduate,
134
+ };
135
+ }
@@ -0,0 +1,404 @@
1
+ import { parseBooleanFlag } from '../core/runMode.mjs';
2
+ import { loadProfileConfig, persistProfileConfig } from '../core/context.mjs';
3
+ import { apiGet, safeJsonParse } from '../core/http.mjs';
4
+
5
+ const NETWORK_CHAIN_IDS = {
6
+ 'base-mainnet': 8453,
7
+ 'base-sepolia': 84532,
8
+ };
9
+
10
+ const DEFAULT_CHAT_CHAIN_ID = 8453;
11
+ const CHAT_STREAM_TIMEOUT_MS = 180_000;
12
+
13
+ function resolveChatChainId(flags, config) {
14
+ if (flags.chainId) {
15
+ const parsed = Number(flags.chainId);
16
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
17
+ }
18
+ const network = String(flags.network || '').trim().toLowerCase();
19
+ if (network && NETWORK_CHAIN_IDS[network]) return NETWORK_CHAIN_IDS[network];
20
+ const fromConfig = Number(config?.chat?.chainId || 0);
21
+ if (Number.isFinite(fromConfig) && fromConfig > 0) return fromConfig;
22
+ return DEFAULT_CHAT_CHAIN_ID;
23
+ }
24
+
25
+ function buildChatAuthHeaders(flags) {
26
+ const config = loadProfileConfig();
27
+ const explicitOwner = String(flags.ownerSessionToken || '').trim();
28
+ const explicitAuth = String(flags.authToken || '').trim();
29
+ const ownerSession = String(
30
+ process.env.THIRDFY_OWNER_SESSION_TOKEN || config?.auth?.ownerSessionToken || '',
31
+ ).trim();
32
+ const authToken = String(process.env.THIRDFY_AUTH_TOKEN || config?.auth?.authToken || '').trim();
33
+
34
+ if (explicitOwner || ownerSession) {
35
+ return { 'x-owner-session-token': explicitOwner || ownerSession };
36
+ }
37
+ const token = explicitAuth || authToken;
38
+ if (token) {
39
+ return { Authorization: `Bearer ${token}` };
40
+ }
41
+ throw new Error(
42
+ 'Missing chat credentials: provide --auth-token, THIRDFY_AUTH_TOKEN, or --owner-session-token.',
43
+ );
44
+ }
45
+
46
+ function buildChatRequestHeaders(flags, modelKey) {
47
+ const headers = {
48
+ 'content-type': 'application/json',
49
+ Accept: 'text/plain; charset=utf-8',
50
+ ...buildChatAuthHeaders(flags),
51
+ };
52
+ if (modelKey) {
53
+ headers['x-thirdfy-chat-model'] = modelKey;
54
+ }
55
+ const persona = String(flags.persona || 'thirdfy').trim();
56
+ if (persona) {
57
+ headers['x-thirdfy-chat-persona'] = persona;
58
+ }
59
+ return headers;
60
+ }
61
+
62
+ function resolveChatModelKey(flags, config) {
63
+ return (
64
+ String(flags.model || '').trim() ||
65
+ String(config?.chat?.defaultChatModel || '').trim() ||
66
+ ''
67
+ );
68
+ }
69
+
70
+ function resolveChatThreadId(flags, config) {
71
+ const explicit = String(flags.thread || flags.threadId || '').trim();
72
+ if (explicit) return explicit;
73
+ if (parseBooleanFlag(flags.continue, false)) {
74
+ return String(config?.chat?.lastThreadId || '').trim() || undefined;
75
+ }
76
+ return undefined;
77
+ }
78
+
79
+ function resolveUserAddress(flags, config) {
80
+ const explicit = String(flags.walletAddress || '').trim();
81
+ if (explicit) return explicit;
82
+ const wallets = config?.wallets && typeof config.wallets === 'object' ? config.wallets : {};
83
+ return String(wallets.primaryEvmWallet || '').trim() || undefined;
84
+ }
85
+
86
+ function parseToolDomains(flags) {
87
+ const raw = String(flags.toolDomains || '').trim();
88
+ if (!raw) return undefined;
89
+ const domains = raw
90
+ .split(',')
91
+ .map((entry) => entry.trim())
92
+ .filter(Boolean);
93
+ return domains.length ? domains : undefined;
94
+ }
95
+
96
+ function parseDataStreamLine(line) {
97
+ const trimmed = line.trim();
98
+ if (!trimmed) return null;
99
+
100
+ if (trimmed.startsWith('data: ')) {
101
+ try {
102
+ return safeJsonParse(trimmed.slice(6));
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+
108
+ const colonIndex = trimmed.indexOf(':');
109
+ if (colonIndex <= 0) return null;
110
+ const prefix = trimmed.slice(0, colonIndex);
111
+ const payload = trimmed.slice(colonIndex + 1);
112
+
113
+ if (prefix === '0') {
114
+ try {
115
+ return { type: 'text', value: String(JSON.parse(payload)) };
116
+ } catch {
117
+ return { type: 'text', value: payload };
118
+ }
119
+ }
120
+
121
+ if (prefix === '2') {
122
+ try {
123
+ const data = JSON.parse(payload);
124
+ return { type: 'data', value: Array.isArray(data) ? data : [data] };
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+
130
+ if (prefix === '3') {
131
+ try {
132
+ return { type: 'error', value: JSON.parse(payload) };
133
+ } catch {
134
+ return { type: 'error', value: payload };
135
+ }
136
+ }
137
+
138
+ return null;
139
+ }
140
+
141
+ function extractThreadMetaFromDataItems(items) {
142
+ if (!Array.isArray(items)) return null;
143
+ for (const item of items) {
144
+ if (item && typeof item === 'object' && item.type === 'thread_meta' && item.threadId) {
145
+ return item;
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+
151
+ function parseThreadMetaHeader(raw) {
152
+ if (!raw) return null;
153
+ try {
154
+ const parsed = JSON.parse(raw);
155
+ if (parsed && typeof parsed === 'object' && parsed.type === 'thread_meta') {
156
+ return parsed;
157
+ }
158
+ if (parsed && typeof parsed === 'object' && parsed.threadId) {
159
+ return { type: 'thread_meta', ...parsed };
160
+ }
161
+ } catch {
162
+ return null;
163
+ }
164
+ return null;
165
+ }
166
+
167
+ async function requestChatStream(ctx, body, headers) {
168
+ const controller = new AbortController();
169
+ const timeoutMs = Math.max(Number(ctx.timeoutMs || 0), CHAT_STREAM_TIMEOUT_MS);
170
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
171
+
172
+ try {
173
+ const response = await fetch(`${ctx.apiBase}/api/v1/chat/stream`, {
174
+ method: 'POST',
175
+ headers,
176
+ body: JSON.stringify(body),
177
+ signal: controller.signal,
178
+ });
179
+
180
+ if (!response.ok) {
181
+ const text = await response.text().catch(() => '');
182
+ const data = text ? safeJsonParse(text) : {};
183
+ const error = new Error(data?.error || data?.message || `HTTP ${response.status}`);
184
+ error.statusCode = response.status;
185
+ error.payload = data;
186
+ throw error;
187
+ }
188
+
189
+ let threadMeta =
190
+ parseThreadMetaHeader(response.headers.get('X-Thirdfy-Chat-Thread-Meta')) || null;
191
+ let threadId = response.headers.get('X-Thirdfy-Chat-Thread-Id') || undefined;
192
+ let content = '';
193
+ let streamError = null;
194
+ const toolCalls = [];
195
+
196
+ if (response.body) {
197
+ const reader = response.body.getReader();
198
+ const decoder = new TextDecoder();
199
+ let lineBuffer = '';
200
+
201
+ while (true) {
202
+ const { done, value } = await reader.read();
203
+ if (done) break;
204
+ lineBuffer += decoder.decode(value, { stream: true });
205
+ const lines = lineBuffer.split('\n');
206
+ lineBuffer = lines.pop() ?? '';
207
+
208
+ for (const line of lines) {
209
+ const parsedLine = parseDataStreamLine(line);
210
+ if (!parsedLine) continue;
211
+
212
+ if (parsedLine.type === 'text') {
213
+ content += parsedLine.value;
214
+ continue;
215
+ }
216
+
217
+ if (parsedLine.type === 'error') {
218
+ streamError = String(parsedLine.value || 'stream error');
219
+ continue;
220
+ }
221
+
222
+ if (parsedLine.type === 'data') {
223
+ const meta = extractThreadMetaFromDataItems(parsedLine.value);
224
+ if (meta) {
225
+ threadMeta = meta;
226
+ if (meta.threadId) threadId = String(meta.threadId);
227
+ }
228
+ continue;
229
+ }
230
+
231
+ if (parsedLine.type === 'content' || parsedLine.type === 'text-delta') {
232
+ content += String(parsedLine.content || parsedLine.textDelta || parsedLine.text || '');
233
+ }
234
+ if (parsedLine.type === 'tool-call' && parsedLine.toolName) {
235
+ toolCalls.push(String(parsedLine.toolName));
236
+ }
237
+ if (parsedLine.type === 'data' && Array.isArray(parsedLine.data)) {
238
+ const meta = extractThreadMetaFromDataItems(parsedLine.data);
239
+ if (meta) {
240
+ threadMeta = meta;
241
+ if (meta.threadId) threadId = String(meta.threadId);
242
+ }
243
+ }
244
+ if (parsedLine.type === 'error') {
245
+ streamError = String(parsedLine.error || parsedLine.message || 'stream error');
246
+ }
247
+ if (parsedLine.type === 'done') {
248
+ const meta = parsedLine.thread_meta || parsedLine.threadMeta;
249
+ if (meta && typeof meta === 'object') {
250
+ threadMeta = meta;
251
+ if (meta.threadId) threadId = String(meta.threadId);
252
+ }
253
+ if (parsedLine.threadId) threadId = String(parsedLine.threadId);
254
+ }
255
+ const debug = parsedLine.debug;
256
+ if (debug && Array.isArray(debug.toolCallsList)) {
257
+ for (const item of debug.toolCallsList) toolCalls.push(String(item));
258
+ }
259
+ }
260
+ }
261
+
262
+ const tail = lineBuffer.trim();
263
+ if (tail) {
264
+ const parsedLine = parseDataStreamLine(tail);
265
+ if (parsedLine?.type === 'text') content += parsedLine.value;
266
+ if (parsedLine?.type === 'data') {
267
+ const meta = extractThreadMetaFromDataItems(parsedLine.value);
268
+ if (meta) {
269
+ threadMeta = meta;
270
+ if (meta.threadId) threadId = String(meta.threadId);
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ if (streamError) {
277
+ const error = new Error(streamError);
278
+ error.statusCode = 502;
279
+ throw error;
280
+ }
281
+
282
+ return {
283
+ content,
284
+ threadId: threadId || threadMeta?.threadId || body.threadId,
285
+ threadMeta,
286
+ toolCalls,
287
+ };
288
+ } finally {
289
+ clearTimeout(timeout);
290
+ }
291
+ }
292
+
293
+ function persistChatPreferences(config, { threadId, modelKey, chainId }) {
294
+ const next = {
295
+ ...config,
296
+ chat: {
297
+ ...(config.chat && typeof config.chat === 'object' ? config.chat : {}),
298
+ },
299
+ };
300
+ if (threadId) next.chat.lastThreadId = String(threadId);
301
+ if (modelKey) next.chat.defaultChatModel = String(modelKey);
302
+ if (chainId) next.chat.chainId = Number(chainId);
303
+ persistProfileConfig(next);
304
+ return next.chat;
305
+ }
306
+
307
+ export function createChatCommands({ printEnvelope }) {
308
+ async function commandChatSend(ctx, flags, _capabilities, messageArg) {
309
+ const message = String(messageArg || flags.message || '').trim();
310
+ if (!message) {
311
+ throw new Error('Missing message. Use: thirdfy-agent chat send "<message>"');
312
+ }
313
+
314
+ const config = loadProfileConfig();
315
+ const chainId = resolveChatChainId(flags, config);
316
+ const modelKey = resolveChatModelKey(flags, config);
317
+ const threadId = resolveChatThreadId(flags, config);
318
+ const userAddress = resolveUserAddress(flags, config);
319
+ const toolDomains = parseToolDomains(flags);
320
+
321
+ const body = {
322
+ messages: [{ role: 'user', content: message }],
323
+ chainId,
324
+ personaMode: String(flags.persona || 'thirdfy').trim() || 'thirdfy',
325
+ ...(threadId ? { threadId } : {}),
326
+ ...(modelKey ? { modelKey } : {}),
327
+ ...(userAddress ? { userAddress } : {}),
328
+ ...(toolDomains ? { toolDomains } : {}),
329
+ };
330
+
331
+ const headers = buildChatRequestHeaders(flags, modelKey);
332
+ const stream = await requestChatStream(ctx, body, headers);
333
+
334
+ const resolvedThreadId = stream.threadId || threadId;
335
+ const resolvedModelKey = stream.threadMeta?.modelKey || modelKey;
336
+ const persisted = persistChatPreferences(config, {
337
+ threadId: resolvedThreadId,
338
+ modelKey: resolvedModelKey,
339
+ chainId,
340
+ });
341
+
342
+ if (!flags.json && stream.content) {
343
+ process.stdout.write(stream.content);
344
+ if (!stream.content.endsWith('\n')) process.stdout.write('\n');
345
+ }
346
+
347
+ const threadLabel = resolvedThreadId ? ` (thread ${resolvedThreadId})` : '';
348
+ printEnvelope({
349
+ success: true,
350
+ code: 'CHAT_SEND_OK',
351
+ message: flags.json ? 'Chat response completed' : `Chat response completed${threadLabel}`,
352
+ data: {
353
+ ...(flags.json ? { content: stream.content } : {}),
354
+ threadId: resolvedThreadId || null,
355
+ threadMeta: stream.threadMeta || null,
356
+ toolCalls: stream.toolCalls,
357
+ modelKey: resolvedModelKey || null,
358
+ chainId,
359
+ persisted,
360
+ },
361
+ meta: {
362
+ apiBase: ctx.apiBase,
363
+ continued: parseBooleanFlag(flags.continue, false),
364
+ network: flags.network || null,
365
+ },
366
+ });
367
+ }
368
+
369
+ async function commandChatThreads(ctx, flags) {
370
+ const headers = buildChatAuthHeaders(flags);
371
+ const query = new URLSearchParams();
372
+ if (flags.limit) query.set('limit', String(flags.limit));
373
+ if (flags.status) query.set('status', String(flags.status));
374
+ const route = query.size
375
+ ? `/api/v1/chat/threads?${query.toString()}`
376
+ : '/api/v1/chat/threads';
377
+ const response = await apiGet(ctx, route, headers);
378
+ printEnvelope({
379
+ success: true,
380
+ code: 'CHAT_THREADS_OK',
381
+ message: 'Chat threads loaded',
382
+ data: response,
383
+ meta: { apiBase: ctx.apiBase },
384
+ });
385
+ }
386
+
387
+ async function commandChatModels(ctx, flags) {
388
+ const headers = buildChatAuthHeaders(flags);
389
+ const response = await apiGet(ctx, '/api/v1/chat/models', headers);
390
+ printEnvelope({
391
+ success: true,
392
+ code: 'CHAT_MODELS_OK',
393
+ message: 'Chat models loaded',
394
+ data: response,
395
+ meta: { apiBase: ctx.apiBase },
396
+ });
397
+ }
398
+
399
+ return {
400
+ commandChatSend,
401
+ commandChatThreads,
402
+ commandChatModels,
403
+ };
404
+ }
@@ -0,0 +1,125 @@
1
+ import { requireFlag } from '../core/args.mjs';
2
+ import { apiGet, apiPost } from '../core/http.mjs';
3
+
4
+ export function createConsoleMandateCommands(deps) {
5
+ const { buildOwnerAuthHeaders, printEnvelope } = deps;
6
+
7
+ async function commandConsoleMandateStatus(ctx, flags) {
8
+ const authHeaders = buildOwnerAuthHeaders(
9
+ flags,
10
+ 'Missing --auth-token/--owner-session-token for console mandate status',
11
+ );
12
+ const chainId = Number(flags.chainId || 8453);
13
+ const walletAddress = String(flags.walletAddress || flags.ownerAddress || '').trim();
14
+ const query = new URLSearchParams({ chainId: String(chainId) });
15
+ if (walletAddress) query.set('walletAddress', walletAddress);
16
+ const response = await apiGet(ctx, `/api/v1/console/delegation/status?${query.toString()}`, {
17
+ ...authHeaders,
18
+ headers: {
19
+ ...(authHeaders.headers || {}),
20
+ 'x-thirdfy-surface': 'cli',
21
+ },
22
+ });
23
+ printEnvelope({
24
+ success: Boolean(response?.success !== false),
25
+ code: 'CONSOLE_MANDATE_STATUS',
26
+ message: 'Console delegated execution status',
27
+ data: response?.data || response,
28
+ meta: { apiBase: ctx.apiBase },
29
+ });
30
+ }
31
+
32
+ async function commandConsoleMandateDraft(ctx, flags) {
33
+ const authHeaders = buildOwnerAuthHeaders(
34
+ flags,
35
+ 'Missing --auth-token/--owner-session-token for console mandate draft',
36
+ );
37
+ const payload = {
38
+ ownerAddress: requireFlag(flags, 'ownerAddress', 'Missing --owner-address'),
39
+ chainId: Number(flags.chainId || 8453),
40
+ maxUsdPerDay: Number(requireFlag(flags, 'maxUsdPerDay', 'Missing --max-usd-per-day')),
41
+ expirySeconds: Number(flags.expirySeconds || 30 * 24 * 60 * 60),
42
+ tokenAddress: flags.tokenAddress,
43
+ periodDuration: Number(flags.periodDuration || 86_400),
44
+ };
45
+ const response = await apiPost(ctx, '/api/v1/console/delegation/draft', payload, {
46
+ ...authHeaders,
47
+ headers: {
48
+ ...(authHeaders.headers || {}),
49
+ 'x-thirdfy-surface': 'cli',
50
+ },
51
+ });
52
+ printEnvelope({
53
+ success: Boolean(response?.success !== false),
54
+ code: 'CONSOLE_MANDATE_DRAFT',
55
+ message: 'Console mandate draft created',
56
+ data: response?.data || response,
57
+ meta: { apiBase: ctx.apiBase },
58
+ });
59
+ }
60
+
61
+ async function commandConsoleMandateActivate(ctx, flags) {
62
+ const authHeaders = buildOwnerAuthHeaders(
63
+ flags,
64
+ 'Missing --auth-token/--owner-session-token for console mandate activate',
65
+ );
66
+ const payload = {
67
+ walletAddress: requireFlag(flags, 'walletAddress', 'Missing --wallet-address'),
68
+ chainId: Number(flags.chainId || 8453),
69
+ delegationManager: requireFlag(flags, 'delegationManager', 'Missing --delegation-manager'),
70
+ delegation: JSON.parse(requireFlag(flags, 'delegation', 'Missing --delegation JSON')),
71
+ signature: requireFlag(flags, 'signature', 'Missing --signature'),
72
+ permissionsExpiry: flags.permissionsExpiry,
73
+ maxUsdPerDay: Number(requireFlag(flags, 'maxUsdPerDay', 'Missing --max-usd-per-day')),
74
+ periodDuration: Number(flags.periodDuration || 86_400),
75
+ tokenAddress: flags.tokenAddress,
76
+ };
77
+ const response = await apiPost(ctx, '/api/v1/console/delegation/activate', payload, {
78
+ ...authHeaders,
79
+ headers: {
80
+ ...(authHeaders.headers || {}),
81
+ 'x-thirdfy-surface': 'cli',
82
+ },
83
+ });
84
+ printEnvelope({
85
+ success: Boolean(response?.success !== false),
86
+ code: 'CONSOLE_MANDATE_ACTIVATED',
87
+ message: 'Console mandate activated',
88
+ data: response?.data || response,
89
+ meta: { apiBase: ctx.apiBase },
90
+ });
91
+ }
92
+
93
+ async function commandConsoleMandateRevoke(ctx, flags) {
94
+ const authHeaders = buildOwnerAuthHeaders(
95
+ flags,
96
+ 'Missing --auth-token/--owner-session-token for console mandate revoke',
97
+ );
98
+ const payload = {
99
+ walletAddress: flags.walletAddress,
100
+ chainId: Number(flags.chainId || 8453),
101
+ reason: flags.reason || 'cli_revoked',
102
+ };
103
+ const response = await apiPost(ctx, '/api/v1/console/delegation/revoke', payload, {
104
+ ...authHeaders,
105
+ headers: {
106
+ ...(authHeaders.headers || {}),
107
+ 'x-thirdfy-surface': 'cli',
108
+ },
109
+ });
110
+ printEnvelope({
111
+ success: Boolean(response?.success !== false),
112
+ code: 'CONSOLE_MANDATE_REVOKED',
113
+ message: 'Console mandate revoked',
114
+ data: response?.data || response,
115
+ meta: { apiBase: ctx.apiBase },
116
+ });
117
+ }
118
+
119
+ return {
120
+ commandConsoleMandateStatus,
121
+ commandConsoleMandateDraft,
122
+ commandConsoleMandateActivate,
123
+ commandConsoleMandateRevoke,
124
+ };
125
+ }
@@ -0,0 +1,110 @@
1
+ import { apiGet, apiPost } from '../core/http.mjs';
2
+ import { loadProfileConfig } from '../core/context.mjs';
3
+
4
+ const VENUES = new Set(['polymarket', 'hyperliquid', 'lighter']);
5
+
6
+ function resolveVenue(flags) {
7
+ const fromQuery = Array.isArray(flags.query) ? flags.query[0] : flags.query;
8
+ const venue = String(flags.venue || fromQuery || '').trim().toLowerCase();
9
+ if (!VENUES.has(venue)) {
10
+ throw new Error(`Unsupported venue "${venue}". Use polymarket, hyperliquid, or lighter.`);
11
+ }
12
+ return venue;
13
+ }
14
+
15
+ function extractAgentKey(value) {
16
+ if (!value || typeof value !== 'object') return '';
17
+ const candidates = [
18
+ value.agentKey,
19
+ value.data?.agentKey,
20
+ value.bootstrap?.agentKey,
21
+ value.registration?.agentKey,
22
+ value.registration?.registration?.agentKey,
23
+ value.data?.registration?.agentKey,
24
+ value.data?.registration?.registration?.agentKey,
25
+ value.owner?.creatorWallet,
26
+ value.data?.owner?.creatorWallet,
27
+ ];
28
+ return String(candidates.find((candidate) => String(candidate || '').trim()) || '').trim();
29
+ }
30
+
31
+ function resolveVenueAgentKey(flags) {
32
+ const fromFlags = String(flags.agentKey || '').trim();
33
+ if (fromFlags) return fromFlags;
34
+ const config = loadProfileConfig();
35
+ const fromAgent = String(config?.agent?.agentKey || '').trim();
36
+ if (fromAgent) return fromAgent;
37
+ const fromConfig = extractAgentKey(config);
38
+ if (fromConfig) return fromConfig;
39
+ throw new Error('Missing --agent-key (or config.agent.agentKey). Venue tooling uses --agent-api-key only for authentication.');
40
+ }
41
+
42
+ function buildAgentQuery(agentKey, flags) {
43
+ const query = new URLSearchParams({ agentKey });
44
+ if (flags.mainWalletAddress) query.set('mainWalletAddress', String(flags.mainWalletAddress));
45
+ if (flags.apiWalletAddress) query.set('apiWalletAddress', String(flags.apiWalletAddress));
46
+ if (flags.l1Address) query.set('l1Address', String(flags.l1Address));
47
+ if (flags.amountUsd) query.set('amountUsd', String(flags.amountUsd));
48
+ if (flags.includeGeoblock === false) query.set('includeGeoblock', 'false');
49
+ return query;
50
+ }
51
+
52
+ export function createVenueCommands({ printEnvelope, resolveAgentApiKey }) {
53
+ function buildAuthHeaders(flags) {
54
+ const agentApiKey = resolveAgentApiKey(flags, flags.runMode || 'agent_wallet');
55
+ return { 'x-agent-api-key': agentApiKey };
56
+ }
57
+
58
+ async function commandVenueReadiness(ctx, flags) {
59
+ const venue = resolveVenue(flags);
60
+ const agentKey = resolveVenueAgentKey(flags);
61
+ const query = buildAgentQuery(agentKey, flags);
62
+ query.set('venue', venue);
63
+ const response = await apiGet(ctx, `/api/v1/agent/venue/readiness?${query.toString()}`, buildAuthHeaders(flags));
64
+ printEnvelope(response);
65
+ }
66
+
67
+ async function commandVenueSetup(ctx, flags) {
68
+ const venue = resolveVenue(flags);
69
+ const agentKey = resolveVenueAgentKey(flags);
70
+ const complete = Boolean(flags.complete);
71
+ const confirmWrites = Boolean(flags.confirmWrites);
72
+ const body = {
73
+ venue,
74
+ agentKey,
75
+ dryRun: complete ? false : !confirmWrites,
76
+ confirmWrites,
77
+ ...(flags.mainWalletAddress ? { mainWalletAddress: String(flags.mainWalletAddress) } : {}),
78
+ ...(flags.apiWalletAddress ? { apiWalletAddress: String(flags.apiWalletAddress) } : {}),
79
+ ...(flags.l1Address ? { l1Address: String(flags.l1Address) } : {}),
80
+ ...(flags.amountUsd ? { amountUsd: Number(flags.amountUsd) } : {}),
81
+ };
82
+ const path = flags.complete ? '/api/v1/agent/venue/complete' : '/api/v1/agent/venue/prepare';
83
+ const response = await apiPost(ctx, path, body, buildAuthHeaders(flags));
84
+ printEnvelope(response);
85
+ }
86
+
87
+ async function commandVenueFund(ctx, flags) {
88
+ const venue = resolveVenue(flags);
89
+ const agentKey = resolveVenueAgentKey(flags);
90
+ const amountUsd = Number(flags.amount || flags.amountUsd || 0);
91
+ if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
92
+ throw new Error('Provide --amount with a positive USD value.');
93
+ }
94
+ const response = await apiPost(ctx, '/api/v1/agent/venue/fund', {
95
+ venue,
96
+ agentKey,
97
+ amountUsd,
98
+ ...(flags.mainWalletAddress ? { mainWalletAddress: String(flags.mainWalletAddress) } : {}),
99
+ ...(flags.apiWalletAddress ? { apiWalletAddress: String(flags.apiWalletAddress) } : {}),
100
+ ...(flags.l1Address ? { l1Address: String(flags.l1Address) } : {}),
101
+ }, buildAuthHeaders(flags));
102
+ printEnvelope(response);
103
+ }
104
+
105
+ return {
106
+ commandVenueReadiness,
107
+ commandVenueSetup,
108
+ commandVenueFund,
109
+ };
110
+ }
@@ -6,14 +6,18 @@ import { createLighterHelpers } from '../commands/lighter.mjs';
6
6
  import { createExecuteCommands } from '../commands/execute.mjs';
7
7
  import { createWalletCommands } from '../commands/wallet.mjs';
8
8
  import { createDelegationCommands } from '../commands/delegation.mjs';
9
+ import { createConsoleMandateCommands } from '../commands/consoleMandate.mjs';
9
10
  import { createBootstrapCommands } from '../commands/bootstrap.mjs';
10
11
  import { createDiscoveryCommands } from '../commands/discovery.mjs';
11
12
  import { createCreditsCommands } from '../commands/credits.mjs';
13
+ import { createChatCommands } from '../commands/chat.mjs';
14
+ import { createBrainCommands } from '../commands/brain.mjs';
12
15
  import { createTelemetryCommands } from '../commands/telemetry.mjs';
13
16
  import { createCredentialsCommands } from '../commands/credentials.mjs';
14
17
  import { createAgentCommands } from '../commands/agent.mjs';
15
18
  import { createDoctorCommands } from '../commands/doctor.mjs';
16
19
  import { createPromptCommands } from '../commands/prompt.mjs';
20
+ import { createVenueCommands } from '../commands/venue.mjs';
17
21
 
18
22
  /**
19
23
  * Wire command-module factories and local handlers for Commander manifest registration.
@@ -62,6 +66,14 @@ export function createRuntimeHandlers(deps) {
62
66
  getAuthToken,
63
67
  });
64
68
 
69
+ const __chat = createChatCommands({
70
+ printEnvelope,
71
+ });
72
+
73
+ const __brain = createBrainCommands({
74
+ printEnvelope,
75
+ });
76
+
65
77
  const __telemetry = createTelemetryCommands({
66
78
  printEnvelope,
67
79
  resolveAgentApiKey,
@@ -94,6 +106,7 @@ export function createRuntimeHandlers(deps) {
94
106
  });
95
107
 
96
108
  const __prompt = createPromptCommands({ printEnvelope });
109
+ const __venue = createVenueCommands({ printEnvelope, resolveAgentApiKey });
97
110
 
98
111
  const __hyperliquid = createHyperliquidHelpers({
99
112
  getPreparedParams,
@@ -144,6 +157,11 @@ export function createRuntimeHandlers(deps) {
144
157
  commandRun: __execute.commandRun,
145
158
  });
146
159
 
160
+ const __consoleMandate = createConsoleMandateCommands({
161
+ buildOwnerAuthHeaders,
162
+ printEnvelope,
163
+ });
164
+
147
165
  const __polymarket = createPolymarketCommands({
148
166
  commandPreflight: __execute.commandPreflight,
149
167
  printEnvelope,
@@ -157,6 +175,8 @@ export function createRuntimeHandlers(deps) {
157
175
  printEnvelope,
158
176
  extractAgentApiKey,
159
177
  extractAgentKey,
178
+ maskSecret,
179
+ buildOwnerAuthHeaders,
160
180
  buildOnboardingHelp: __doctor.buildOnboardingHelp,
161
181
  buildWalletChallengePayload: __agent.buildWalletChallengePayload,
162
182
  issueBootstrapToken: __agent.issueBootstrapToken,
@@ -170,6 +190,7 @@ export function createRuntimeHandlers(deps) {
170
190
  ...__execute,
171
191
  ...__wallet,
172
192
  ...__delegation,
193
+ ...__consoleMandate,
173
194
  ...__polymarket,
174
195
  ...__hummingbot,
175
196
  ...__bootstrap,
@@ -179,6 +200,7 @@ export function createRuntimeHandlers(deps) {
179
200
  ...__agent,
180
201
  ...__doctor,
181
202
  ...__prompt,
203
+ ...__venue,
182
204
  commandDoctorSelf: __doctor.commandDoctorSelf,
183
205
  commandDoctorAuth: __doctor.commandDoctorAuth,
184
206
  commandManagedSetup: __doctor.commandManagedSetup,
@@ -190,6 +212,13 @@ export function createRuntimeHandlers(deps) {
190
212
  commandModelsList: __credits.commandModelsList,
191
213
  commandModelsEstimate: __credits.commandModelsEstimate,
192
214
  commandPricingQuote: __credits.commandPricingQuote,
215
+ commandChatSend: __chat.commandChatSend,
216
+ commandChatThreads: __chat.commandChatThreads,
217
+ commandChatModels: __chat.commandChatModels,
218
+ commandBrainSections: __brain.commandBrainSections,
219
+ commandBrainSuggest: __brain.commandBrainSuggest,
220
+ commandBrainPreflight: __brain.commandBrainPreflight,
221
+ commandBrainGraduate: __brain.commandBrainGraduate,
193
222
  commandDataSummary: __telemetry.commandDataSummary,
194
223
  commandTrackList: __telemetry.commandTrackList,
195
224
  commandTrackAction: __telemetry.commandTrackAction,
@@ -203,5 +232,8 @@ export function createRuntimeHandlers(deps) {
203
232
  commandAnalyticsPortfolio: __telemetry.commandAnalyticsPortfolio,
204
233
  commandAnalyticsLeaderboard: __telemetry.commandAnalyticsLeaderboard,
205
234
  commandPrompt: __prompt.commandPrompt,
235
+ commandVenueReadiness: __venue.commandVenueReadiness,
236
+ commandVenueSetup: __venue.commandVenueSetup,
237
+ commandVenueFund: __venue.commandVenueFund,
206
238
  };
207
239
  }