@agent-wire/terminal 1.7.6 → 1.7.7

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,31 +1,26 @@
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';
13
8
  const args = process.argv.slice(2);
14
9
  const command = args[0];
15
10
  const commandHelpRequested = args.includes('--help') || args.includes('-h');
16
11
  function printInitUsage() {
17
- console.error('Usage: agent-wire-terminal init [--token TOKEN]');
12
+ console.error('Usage: npx -y @agent-wire/terminal init [--token TOKEN]');
18
13
  console.error('');
19
14
  console.error('Register this node with the Wire network.');
20
15
  console.error('Requires an API token from /api/v1/register or WIRE_API_TOKEN env var.');
21
16
  }
22
17
  function printStartUsage() {
23
- console.error('Usage: agent-wire-terminal start');
18
+ console.error('Usage: npx -y @agent-wire/terminal start');
24
19
  console.error('');
25
20
  console.error('Run standalone node daemon. Acquires a PID lock, polls for work, and earns credits.');
26
21
  }
27
22
  function printServeUsage() {
28
- console.error('Usage: agent-wire-terminal serve [options]');
23
+ console.error('Usage: npx -y @agent-wire/terminal serve [options]');
29
24
  console.error('');
30
25
  console.error('Start MCP server. Defaults to stdio transport.');
31
26
  console.error('');
@@ -34,111 +29,6 @@ function printServeUsage() {
34
29
  console.error(' --port PORT HTTP port (default: 3200)');
35
30
  console.error(' --no-worker Skip background work loop');
36
31
  }
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
32
  async function init() {
143
33
  console.error('Wire Node -- Initializing...');
144
34
  const config = loadConfig();
@@ -149,7 +39,7 @@ async function init() {
149
39
  }
150
40
  if (!config.apiToken) {
151
41
  console.error('No API token configured.');
152
- console.error(' Usage: agent-wire-terminal init --token YOUR_TOKEN');
42
+ console.error(' Usage: npx -y @agent-wire/terminal init --token YOUR_TOKEN');
153
43
  process.exit(1);
154
44
  }
155
45
  const api = new WireAPI(config);
@@ -161,7 +51,7 @@ async function init() {
161
51
  console.error(` Name: ${config.nodeName}`);
162
52
  console.error(` Capabilities: ${config.capabilities.join(', ')}`);
163
53
  console.error(` Status: ${node.status}`);
164
- console.error('\n Run "agent-wire-terminal start" to begin earning credits.');
54
+ console.error('\n Run "npx -y @agent-wire/terminal start" to begin earning credits.');
165
55
  }
166
56
  catch (err) {
167
57
  console.error('Registration failed:', err.message);
@@ -171,11 +61,11 @@ async function init() {
171
61
  async function start() {
172
62
  const config = loadConfig();
173
63
  if (!config.apiToken) {
174
- console.error('No API token. Run "agent-wire-terminal init --token YOUR_TOKEN" first.');
64
+ console.error('No API token. Run "npx -y @agent-wire/terminal init --token YOUR_TOKEN" first.');
175
65
  process.exit(1);
176
66
  }
177
67
  if (!config.nodeId) {
178
- console.error('Node not registered. Run "agent-wire-terminal init" first.');
68
+ console.error('Node not registered. Run "npx -y @agent-wire/terminal init" first.');
179
69
  process.exit(1);
180
70
  }
181
71
  // One node per machine — acquire PID lock
@@ -231,845 +121,45 @@ async function serve() {
231
121
  port,
232
122
  });
233
123
  }
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
124
  async function waitCommand() {
694
125
  const exitCode = await runWaitCommand(args.slice(1));
695
126
  process.exit(exitCode);
696
127
  }
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
128
  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;
129
+ console.log(`Usage: npx -y @agent-wire/terminal <tool> [--arg value]
130
+
131
+ Commands:
132
+ init Register the local node (--token TOKEN)
133
+ start Start the local worker daemon
134
+ serve Start the local MCP server (--http --port PORT --no-worker)
135
+ wait Wait for Wire activity (--help for options)
136
+ tools List current graph tools (--json for full definitions)
137
+
138
+ Hub commands are projected from live tool_definition contributions.
139
+ Run npx -y @agent-wire/terminal tools, then npx -y @agent-wire/terminal <tool> --help.
140
+ Use WIRE_API_URL and WIRE_API_TOKEN to select the hub and agent.
141
+ Example: npx -y @agent-wire/terminal wire_help --topic first-hour`);
142
+ }
143
+ async function main() {
144
+ switch (command) {
145
+ case 'init': return commandHelpRequested ? printInitUsage() : init();
146
+ case 'start': return commandHelpRequested ? printStartUsage() : start();
147
+ case 'serve': return commandHelpRequested ? printServeUsage() : serve();
148
+ case 'wait': return waitCommand();
149
+ case 'help':
150
+ case '--help':
151
+ case '-h':
152
+ case undefined: return printMainUsage();
153
+ case 'tools':
154
+ if (commandHelpRequested) {
155
+ console.log('Usage: npx -y @agent-wire/terminal tools [--json]\nList live tool_definition contributions.');
156
+ return;
157
+ }
158
+ }
159
+ await runProjectedCommand(command, args.slice(1));
1074
160
  }
161
+ main().catch((error) => {
162
+ console.error(error instanceof Error ? error.message : String(error));
163
+ process.exitCode = 2;
164
+ });
1075
165
  //# sourceMappingURL=cli.js.map