@agent-wire/terminal 1.7.6 → 1.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,144 +1,41 @@
1
1
  #!/usr/bin/env node
2
2
  import { loadConfig, saveConfig } from './config.js';
3
- import { CONFIG_DIR } from './config.js';
4
3
  import { WireAPI } from './api.js';
5
4
  import { startBackgroundWorkLoop } from './background-worker.js';
6
5
  import { acquireLock, releaseLock, isWorkerRunning } from './lockfile.js';
7
6
  import { runWaitCommand } from './wait-cli.js';
8
- import { formatLocalPullReport, pullLocalSubscriptions, writeDefaultLocalPullManifest } from './local-pull.js';
9
- import { readFileSync, writeFileSync, watch as fsWatch, existsSync, mkdirSync } from 'fs';
10
- import { resolve, join } from 'path';
11
- import { createInterface } from 'readline';
12
- import { walkDirectory, computeDiff, pushFiles, pullFiles, generatePreview, parseManifest, serializeManifest, updateManifest, resolveConflicts, } from './sync/index.js';
7
+ import { runProjectedCommand } from './cli-projection.js';
8
+ import { resumeToken } from './resume.js';
13
9
  const args = process.argv.slice(2);
14
10
  const command = args[0];
15
11
  const commandHelpRequested = args.includes('--help') || args.includes('-h');
16
12
  function printInitUsage() {
17
- console.error('Usage: agent-wire-terminal init [--token TOKEN]');
13
+ console.error('Usage: npx -y @agent-wire/terminal init [--token TOKEN]');
18
14
  console.error('');
19
- console.error('Register this node with the Wire network.');
20
- console.error('Requires an API token from /api/v1/register or WIRE_API_TOKEN env var.');
15
+ console.error('Resume the existing agent identified by your saved API token.');
16
+ console.error('Terminal 1.7.9+: set WIRE_API_TOKEN_FILE to the absolute path of your API token file.');
17
+ console.error('WIRE_API_TOKEN is supported on every terminal version.');
18
+ console.error('Token precedence: WIRE_API_TOKEN > WIRE_API_TOKEN_FILE > saved config.');
21
19
  }
22
20
  function printStartUsage() {
23
- console.error('Usage: agent-wire-terminal start');
21
+ console.error('Usage: npx -y @agent-wire/terminal start');
24
22
  console.error('');
25
23
  console.error('Run standalone node daemon. Acquires a PID lock, polls for work, and earns credits.');
26
24
  }
27
25
  function printServeUsage() {
28
- console.error('Usage: agent-wire-terminal serve [options]');
26
+ console.error('Usage: npx -y @agent-wire/terminal serve [options]');
29
27
  console.error('');
30
28
  console.error('Start MCP server. Defaults to stdio transport.');
29
+ console.error('Terminal 1.7.9+ for Claude/other MCP clients: env: { "WIRE_API_TOKEN_FILE": "/absolute/path/to/token" }');
30
+ console.error('WIRE_API_TOKEN is the alternative on every terminal version.');
31
+ console.error('In file mode, wire_identify registration/device-resume tokens are session-only.');
32
+ console.error('Restarts resume the identity in the file; have your operator provision that file to keep a new identity.');
31
33
  console.error('');
32
34
  console.error('Options:');
33
35
  console.error(' --http Use HTTP transport instead of stdio');
34
36
  console.error(' --port PORT HTTP port (default: 3200)');
35
37
  console.error(' --no-worker Skip background work loop');
36
38
  }
37
- function printBalanceUsage() {
38
- console.error('Usage: agent-wire-terminal balance');
39
- console.error('');
40
- console.error('Check operator pool credits, reputation, and jobs.');
41
- }
42
- function printStatusUsage() {
43
- console.error('Usage: agent-wire-terminal status');
44
- console.error('');
45
- console.error('Show current config: API URL, token, node ID, and capabilities.');
46
- }
47
- function printSyncUsage() {
48
- console.error('Usage: agent-wire-terminal sync --dir PATH --corpus SLUG --action diff|push|pull|preview [options]');
49
- console.error('');
50
- console.error('Sync local directory with a Wire corpus.');
51
- console.error('');
52
- console.error('Options:');
53
- console.error(' --dir PATH Local directory to sync (required)');
54
- console.error(' --corpus SLUG Wire corpus slug (required)');
55
- console.error(' --action ACTION diff|push|pull|preview (required)');
56
- console.error(' --watch Watch for changes, auto-push (push only)');
57
- console.error(' --publish Publish documents on push (default: draft)');
58
- console.error(' --market-native-docs-ingest MODE');
59
- console.error(' Route push through /wire/sync and dispatch market-native');
60
- console.error(' docs ingest. MODE: off|auto|all (default: off)');
61
- console.error(' Oversized docs use 8000-token windows with 2000-token overlap.');
62
- console.error(' --yes Skip confirmation prompts');
63
- }
64
- function printPullUsage() {
65
- console.error('Usage: agent-wire-terminal pull [--manifest PATH] [--init] [--dry-run] [--json]');
66
- console.error('');
67
- console.error('Pull subscribed Wire contribution bodies into local cache/skill files.');
68
- console.error('Default manifest: ~/.wire-node/sync-manifest.json');
69
- }
70
- function printChainUsage() {
71
- console.error('Usage: agent-wire-terminal chain run --chain HANDLE_OR_UUID --input-json JSON --quote');
72
- console.error(' agent-wire-terminal chain run --chain HANDLE_OR_UUID --input-json JSON --quote-id TOKEN [--async-ack|--timeout-ms MS]');
73
- console.error(' agent-wire-terminal chain run --chain HANDLE_OR_UUID --input-json JSON --auto --max-credits N [--async-ack|--timeout-ms MS]');
74
- console.error(' agent-wire-terminal chain poll --chain HANDLE_OR_UUID --run-handle HANDLE_PATH [--include-steps]');
75
- console.error('');
76
- console.error('Quote, execute, or poll a canonical Wire chain.');
77
- console.error('');
78
- console.error('Options:');
79
- console.error(' --chain VALUE Chain handle, UUID, or canonical target (required)');
80
- console.error(' --input-json JSON JSON object input (default: {})');
81
- console.error(' --quote Request quote mode');
82
- console.error(' --quote-id TOKEN Execute trusted mode with quote token');
83
- console.error(' --auto Quote server-side and execute only when price is <= --max-credits');
84
- console.error(' --max-credits N Required with --auto; positive integer price cap');
85
- console.error(' --async-ack Return immediately with a pollable async run handle');
86
- console.error(' --timeout-ms MS Trusted invoke deadline (default: 600000ms; max: 1800000ms)');
87
- console.error(' --run-handle HANDLE Async run handle path for chain poll');
88
- console.error(' --run-id UUID Diagnostic async run id for chain poll');
89
- console.error(' --entry-mode MODE direct|start (default: direct)');
90
- console.error(' --chain-id UUID Optional chain UUID to bind in quote');
91
- console.error(' --include-steps Include step_results in execute response');
92
- }
93
- function printSurfaceUsage() {
94
- console.error('Usage: agent-wire-terminal s [list|init]');
95
- console.error(' agent-wire-terminal s SHORTCUT [--input-json JSON] [--quote|--quote-id TOKEN|--auto --max-credits N] [--async-ack|--timeout-ms MS]');
96
- console.error(' agent-wire-terminal surface SHORTCUT [--input-json JSON] [--quote|--quote-id TOKEN|--auto --max-credits N] [--async-ack|--timeout-ms MS]');
97
- console.error('');
98
- console.error('Resolve local surface/holster shortcuts to canonical Wire chain runs.');
99
- console.error('');
100
- console.error('Options:');
101
- console.error(' --holster PATH Shortcut holster JSON path (default: ~/.wire-node/surface-shortcuts.json)');
102
- console.error(' --input-json JSON JSON object merged over shortcut input');
103
- console.error(' --quote Request quote mode (default when --quote-id is absent)');
104
- console.error(' --quote-id TOKEN Execute trusted mode with quote token');
105
- console.error(' --auto Quote server-side and execute only when price is <= --max-credits');
106
- console.error(' --max-credits N Required with --auto; positive integer price cap');
107
- console.error(' --async-ack Return immediately with a pollable async run handle');
108
- console.error(' --timeout-ms MS Trusted invoke deadline (default: 600000ms; max: 1800000ms)');
109
- console.error(' --entry-mode MODE direct|start (default from shortcut or direct)');
110
- console.error(' --chain-id UUID Optional chain UUID to bind in quote');
111
- console.error(' --include-steps Include step_results in execute response');
112
- console.error('');
113
- console.error('Seeded canary input:');
114
- console.error(' agent-wire-terminal s canary --input-json \'{"battery_ref":"pr77-smoke","test_run_id":"surface-smoke-001","subject_agent":"agent/playful/codex-newman","source_principal":"agent/playful/codex-kramer"}\' --quote');
115
- console.error(' source_principal and subject_agent must be different.');
116
- }
117
- function readFlag(argv, flag) {
118
- const idx = argv.indexOf(flag);
119
- if (idx === -1)
120
- return undefined;
121
- return argv[idx + 1];
122
- }
123
- function parseInputJson(raw) {
124
- if (!raw)
125
- return {};
126
- const parsed = JSON.parse(raw);
127
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
128
- throw new Error('--input-json must parse to a JSON object');
129
- }
130
- return parsed;
131
- }
132
- function parsePositiveIntegerFlag(argv, flag) {
133
- const raw = readFlag(argv, flag);
134
- if (raw === undefined)
135
- return undefined;
136
- const parsed = Number(raw);
137
- if (!Number.isInteger(parsed) || parsed <= 0) {
138
- throw new Error(`${flag} must be a positive integer`);
139
- }
140
- return parsed;
141
- }
142
39
  async function init() {
143
40
  console.error('Wire Node -- Initializing...');
144
41
  const config = loadConfig();
@@ -146,37 +43,38 @@ async function init() {
146
43
  const tokenIdx = args.indexOf('--token');
147
44
  if (tokenIdx !== -1 && args[tokenIdx + 1]) {
148
45
  config.apiToken = args[tokenIdx + 1];
46
+ delete config.apiTokenFile;
149
47
  }
150
48
  if (!config.apiToken) {
151
49
  console.error('No API token configured.');
152
- console.error(' Usage: agent-wire-terminal init --token YOUR_TOKEN');
50
+ console.error(' Usage: npx -y @agent-wire/terminal init --token YOUR_TOKEN');
153
51
  process.exit(1);
154
52
  }
155
53
  const api = new WireAPI(config);
156
54
  try {
157
- const node = await api.registerNode(config.nodeName, config.capabilities);
158
- config.nodeId = node.node_id;
55
+ const resumed = await resumeToken(api, config.apiToken);
159
56
  saveConfig(config);
160
- console.error(`Node registered: ${node.node_id}`);
57
+ console.error(`Agent resumed: ${resumed.name} (${resumed.identity.pseudoId})`);
161
58
  console.error(` Name: ${config.nodeName}`);
162
59
  console.error(` Capabilities: ${config.capabilities.join(', ')}`);
163
- console.error(` Status: ${node.status}`);
164
- console.error('\n Run "agent-wire-terminal start" to begin earning credits.');
60
+ console.error(` Status: ${resumed.identity.verificationStatus}`);
61
+ console.error('\n Run "npx -y @agent-wire/terminal serve" to use this agent over MCP.');
165
62
  }
166
63
  catch (err) {
167
- console.error('Registration failed:', err.message);
64
+ console.error('Resume failed:', err.message);
168
65
  process.exit(1);
169
66
  }
170
67
  }
171
68
  async function start() {
172
69
  const config = loadConfig();
173
70
  if (!config.apiToken) {
174
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
71
+ console.error('No API token. Run "npx -y @agent-wire/terminal init --token YOUR_TOKEN" first.');
175
72
  process.exit(1);
176
73
  }
177
74
  if (!config.nodeId) {
178
- console.error('Node not registered. Run "agent-wire-terminal init" first.');
179
- process.exit(1);
75
+ const node = await new WireAPI(config).registerNode(config.nodeName, config.capabilities);
76
+ config.nodeId = node.node_id;
77
+ saveConfig(config);
180
78
  }
181
79
  // One node per machine — acquire PID lock
182
80
  const existingPid = isWorkerRunning();
@@ -231,845 +129,48 @@ async function serve() {
231
129
  port,
232
130
  });
233
131
  }
234
- async function balance() {
235
- const config = loadConfig();
236
- if (!config.apiToken) {
237
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
238
- process.exit(1);
239
- }
240
- const api = new WireAPI(config);
241
- try {
242
- const result = await api.getBalance();
243
- console.log('Wire Node -- Balance');
244
- console.log('');
245
- // Credits summary (Pillar 15 — operator pool is the sole source of truth)
246
- const rep = result.reputation;
247
- const creditsBalance = rep?.pool_balance;
248
- const totalEarned = rep?.total_credits_earned;
249
- const jobsCompleted = rep?.jobs_completed;
250
- if (creditsBalance !== undefined) {
251
- const wireTake = totalEarned !== undefined
252
- ? Math.round(totalEarned * 0.025)
253
- : undefined;
254
- const earnedStr = totalEarned !== undefined ? ` (earned: ${totalEarned.toLocaleString()}` : '';
255
- const takeStr = wireTake !== undefined ? ` | wire take: ${wireTake.toLocaleString()})` : '';
256
- console.log(` Credits: ${creditsBalance.toLocaleString()}${earnedStr}${takeStr}`);
257
- }
258
- else {
259
- console.log(' Credits: unable to retrieve (check your token with `agent-wire-terminal status`)');
260
- }
261
- if (jobsCompleted !== undefined) {
262
- console.log(` Jobs completed: ${jobsCompleted.toLocaleString()}`);
263
- }
264
- // Reputation
265
- const domains = rep?.domains;
266
- if (domains && domains.length > 0) {
267
- const topScore = domains[0].score;
268
- console.log(` Reputation: ${topScore}`);
269
- console.log('');
270
- console.log(' Domains:');
271
- for (const d of domains) {
272
- console.log(` ${d.domain}: ${d.score} (${d.contribution_count} contributions)`);
273
- }
274
- }
275
- // Work stats (from node polling, if available)
276
- if (result.work_stats) {
277
- console.log('');
278
- console.log(' Work stats:');
279
- console.log(` ${JSON.stringify(result.work_stats, null, 2).replace(/\n/g, '\n ')}`);
280
- }
281
- if (!rep && !result.work_stats) {
282
- console.log(' No data available. Your account may be new or the API may be unreachable.');
283
- console.log(' Try: agent-wire-terminal status (verify config)');
284
- }
285
- }
286
- catch (err) {
287
- console.error('Error: Could not reach balance endpoint');
288
- console.error(` ${err.message}`);
289
- console.error(' Try: Check your token with `agent-wire-terminal status`');
290
- process.exit(1);
291
- }
292
- }
293
- function status() {
294
- const config = loadConfig();
295
- console.error('Wire Node -- Status');
296
- console.error(` API URL: ${config.apiUrl}`);
297
- console.error(` Token: ${config.apiToken ? config.apiToken.slice(0, 15) + '...' : 'NOT SET'}`);
298
- console.error(` Node ID: ${config.nodeId || 'NOT REGISTERED'}`);
299
- console.error(` Name: ${config.nodeName}`);
300
- console.error(` Capabilities: ${config.capabilities.join(', ')}`);
301
- console.error(` Cache size: ${config.cacheSizeMb}MB`);
302
- }
303
- // ── Sync helpers ──────────────────────────────────────────────
304
- function getArgValue(flag) {
305
- const idx = args.indexOf(flag);
306
- if (idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith('--')) {
307
- return args[idx + 1];
308
- }
309
- return undefined;
310
- }
311
- function hasFlag(flag) {
312
- return args.includes(flag);
313
- }
314
- function readMarketNativeDocsIngestFlag() {
315
- const raw = getArgValue('--market-native-docs-ingest') ??
316
- getArgValue('--market-native-ingest') ??
317
- getArgValue('--market-ingest');
318
- if (!raw)
319
- return 'off';
320
- if (raw === 'off' || raw === 'auto' || raw === 'all')
321
- return raw;
322
- console.error(`Error: --market-native-docs-ingest must be one of: off, auto, all (got "${raw}")`);
323
- process.exit(1);
324
- }
325
- function isMarketNativeDocsIngestEnabled(mode) {
326
- return mode !== 'off';
327
- }
328
- function loadManifestFromDisk(syncDir) {
329
- const manifestPath = join(resolve(syncDir), '.wire-sync.json');
330
- if (!existsSync(manifestPath)) {
331
- return null;
332
- }
333
- try {
334
- const raw = readFileSync(manifestPath, 'utf-8');
335
- return parseManifest(raw);
336
- }
337
- catch {
338
- return null;
339
- }
340
- }
341
- function saveManifestToDisk(syncDir, manifest) {
342
- const manifestPath = join(resolve(syncDir), '.wire-sync.json');
343
- writeFileSync(manifestPath, serializeManifest(manifest), 'utf-8');
344
- }
345
- async function promptConfirm(message) {
346
- const rl = createInterface({ input: process.stdin, output: process.stderr });
347
- return new Promise((resolvePromise) => {
348
- rl.question(`${message} [y/N] `, (answer) => {
349
- rl.close();
350
- resolvePromise(answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes');
351
- });
352
- });
353
- }
354
- function buildPreviewOutput(corpus, dir, diff) {
355
- return {
356
- corpus_slug: corpus,
357
- local_dir: dir,
358
- diff,
359
- summary: {
360
- push_new: diff.push_new.length,
361
- push_update: diff.push_update.length,
362
- pull_new: diff.pull_new.length,
363
- pull_update: diff.pull_update.length,
364
- in_sync: diff.in_sync.length,
365
- conflicts: diff.conflicts.length,
366
- },
367
- };
368
- }
369
- async function syncCommand() {
370
- const dir = getArgValue('--dir');
371
- const corpus = getArgValue('--corpus');
372
- const action = getArgValue('--action');
373
- const watchMode = hasFlag('--watch');
374
- const publish = hasFlag('--publish');
375
- const autoYes = hasFlag('--yes');
376
- const marketNativeDocsIngest = readMarketNativeDocsIngestFlag();
377
- if (!dir) {
378
- console.error('Error: --dir is required.');
379
- console.error(' Usage: agent-wire-terminal sync --dir PATH --corpus SLUG --action diff|push|pull|preview');
380
- process.exit(1);
381
- }
382
- if (!corpus) {
383
- console.error('Error: --corpus is required.');
384
- console.error(' Usage: agent-wire-terminal sync --dir PATH --corpus SLUG --action diff|push|pull|preview');
385
- process.exit(1);
386
- }
387
- const validActions = ['diff', 'push', 'pull', 'preview'];
388
- if (!action || !validActions.includes(action)) {
389
- console.error(`Error: --action must be one of: ${validActions.join(', ')}`);
390
- console.error(' Usage: agent-wire-terminal sync --dir PATH --corpus SLUG --action diff|push|pull|preview');
391
- process.exit(1);
392
- }
393
- if (watchMode && action !== 'push') {
394
- console.error('Error: --watch is only supported with --action push');
395
- process.exit(1);
396
- }
397
- if (isMarketNativeDocsIngestEnabled(marketNativeDocsIngest) && action === 'pull') {
398
- console.error('Error: --market-native-docs-ingest only applies to push-side sync.');
399
- process.exit(1);
400
- }
401
- const resolvedDir = resolve(dir);
402
- if (!existsSync(resolvedDir)) {
403
- console.error(`Error: Directory does not exist: ${resolvedDir}`);
404
- process.exit(1);
405
- }
406
- const config = loadConfig();
407
- if (!config.apiToken) {
408
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
409
- process.exit(1);
410
- }
411
- const api = new WireAPI(config);
412
- // Run the sync action
413
- async function runSync() {
414
- console.error(`Wire Corpus Sync -- ${action}`);
415
- console.error(` Directory: ${resolvedDir}`);
416
- console.error(` Corpus: ${corpus}`);
417
- if (isMarketNativeDocsIngestEnabled(marketNativeDocsIngest)) {
418
- console.error(` Market-native docs ingest: ${marketNativeDocsIngest}`);
419
- if (publish) {
420
- console.error(' Note: /wire/sync publishes source docs; --publish is already implied.');
421
- }
422
- }
423
- console.error('');
424
- // 1. Walk local directory
425
- const localFiles = await walkDirectory(resolvedDir);
426
- console.error(` Found ${localFiles.size} local file(s)`);
427
- // 2. Load manifest
428
- const manifest = loadManifestFromDisk(resolvedDir);
429
- if (manifest) {
430
- console.error(` Manifest loaded (last sync: ${manifest.last_sync})`);
431
- }
432
- else {
433
- console.error(' No previous manifest -- first sync');
434
- }
435
- // 3. List remote documents
436
- const remoteDocs = await api.listDocumentsAll(corpus);
437
- console.error(` Found ${remoteDocs.length} remote document(s)`);
438
- console.error('');
439
- // 4. Compute diff
440
- const diff = await computeDiff(localFiles, remoteDocs, manifest);
441
- const previewOutput = buildPreviewOutput(corpus, resolvedDir, diff);
442
- // Handle conflicts -- list and skip
443
- if (diff.conflicts.length > 0) {
444
- const resolutions = new Map();
445
- for (const c of diff.conflicts) {
446
- resolutions.set(c.relativePath, 'skip');
447
- }
448
- const resolved = resolveConflicts(diff.conflicts, resolutions);
449
- if (resolved.skipped.length > 0) {
450
- console.error(` Conflicts (${resolved.skipped.length} skipped):`);
451
- for (const entry of resolved.skipped) {
452
- console.error(` - ${entry.relativePath}`);
453
- for (const w of entry.warnings) {
454
- console.error(` Warning: ${w}`);
455
- }
456
- }
457
- console.error('');
458
- }
459
- }
460
- // 5. Execute action
461
- if (action === 'preview' || action === 'diff') {
462
- console.log(generatePreview(previewOutput));
463
- return;
464
- }
465
- if (action === 'push') {
466
- const pushEntries = [...diff.push_new, ...diff.push_update];
467
- if (pushEntries.length === 0) {
468
- console.error(' Nothing to push -- all files are in sync.');
469
- return;
470
- }
471
- // Show preview
472
- console.log(generatePreview(previewOutput));
473
- // Confirm unless --yes
474
- if (!autoYes) {
475
- const confirmed = await promptConfirm(`\nPush ${pushEntries.length} file(s) to Wire corpus "${corpus}"?`);
476
- if (!confirmed) {
477
- console.error(' Aborted.');
478
- return;
479
- }
480
- }
481
- console.error(`\n Pushing ${pushEntries.length} file(s)...`);
482
- const results = await pushFiles(api, corpus, pushEntries, {
483
- publish,
484
- marketNativeDocsIngest,
485
- });
486
- // Report results
487
- let successCount = 0;
488
- let failCount = 0;
489
- for (const r of results) {
490
- if (r.success) {
491
- successCount++;
492
- console.error(` OK: ${r.relativePath} -> ${r.documentId}`);
493
- for (const warning of r.warnings || []) {
494
- console.error(` WARN: ${warning}`);
495
- }
496
- const marketResult = r.marketNativeDocsIngest;
497
- if (marketResult?.window_count && marketResult.window_count > 1) {
498
- console.error(` Market windows: ${marketResult.dispatched_windows ?? 0}/${marketResult.window_count} dispatched`);
499
- }
500
- if (marketResult?.chain_result_handle_path) {
501
- console.error(` Market result: ${marketResult.chain_result_handle_path}`);
502
- }
503
- else if (marketResult?.chain_invocation_id) {
504
- console.error(` Market invocation: ${marketResult.chain_invocation_id}`);
505
- }
506
- }
507
- else {
508
- failCount++;
509
- console.error(` FAIL: ${r.relativePath} -- ${r.error}`);
510
- }
511
- }
512
- console.error(`\n Push complete: ${successCount} succeeded, ${failCount} failed.`);
513
- // PATCH source_path for in-sync documents missing it on the server
514
- // This ensures round-trip fidelity: documents uploaded before source_path
515
- // existed get their folder metadata populated without creating new versions.
516
- let metadataPatched = 0;
517
- for (const entry of diff.in_sync) {
518
- const remoteSourcePath = entry.remoteDoc?.source_path;
519
- const localPath = entry.relativePath;
520
- if (entry.remoteDoc && localPath && (!remoteSourcePath || remoteSourcePath !== localPath)) {
521
- try {
522
- await api.updateDocumentSourcePath(entry.remoteDoc.id, localPath);
523
- metadataPatched++;
524
- }
525
- catch (err) {
526
- console.error(` WARN: Failed to patch source_path for ${localPath}: ${err.message}`);
527
- }
528
- }
529
- }
530
- if (metadataPatched > 0) {
531
- console.error(` Patched source_path on ${metadataPatched} in-sync document(s).`);
532
- }
533
- // Update manifest for successful pushes
534
- if (successCount > 0) {
535
- const currentManifest = manifest || {
536
- corpus_slug: corpus,
537
- corpus_id: corpus, // Will be refined on next sync
538
- last_sync: new Date().toISOString(),
539
- files: {},
540
- };
541
- const manifestEntries = results
542
- .filter(r => r.success)
543
- .map(r => {
544
- const entry = pushEntries.find(e => e.relativePath === r.relativePath);
545
- return {
546
- relativePath: r.relativePath,
547
- documentId: r.documentId,
548
- localHash: entry.localFile?.hash || '',
549
- remoteHash: entry.localFile?.hash || '', // After push, remote matches local
550
- remoteStatus: (publish || isMarketNativeDocsIngestEnabled(marketNativeDocsIngest) ? 'published' : 'draft'),
551
- remoteAnchored: false,
552
- remoteVersionNumber: r.version ?? (entry.remoteDoc?.version_number ? entry.remoteDoc.version_number + 1 : 1),
553
- remoteWordCount: entry.localFile?.content.split(/\s+/).length || 0,
554
- };
555
- });
556
- const updated = updateManifest(currentManifest, manifestEntries);
557
- saveManifestToDisk(resolvedDir, updated);
558
- console.error(' Manifest updated.');
559
- }
560
- return;
561
- }
562
- if (action === 'pull') {
563
- const pullEntries = [...diff.pull_new, ...diff.pull_update];
564
- if (pullEntries.length === 0) {
565
- console.error(' Nothing to pull -- all files are in sync.');
566
- return;
567
- }
568
- // Show preview
569
- console.log(generatePreview(previewOutput));
570
- // Confirm unless --yes
571
- if (!autoYes) {
572
- const confirmed = await promptConfirm(`\nPull ${pullEntries.length} file(s) from Wire corpus "${corpus}"?`);
573
- if (!confirmed) {
574
- console.error(' Aborted.');
575
- return;
576
- }
577
- }
578
- console.error(`\n Pulling ${pullEntries.length} file(s)...`);
579
- const results = await pullFiles(api, resolvedDir, pullEntries);
580
- // Report results
581
- let successCount = 0;
582
- let failCount = 0;
583
- for (const r of results) {
584
- if (r.success) {
585
- successCount++;
586
- console.error(` OK: ${r.relativePath}`);
587
- }
588
- else {
589
- failCount++;
590
- console.error(` FAIL: ${r.relativePath} -- ${r.error}`);
591
- }
592
- }
593
- console.error(`\n Pull complete: ${successCount} succeeded, ${failCount} failed.`);
594
- // Update manifest for successful pulls
595
- if (successCount > 0) {
596
- const currentManifest = manifest || {
597
- corpus_slug: corpus,
598
- corpus_id: corpus,
599
- last_sync: new Date().toISOString(),
600
- files: {},
601
- };
602
- // Re-walk to get hashes of pulled files
603
- const updatedLocalFiles = await walkDirectory(resolvedDir);
604
- const manifestEntries = results
605
- .filter(r => r.success)
606
- .map(r => {
607
- const entry = pullEntries.find(e => e.relativePath === r.relativePath);
608
- const localFile = updatedLocalFiles.get(r.relativePath);
609
- return {
610
- relativePath: r.relativePath,
611
- documentId: entry.remoteDoc?.id || '',
612
- localHash: localFile?.hash || '',
613
- remoteHash: entry.remoteDoc?.body_hash || '',
614
- remoteStatus: (entry.remoteDoc?.status || 'draft'),
615
- remoteAnchored: entry.remoteDoc?.anchored || false,
616
- remoteVersionNumber: entry.remoteDoc?.version_number || 1,
617
- remoteWordCount: entry.remoteDoc?.word_count || 0,
618
- };
619
- });
620
- const updated = updateManifest(currentManifest, manifestEntries);
621
- saveManifestToDisk(resolvedDir, updated);
622
- console.error(' Manifest updated.');
623
- }
624
- return;
625
- }
626
- }
627
- // Execute the sync
628
- await runSync();
629
- // Watch mode: re-run on file changes with 2-second debounce
630
- if (watchMode) {
631
- console.error('\n Watching for changes (2s debounce)... Press Ctrl+C to stop.\n');
632
- let debounceTimer = null;
633
- let syncing = false;
634
- const watcher = fsWatch(resolvedDir, { recursive: true }, (_event, filename) => {
635
- // Skip manifest file changes
636
- if (filename && filename.toString().includes('.wire-sync.json'))
637
- return;
638
- if (debounceTimer)
639
- clearTimeout(debounceTimer);
640
- debounceTimer = setTimeout(async () => {
641
- if (syncing)
642
- return;
643
- syncing = true;
644
- console.error(`\n Change detected${filename ? `: ${filename}` : ''}. Syncing...`);
645
- try {
646
- await runSync();
647
- }
648
- catch (err) {
649
- console.error(` Sync error: ${err.message}`);
650
- }
651
- syncing = false;
652
- }, 2000);
653
- });
654
- // Handle graceful shutdown
655
- process.on('SIGINT', () => {
656
- console.error('\n Stopping watch...');
657
- watcher.close();
658
- if (debounceTimer)
659
- clearTimeout(debounceTimer);
660
- process.exit(0);
661
- });
662
- process.on('SIGTERM', () => {
663
- watcher.close();
664
- if (debounceTimer)
665
- clearTimeout(debounceTimer);
666
- process.exit(0);
667
- });
668
- // Keep the process alive
669
- await new Promise(() => { });
670
- }
671
- }
672
- async function pullCommand() {
673
- const manifestPath = getArgValue('--manifest');
674
- const init = hasFlag('--init');
675
- const dryRun = hasFlag('--dry-run');
676
- const json = hasFlag('--json');
677
- if (init) {
678
- const path = await writeDefaultLocalPullManifest(manifestPath);
679
- if (!json)
680
- console.error(`Initialized local-sync manifest: ${path}`);
681
- }
682
- const config = loadConfig();
683
- if (!config.apiToken) {
684
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
685
- process.exit(1);
686
- }
687
- const api = new WireAPI(config);
688
- const report = await pullLocalSubscriptions(api, { manifestPath, dryRun });
689
- console.log(json ? JSON.stringify(report, null, 2) : formatLocalPullReport(report));
690
- if (report.failed > 0)
691
- process.exit(1);
692
- }
693
132
  async function waitCommand() {
694
133
  const exitCode = await runWaitCommand(args.slice(1));
695
134
  process.exit(exitCode);
696
135
  }
697
- async function chainCommand() {
698
- const subcommand = args[1];
699
- const commandArgs = args.slice(2);
700
- if (subcommand !== 'run' && subcommand !== 'poll') {
701
- printChainUsage();
702
- process.exit(1);
703
- }
704
- const config = loadConfig();
705
- if (!config.apiToken) {
706
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
707
- process.exit(1);
708
- }
709
- const chain = readFlag(commandArgs, '--chain');
710
- if (!chain) {
711
- console.error('Error: --chain is required');
712
- printChainUsage();
713
- process.exit(1);
714
- }
715
- const api = new WireAPI(config);
716
- if (subcommand === 'poll') {
717
- const runHandlePath = readFlag(commandArgs, '--run-handle');
718
- const runId = readFlag(commandArgs, '--run-id');
719
- if (!runHandlePath && !runId) {
720
- console.error('Error: --run-handle or --run-id is required for chain poll');
721
- printChainUsage();
722
- process.exit(1);
723
- }
724
- const result = await api.pollChainRun({
725
- run_handle_path: runHandlePath,
726
- run_id: runId,
727
- chain,
728
- include_steps: commandArgs.includes('--include-steps'),
729
- });
730
- console.log(JSON.stringify(result, null, 2));
731
- return;
732
- }
733
- const quoteId = readFlag(commandArgs, '--quote-id');
734
- const quoteMode = commandArgs.includes('--quote');
735
- const autoMode = commandArgs.includes('--auto');
736
- if (quoteMode && autoMode) {
737
- console.error('Error: --quote and --auto are mutually exclusive');
738
- printChainUsage();
739
- process.exit(1);
740
- }
741
- if (autoMode && quoteId) {
742
- console.error('Error: --auto does not accept --quote-id');
743
- printChainUsage();
744
- process.exit(1);
745
- }
746
- const mode = autoMode ? 'auto' : quoteMode ? 'quote' : 'trusted';
747
- if (mode === 'trusted' && !quoteId) {
748
- console.error('Error: trusted chain execution requires --quote-id');
749
- printChainUsage();
750
- process.exit(1);
751
- }
752
- const maxCredits = parsePositiveIntegerFlag(commandArgs, '--max-credits');
753
- if (mode === 'auto' && !maxCredits) {
754
- console.error('Error: --auto requires --max-credits');
755
- printChainUsage();
756
- process.exit(1);
757
- }
758
- const entryMode = readFlag(commandArgs, '--entry-mode') ?? 'direct';
759
- if (entryMode !== 'direct' && entryMode !== 'start') {
760
- console.error('Error: --entry-mode must be direct or start');
761
- process.exit(1);
762
- }
763
- const timeoutMs = parsePositiveIntegerFlag(commandArgs, '--timeout-ms');
764
- const result = await api.runChain({
765
- chain,
766
- mode,
767
- input: parseInputJson(readFlag(commandArgs, '--input-json')),
768
- quote_id: quoteId,
769
- max_credits: mode === 'auto' ? maxCredits : undefined,
770
- chain_id: readFlag(commandArgs, '--chain-id'),
771
- entry_mode: entryMode,
772
- include_steps: commandArgs.includes('--include-steps'),
773
- async_ack: mode === 'trusted' || mode === 'auto' ? commandArgs.includes('--async-ack') : undefined,
774
- timeout_ms: mode === 'trusted' || mode === 'auto' ? timeoutMs : undefined,
775
- });
776
- console.log(JSON.stringify(result, null, 2));
777
- }
778
- function surfaceHolsterPath(commandArgs) {
779
- return resolve(readFlag(commandArgs, '--holster') || join(CONFIG_DIR, 'surface-shortcuts.json'));
780
- }
781
- function firstSurfacePositional(commandArgs) {
782
- const valueFlags = new Set(['--chain-id', '--entry-mode', '--holster', '--input-json', '--quote-id', '--timeout-ms', '--max-credits']);
783
- for (let i = 0; i < commandArgs.length; i += 1) {
784
- const arg = commandArgs[i];
785
- if (valueFlags.has(arg)) {
786
- i += 1;
787
- continue;
788
- }
789
- if (arg.startsWith('--')) {
790
- continue;
791
- }
792
- return arg;
793
- }
794
- return undefined;
795
- }
796
- function readSurfaceHolster(path) {
797
- if (!existsSync(path)) {
798
- throw new Error(`Surface holster not found: ${path}. Run "agent-wire-terminal s init" to create one.`);
799
- }
800
- const parsed = JSON.parse(readFileSync(path, 'utf-8'));
801
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
802
- throw new Error('Surface holster must be a JSON object');
803
- }
804
- if (parsed.shortcuts != null && (typeof parsed.shortcuts !== 'object' || Array.isArray(parsed.shortcuts))) {
805
- throw new Error('Surface holster shortcuts must be an object');
806
- }
807
- return parsed;
808
- }
809
- function validateSurfaceShortcut(name, shortcut) {
810
- if (!shortcut || typeof shortcut !== 'object' || Array.isArray(shortcut)) {
811
- throw new Error(`Shortcut "${name}" is not defined`);
812
- }
813
- if (typeof shortcut.chain !== 'string' || shortcut.chain.trim().length === 0) {
814
- throw new Error(`Shortcut "${name}" must declare a non-empty chain`);
815
- }
816
- if (shortcut.input != null && (typeof shortcut.input !== 'object' || Array.isArray(shortcut.input))) {
817
- throw new Error(`Shortcut "${name}" input must be a JSON object`);
818
- }
819
- if (shortcut.entry_mode != null && shortcut.entry_mode !== 'direct' && shortcut.entry_mode !== 'start') {
820
- throw new Error(`Shortcut "${name}" entry_mode must be direct or start`);
821
- }
822
- return shortcut;
823
- }
824
- function initSurfaceHolster(path) {
825
- if (existsSync(path)) {
826
- console.error(`Surface holster already exists: ${path}`);
827
- return;
828
- }
829
- const example = {
830
- shortcuts: {
831
- canary: {
832
- chain: '/default/optimal-kit/canary',
833
- entry_mode: 'direct',
834
- },
835
- },
836
- };
837
- mkdirSync(resolve(path, '..'), { recursive: true });
838
- writeFileSync(path, JSON.stringify(example, null, 2), { mode: 0o600 });
839
- console.error(`Initialized surface holster: ${path}`);
840
- console.error('Seeded canary requires --input-json with battery_ref, test_run_id, subject_agent, and source_principal.');
841
- console.error('source_principal and subject_agent must be different.');
842
- }
843
- async function surfaceCommand() {
844
- const commandArgs = args.slice(1);
845
- const subcommand = firstSurfacePositional(commandArgs) || 'list';
846
- const holsterPath = surfaceHolsterPath(commandArgs);
847
- if (subcommand === 'init') {
848
- initSurfaceHolster(holsterPath);
849
- return;
850
- }
851
- const holster = readSurfaceHolster(holsterPath);
852
- const shortcuts = holster.shortcuts || {};
853
- if (subcommand === 'list') {
854
- const names = Object.keys(shortcuts).sort();
855
- if (names.length === 0) {
856
- console.log(JSON.stringify({ holster: holsterPath, shortcuts: [] }, null, 2));
857
- return;
858
- }
859
- console.log(JSON.stringify({
860
- holster: holsterPath,
861
- shortcuts: names.map((name) => {
862
- const shortcut = validateSurfaceShortcut(name, shortcuts[name]);
863
- return { name, chain: shortcut.chain, entry_mode: shortcut.entry_mode || 'direct' };
864
- }),
865
- }, null, 2));
866
- return;
867
- }
868
- const shortcut = validateSurfaceShortcut(subcommand, shortcuts[subcommand]);
869
- const quoteId = readFlag(commandArgs, '--quote-id');
870
- const autoMode = commandArgs.includes('--auto');
871
- if (commandArgs.includes('--quote') && autoMode) {
872
- console.error('Error: --quote and --auto are mutually exclusive');
873
- printSurfaceUsage();
874
- process.exit(1);
875
- }
876
- if (autoMode && quoteId) {
877
- console.error('Error: --auto does not accept --quote-id');
878
- printSurfaceUsage();
879
- process.exit(1);
880
- }
881
- const quoteMode = !autoMode && (commandArgs.includes('--quote') || !quoteId);
882
- const maxCredits = parsePositiveIntegerFlag(commandArgs, '--max-credits');
883
- if (autoMode && !maxCredits) {
884
- console.error('Error: --auto requires --max-credits');
885
- printSurfaceUsage();
886
- process.exit(1);
887
- }
888
- const entryMode = readFlag(commandArgs, '--entry-mode') ?? shortcut.entry_mode ?? 'direct';
889
- if (entryMode !== 'direct' && entryMode !== 'start') {
890
- console.error('Error: --entry-mode must be direct or start');
891
- process.exit(1);
892
- }
893
- const config = loadConfig();
894
- if (!config.apiToken) {
895
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
896
- process.exit(1);
897
- }
898
- const api = new WireAPI(config);
899
- const timeoutMs = parsePositiveIntegerFlag(commandArgs, '--timeout-ms');
900
- const input = {
901
- ...(shortcut.input || {}),
902
- ...parseInputJson(readFlag(commandArgs, '--input-json')),
903
- };
904
- const result = await api.runChain({
905
- chain: shortcut.chain,
906
- mode: autoMode ? 'auto' : quoteMode ? 'quote' : 'trusted',
907
- input,
908
- quote_id: quoteId,
909
- max_credits: autoMode ? maxCredits : undefined,
910
- chain_id: readFlag(commandArgs, '--chain-id'),
911
- entry_mode: entryMode,
912
- include_steps: commandArgs.includes('--include-steps'),
913
- async_ack: quoteMode ? undefined : commandArgs.includes('--async-ack'),
914
- timeout_ms: quoteMode ? undefined : timeoutMs,
915
- });
916
- console.log(JSON.stringify(result, null, 2));
917
- }
918
136
  function printMainUsage() {
919
- console.error('agent-wire-terminal - The Wire is a machine intelligence exchange.');
920
- console.error('Run a node to earn credits. Connect via MCP to query and contribute intelligence.');
921
- console.error('');
922
- console.error('Usage: agent-wire-terminal <command>');
923
- console.error('');
924
- console.error('Commands:');
925
- console.error(' serve [options] Start MCP server. Defaults to stdio transport.');
926
- console.error(' --http Use HTTP transport instead of stdio');
927
- console.error(' --port PORT HTTP port (default: 3200)');
928
- console.error(' --no-worker Skip background work loop');
929
- console.error(' Auto-detects standalone daemon and skips background work.');
930
- console.error(' start Run standalone node daemon. Acquires a PID lock (one per');
931
- console.error(' machine). Polls for mechanical work and earns credits.');
932
- console.error(' init [--token TOKEN] Register this node with the Wire network. Requires an API');
933
- console.error(' token from /api/v1/register or WIRE_API_TOKEN env var.');
934
- console.error(' balance Check your operator pool credits, reputation, and jobs.');
935
- console.error(' status Show current config: API URL, token, node ID, capabilities.');
936
- console.error(' wait [options] Block on Wire coordination events over SSE and print JSON.');
937
- console.error(" --triggers LIST Comma-separated triggers, e.g. 'board.*'");
938
- console.error(' --cursor CURSOR Resume/replay from an opaque cursor');
939
- console.error(' --filter k=v Repeatable AND filter');
940
- console.error(' --timeout-seconds SECONDS (default 600, max 86400; -1 = park indefinitely)');
941
- console.error(' --limit N Matching events to print (default: 1)');
942
- console.error(' --name NAME Cached identity override');
943
- console.error(' chain run [options] Quote or execute a canonical Wire chain.');
944
- console.error(' --chain HANDLE_OR_UUID --input-json JSON --quote');
945
- console.error(' --quote-id TOKEN [--async-ack|--timeout-ms MS]');
946
- console.error(' poll async runs with:');
947
- console.error(' --chain HANDLE_OR_UUID --run-handle HANDLE [--include-steps]');
948
- console.error(' s [options] Resolve local holster shortcuts to canonical chain runs.');
949
- console.error(' surface [options] Alias for s.');
950
- console.error(' agent-wire-terminal s SHORTCUT --input-json JSON --quote');
951
- console.error(' trusted sync defaults to --timeout-ms 600000 (max 1800000)');
952
- console.error(' sync [options] Sync local directory with a Wire corpus.');
953
- console.error(' --dir PATH Local directory to sync (required)');
954
- console.error(' --corpus SLUG Wire corpus slug (required)');
955
- console.error(' --action ACTION diff|push|pull|preview (required)');
956
- console.error(' --watch Watch for changes, auto-push (push only)');
957
- console.error(' --publish Publish documents on push (default: draft)');
958
- console.error(' --market-native-docs-ingest MODE');
959
- console.error(' off|auto|all; auto routes missing');
960
- console.error(' rear-matter or oversized docs');
961
- console.error(' oversized docs use 8000/2000 windows');
962
- console.error(' --yes Skip confirmation prompts');
963
- console.error(' pull [options] Pull subscribed Wire contribution bodies into local');
964
- console.error(' cache/skill files from ~/.wire-node/sync-manifest.json.');
965
- console.error('');
966
- console.error('Quick start (MCP):');
967
- console.error(' Stdio (Cursor, Claude Desktop):');
968
- console.error(' "command": "npx", "args": ["-y", "agent-wire-terminal", "serve"]');
969
- console.error(' HTTP (Antigravity, web agents):');
970
- console.error(' WIRE_API_TOKEN=gne_live_... npx agent-wire-terminal serve --http');
971
- console.error(' Then add: "wire": { "url": "http://localhost:3200/" }');
972
- console.error('');
973
- console.error('Quick start (standalone):');
974
- console.error(' WIRE_API_TOKEN=gne_live_... npx agent-wire-terminal init');
975
- console.error(' npx agent-wire-terminal start');
976
- console.error('');
977
- console.error('Quick start (sync):');
978
- console.error(' agent-wire-terminal sync --dir ./my-docs --corpus my-corpus --action preview');
979
- console.error(' agent-wire-terminal sync --dir ./my-docs --corpus my-corpus --action push --yes');
980
- console.error(' agent-wire-terminal sync --dir ./my-docs --corpus my-corpus --action push --market-native-docs-ingest auto --yes');
981
- console.error(' agent-wire-terminal sync --dir ./my-docs --corpus my-corpus --action push --watch');
982
- console.error(' agent-wire-terminal pull --init');
983
- console.error(' agent-wire-terminal pull');
984
- console.error('');
985
- console.error('Docs: https://agent-wire.com/docs');
986
- }
987
- // Route commands
988
- switch (command) {
989
- case 'init':
990
- if (commandHelpRequested) {
991
- printInitUsage();
992
- break;
993
- }
994
- init().catch(console.error);
995
- break;
996
- case 'start':
997
- if (commandHelpRequested) {
998
- printStartUsage();
999
- break;
1000
- }
1001
- start().catch(console.error);
1002
- break;
1003
- case 'serve':
1004
- if (commandHelpRequested) {
1005
- printServeUsage();
1006
- break;
1007
- }
1008
- serve().catch(console.error);
1009
- break;
1010
- case 'balance':
1011
- if (commandHelpRequested) {
1012
- printBalanceUsage();
1013
- break;
1014
- }
1015
- balance().catch(console.error);
1016
- break;
1017
- case 'status':
1018
- if (commandHelpRequested) {
1019
- printStatusUsage();
1020
- break;
1021
- }
1022
- status();
1023
- break;
1024
- case 'sync':
1025
- if (commandHelpRequested) {
1026
- printSyncUsage();
1027
- break;
1028
- }
1029
- syncCommand().catch(console.error);
1030
- break;
1031
- case 'pull':
1032
- if (commandHelpRequested) {
1033
- printPullUsage();
1034
- break;
1035
- }
1036
- pullCommand().catch((err) => {
1037
- console.error(err);
1038
- process.exit(2);
1039
- });
1040
- break;
1041
- case 'wait':
1042
- waitCommand().catch((err) => {
1043
- console.error(err);
1044
- process.exit(2);
1045
- });
1046
- break;
1047
- case 'chain':
1048
- if (commandHelpRequested) {
1049
- printChainUsage();
1050
- break;
1051
- }
1052
- chainCommand().catch((err) => {
1053
- console.error(err);
1054
- process.exit(2);
1055
- });
1056
- break;
1057
- case 's':
1058
- case 'surface':
1059
- if (commandHelpRequested) {
1060
- printSurfaceUsage();
1061
- break;
1062
- }
1063
- surfaceCommand().catch((err) => {
1064
- console.error(err);
1065
- process.exit(2);
1066
- });
1067
- break;
1068
- case '--help':
1069
- case '-h':
1070
- case 'help':
1071
- default:
1072
- printMainUsage();
1073
- break;
137
+ console.log(`Usage: npx -y @agent-wire/terminal <tool> [--arg value]
138
+
139
+ Commands:
140
+ init Resume an existing agent (--token TOKEN)
141
+ start Start the local worker daemon
142
+ serve Start the local MCP server (--http --port PORT --no-worker)
143
+ wait Wait for Wire activity (--help for options)
144
+ tools List current graph tools (--json for full definitions)
145
+
146
+ Hub commands are projected from live tool_definition contributions.
147
+ Run npx -y @agent-wire/terminal tools, then npx -y @agent-wire/terminal <tool> --help.
148
+ Use WIRE_API_URL to select the hub. Terminal 1.7.9+: WIRE_API_TOKEN_FILE=/absolute/path/to/token selects the agent.
149
+ WIRE_API_TOKEN is the alternative on every terminal version.
150
+ Token precedence: WIRE_API_TOKEN > WIRE_API_TOKEN_FILE > saved config.
151
+ The token file is UTF-8, trimmed and read once per process; restart after rotation.
152
+ Example: npx -y @agent-wire/terminal wire_help --topic first-hour`);
153
+ }
154
+ async function main() {
155
+ switch (command) {
156
+ case 'init': return commandHelpRequested ? printInitUsage() : init();
157
+ case 'start': return commandHelpRequested ? printStartUsage() : start();
158
+ case 'serve': return commandHelpRequested ? printServeUsage() : serve();
159
+ case 'wait': return waitCommand();
160
+ case 'help':
161
+ case '--help':
162
+ case '-h':
163
+ case undefined: return printMainUsage();
164
+ case 'tools':
165
+ if (commandHelpRequested) {
166
+ console.log('Usage: npx -y @agent-wire/terminal tools [--json]\nList live tool_definition contributions.');
167
+ return;
168
+ }
169
+ }
170
+ await runProjectedCommand(command, args.slice(1));
1074
171
  }
172
+ main().catch((error) => {
173
+ console.error(error instanceof Error ? error.message : String(error));
174
+ process.exitCode = 2;
175
+ });
1075
176
  //# sourceMappingURL=cli.js.map