@cloudpftc/opencode-orchestrator 3.5.15 → 3.6.1

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.
Files changed (55) hide show
  1. package/.opencode/helpers/auto-memory-hook.mjs +104 -0
  2. package/.opencode/helpers/hook-handler.cjs +223 -0
  3. package/.opencode/helpers/intelligence.cjs +197 -0
  4. package/.opencode/helpers/memory.js +83 -0
  5. package/.opencode/helpers/post-commit +16 -0
  6. package/.opencode/helpers/pre-commit +26 -0
  7. package/.opencode/helpers/router.js +66 -0
  8. package/.opencode/helpers/session.js +127 -0
  9. package/.opencode/helpers/statusline.cjs +774 -0
  10. package/.opencode/settings.json +319 -0
  11. package/opencode.json +35 -78
  12. package/package.json +2 -6
  13. package/v3/@claude-flow/cli/README.md +391 -534
  14. package/v3/@claude-flow/cli/dist/src/commands/benchmark.js +2 -2
  15. package/v3/@claude-flow/cli/dist/src/commands/claims.js +1 -1
  16. package/v3/@claude-flow/cli/dist/src/commands/config.js +1 -1
  17. package/v3/@claude-flow/cli/dist/src/commands/daemon.js +3 -3
  18. package/v3/@claude-flow/cli/dist/src/commands/deployment.js +1 -1
  19. package/v3/@claude-flow/cli/dist/src/commands/doctor.js +1 -1
  20. package/v3/@claude-flow/cli/dist/src/commands/embeddings.js +1 -1
  21. package/v3/@claude-flow/cli/dist/src/commands/hooks.js +1 -1
  22. package/v3/@claude-flow/cli/dist/src/commands/init.js +16 -16
  23. package/v3/@claude-flow/cli/dist/src/commands/neural.js +1 -1
  24. package/v3/@claude-flow/cli/dist/src/commands/performance.js +1 -1
  25. package/v3/@claude-flow/cli/dist/src/commands/plugins.js +1 -1
  26. package/v3/@claude-flow/cli/dist/src/commands/providers.js +1 -1
  27. package/v3/@claude-flow/cli/dist/src/commands/security.js +1 -1
  28. package/v3/@claude-flow/cli/dist/src/commands/start.js +10 -10
  29. package/v3/@claude-flow/cli/dist/src/commands/status.js +2 -2
  30. package/v3/@claude-flow/cli/dist/src/commands/transfer-store.js +1 -1
  31. package/v3/@claude-flow/cli/dist/src/init/executor.js +181 -133
  32. package/v3/@claude-flow/cli/dist/src/init/helpers-generator.d.ts +1 -1
  33. package/v3/@claude-flow/cli/dist/src/init/helpers-generator.js +20 -20
  34. package/v3/@claude-flow/cli/dist/src/init/index.d.ts +1 -1
  35. package/v3/@claude-flow/cli/dist/src/init/index.js +1 -1
  36. package/v3/@claude-flow/cli/dist/src/init/mcp-generator.d.ts +2 -2
  37. package/v3/@claude-flow/cli/dist/src/init/mcp-generator.js +15 -15
  38. package/v3/@claude-flow/cli/dist/src/init/opencode-generator.d.ts +42 -0
  39. package/v3/@claude-flow/cli/dist/src/init/opencode-generator.js +107 -0
  40. package/v3/@claude-flow/cli/dist/src/init/settings-generator.d.ts +1 -1
  41. package/v3/@claude-flow/cli/dist/src/init/settings-generator.js +18 -18
  42. package/v3/@claude-flow/cli/dist/src/init/{claudemd-generator.d.ts → skillmd-generator.d.ts} +8 -8
  43. package/v3/@claude-flow/cli/dist/src/init/{claudemd-generator.js → skillmd-generator.js} +9 -9
  44. package/v3/@claude-flow/cli/dist/src/init/statusline-generator.d.ts +1 -1
  45. package/v3/@claude-flow/cli/dist/src/init/statusline-generator.js +39 -23
  46. package/v3/@claude-flow/cli/dist/src/init/types.d.ts +14 -10
  47. package/v3/@claude-flow/cli/dist/src/init/types.js +3 -3
  48. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +1 -1
  49. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +1 -1
  50. package/v3/@claude-flow/cli/dist/src/plugins/store/discovery.js +1 -1
  51. package/v3/@claude-flow/cli/dist/src/runtime/headless.js +3 -3
  52. package/v3/@claude-flow/cli/dist/src/services/claim-service.js +1 -1
  53. package/v3/@claude-flow/cli/dist/src/types.d.ts +1 -1
  54. package/v3/@claude-flow/cli/dist/src/types.js +1 -1
  55. package/v3/@claude-flow/cli/package.json +1 -1
@@ -371,7 +371,7 @@ const allCommand = {
371
371
  action: async (ctx) => {
372
372
  output.writeln();
373
373
  output.writeln(output.bold(output.highlight('═'.repeat(65))));
374
- output.writeln(output.bold(' RuFlo V3 - Full Benchmark Suite'));
374
+ output.writeln(output.bold(' OpenCode Orchestrator - Full Benchmark Suite'));
375
375
  output.writeln(output.bold(output.highlight('═'.repeat(65))));
376
376
  const startTime = Date.now();
377
377
  const allResults = {};
@@ -439,7 +439,7 @@ export const benchmarkCommand = {
439
439
  ],
440
440
  action: async (_ctx) => {
441
441
  output.writeln();
442
- output.writeln(output.bold('RuFlo V3 Benchmark Suite'));
442
+ output.writeln(output.bold('OpenCode Orchestrator Benchmark Suite'));
443
443
  output.writeln(output.dim('─'.repeat(50)));
444
444
  output.writeln();
445
445
  output.writeln('Available subcommands:');
@@ -344,7 +344,7 @@ export const claimsCommand = {
344
344
  ],
345
345
  action: async () => {
346
346
  output.writeln();
347
- output.writeln(output.bold('RuFlo Claims System'));
347
+ output.writeln(output.bold('OpenCode Claims System'));
348
348
  output.writeln(output.dim('Fine-grained authorization and access control'));
349
349
  output.writeln();
350
350
  output.writeln('Subcommands:');
@@ -33,7 +33,7 @@ const initCommand = {
33
33
  const sparc = ctx.flags.sparc;
34
34
  const v3 = ctx.flags.v3;
35
35
  output.writeln();
36
- output.printInfo('Initializing RuFlo configuration...');
36
+ output.printInfo('Initializing OpenCode configuration...');
37
37
  output.writeln();
38
38
  // Create default configuration
39
39
  const config = {
@@ -371,7 +371,7 @@ const statusCommand = {
371
371
  status.startedAt ? `Started: ${status.startedAt.toISOString()}` : '',
372
372
  `Workers Enabled: ${status.config.workers.filter(w => w.enabled).length}`,
373
373
  `Max Concurrent: ${status.config.maxConcurrent}`,
374
- ].filter(Boolean).join('\n'), 'RuFlo Daemon');
374
+ ].filter(Boolean).join('\n'), 'OpenCode Daemon');
375
375
  output.writeln();
376
376
  output.writeln(output.bold('Worker Status'));
377
377
  const workerData = status.config.workers.map(w => {
@@ -442,7 +442,7 @@ const statusCommand = {
442
442
  `Status: ${output.error('○')} ${output.error('NOT INITIALIZED')}`,
443
443
  '',
444
444
  'Run "claude-flow daemon start" to start the daemon',
445
- ].join('\n'), 'RuFlo Daemon');
445
+ ].join('\n'), 'OpenCode Daemon');
446
446
  return { success: true };
447
447
  }
448
448
  },
@@ -567,7 +567,7 @@ export const daemonCommand = {
567
567
  ],
568
568
  action: async () => {
569
569
  output.writeln();
570
- output.writeln(output.bold('RuFlo Daemon - Background Task Management'));
570
+ output.writeln(output.bold('OpenCode Daemon - Background Task Management'));
571
571
  output.writeln();
572
572
  output.writeln('Node.js-based background worker system that auto-runs like shell daemons.');
573
573
  output.writeln('Manages 12 specialized workers for continuous optimization and monitoring.');
@@ -260,7 +260,7 @@ export const deploymentCommand = {
260
260
  ],
261
261
  action: async () => {
262
262
  output.writeln();
263
- output.writeln(output.bold('RuFlo Deployment'));
263
+ output.writeln(output.bold('OpenCode Deployment'));
264
264
  output.writeln(output.dim('Multi-environment deployment management'));
265
265
  output.writeln();
266
266
  output.writeln('Subcommands:');
@@ -428,7 +428,7 @@ export const doctorCommand = {
428
428
  const component = ctx.flags.component;
429
429
  const verbose = ctx.flags.verbose;
430
430
  output.writeln();
431
- output.writeln(output.bold('RuFlo Doctor'));
431
+ output.writeln(output.bold('OpenCode Doctor'));
432
432
  output.writeln(output.dim('System diagnostics and health check'));
433
433
  output.writeln(output.dim('─'.repeat(50)));
434
434
  output.writeln();
@@ -1536,7 +1536,7 @@ export const embeddingsCommand = {
1536
1536
  ],
1537
1537
  action: async () => {
1538
1538
  output.writeln();
1539
- output.writeln(output.bold('RuFlo Embeddings'));
1539
+ output.writeln(output.bold('OpenCode Embeddings'));
1540
1540
  output.writeln(output.dim('Vector embeddings and semantic search'));
1541
1541
  output.writeln();
1542
1542
  output.writeln('Core Commands:');
@@ -2869,7 +2869,7 @@ const statuslineCommand = {
2869
2869
  return '[' + '●'.repeat(filled) + '○'.repeat(empty) + ']';
2870
2870
  };
2871
2871
  // Generate lines
2872
- let header = `${c.bold}${c.brightPurple}▊ RuFlo V3 ${c.reset}`;
2872
+ let header = `${c.bold}${c.brightPurple}▊ OpenCode Orchestrator ${c.reset}`;
2873
2873
  header += `${swarm.coordinationActive ? c.brightCyan : c.dim}● ${c.brightCyan}${user.name}${c.reset}`;
2874
2874
  if (user.gitBranch) {
2875
2875
  header += ` ${c.dim}│${c.reset} ${c.brightBlue}⎇ ${user.gitBranch}${c.reset}`;
@@ -28,7 +28,7 @@ const initAction = async (ctx) => {
28
28
  const initialized = isInitialized(cwd);
29
29
  const hasExisting = initialized.claude || initialized.claudeFlow;
30
30
  if (hasExisting && !force) {
31
- output.printWarning('RuFlo appears to be already initialized');
31
+ output.printWarning('OpenCode appears to be already initialized');
32
32
  if (initialized.claude)
33
33
  output.printInfo(' Found: .claude/settings.json');
34
34
  if (initialized.claudeFlow)
@@ -48,7 +48,7 @@ const initAction = async (ctx) => {
48
48
  }
49
49
  }
50
50
  output.writeln();
51
- output.writeln(output.bold('Initializing RuFlo V3'));
51
+ output.writeln(output.bold('Initializing OpenCode Orchestrator'));
52
52
  output.writeln();
53
53
  // Build init options based on flags
54
54
  let options;
@@ -70,7 +70,7 @@ const initAction = async (ctx) => {
70
70
  options.components.helpers = false;
71
71
  options.components.statusline = false;
72
72
  options.components.mcp = false;
73
- options.components.claudeMd = false;
73
+ options.components.opencodeMd = false;
74
74
  }
75
75
  if (onlyClaude) {
76
76
  options.components.runtime = false;
@@ -88,7 +88,7 @@ const initAction = async (ctx) => {
88
88
  }
89
89
  return { success: false, exitCode: 1 };
90
90
  }
91
- spinner.succeed('RuFlo V3 initialized successfully!');
91
+ spinner.succeed('OpenCode Orchestrator initialized successfully!');
92
92
  output.writeln();
93
93
  // Display summary
94
94
  const summary = [];
@@ -104,9 +104,9 @@ const initAction = async (ctx) => {
104
104
  output.printBox(summary.join('\n'), 'Summary');
105
105
  output.writeln();
106
106
  // Show what was created
107
- if (options.components.claudeMd || options.components.settings || options.components.skills || options.components.commands || options.components.agents) {
107
+ if (options.components.opencodeMd || options.components.settings || options.components.skills || options.components.commands || options.components.agents) {
108
108
  output.printBox([
109
- options.components.claudeMd ? `CLAUDE.md: Swarm guidance & configuration` : '',
109
+ options.components.opencodeMd ? `CLAUDE.md: Swarm guidance & configuration` : '',
110
110
  options.components.settings ? `Settings: .claude/settings.json` : '',
111
111
  options.components.skills ? `Skills: .claude/skills/ (${result.summary.skillsCount} skills)` : '',
112
112
  options.components.commands ? `Commands: .claude/commands/ (${result.summary.commandsCount} commands)` : '',
@@ -235,7 +235,7 @@ const wizardCommand = {
235
235
  description: 'Interactive setup wizard for comprehensive configuration',
236
236
  action: async (ctx) => {
237
237
  output.writeln();
238
- output.writeln(output.bold('RuFlo V3 Setup Wizard'));
238
+ output.writeln(output.bold('OpenCode Orchestrator Setup Wizard'));
239
239
  output.writeln(output.dim('Answer questions to configure your project'));
240
240
  output.writeln();
241
241
  try {
@@ -264,7 +264,7 @@ const wizardCommand = {
264
264
  const components = await multiSelect({
265
265
  message: 'Select components to initialize:',
266
266
  options: [
267
- { value: 'claudeMd', label: 'CLAUDE.md', hint: 'Swarm guidance and project configuration', selected: true },
267
+ { value: 'opencodeMd', label: 'CLAUDE.md', hint: 'Swarm guidance and project configuration', selected: true },
268
268
  { value: 'settings', label: 'settings.json', hint: 'Claude Code hooks configuration', selected: true },
269
269
  { value: 'skills', label: 'Skills', hint: 'Claude Code skills in .claude/skills/', selected: true },
270
270
  { value: 'commands', label: 'Commands', hint: 'Claude Code commands in .claude/commands/', selected: true },
@@ -275,7 +275,7 @@ const wizardCommand = {
275
275
  { value: 'runtime', label: 'Runtime', hint: '.claude-flow/ directory for V3 runtime', selected: true },
276
276
  ],
277
277
  });
278
- options.components.claudeMd = components.includes('claudeMd');
278
+ options.components.opencodeMd = components.includes('opencodeMd');
279
279
  options.components.settings = components.includes('settings');
280
280
  options.components.skills = components.includes('skills');
281
281
  options.components.commands = components.includes('commands');
@@ -468,7 +468,7 @@ const wizardCommand = {
468
468
  // Check subcommand
469
469
  const checkCommand = {
470
470
  name: 'check',
471
- description: 'Check if RuFlo is initialized',
471
+ description: 'Check if OpenCode is initialized',
472
472
  action: async (ctx) => {
473
473
  const initialized = isInitialized(ctx.cwd);
474
474
  const result = {
@@ -485,7 +485,7 @@ const checkCommand = {
485
485
  return { success: true, data: result };
486
486
  }
487
487
  if (result.initialized) {
488
- output.printSuccess('RuFlo is initialized');
488
+ output.printSuccess('OpenCode is initialized');
489
489
  if (initialized.claude) {
490
490
  output.printInfo(` Claude Code: .claude/settings.json`);
491
491
  }
@@ -494,7 +494,7 @@ const checkCommand = {
494
494
  }
495
495
  }
496
496
  else {
497
- output.printWarning('RuFlo is not initialized in this directory');
497
+ output.printWarning('OpenCode is not initialized in this directory');
498
498
  output.printInfo('Run "ruflo init" to initialize');
499
499
  }
500
500
  return { success: true, data: result };
@@ -525,7 +525,7 @@ const skillsCommand = {
525
525
  statusline: false,
526
526
  mcp: false,
527
527
  runtime: false,
528
- claudeMd: false,
528
+ opencodeMd: false,
529
529
  },
530
530
  skills: {
531
531
  all: ctx.flags.all,
@@ -575,7 +575,7 @@ const hooksCommand = {
575
575
  statusline: false,
576
576
  mcp: false,
577
577
  runtime: false,
578
- claudeMd: false,
578
+ opencodeMd: false,
579
579
  },
580
580
  hooks: minimal
581
581
  ? {
@@ -637,7 +637,7 @@ const upgradeCommand = {
637
637
  const addMissing = (ctx.flags['add-missing'] || ctx.flags.addMissing);
638
638
  const upgradeSettings = (ctx.flags.settings);
639
639
  output.writeln();
640
- output.writeln(output.bold('Upgrading RuFlo'));
640
+ output.writeln(output.bold('Upgrading OpenCode'));
641
641
  if (addMissing && upgradeSettings) {
642
642
  output.writeln(output.dim('Updates helpers, settings, and adds any missing skills/agents/commands'));
643
643
  }
@@ -737,7 +737,7 @@ const upgradeCommand = {
737
737
  // Main init command
738
738
  export const initCommand = {
739
739
  name: 'init',
740
- description: 'Initialize RuFlo in the current directory',
740
+ description: 'Initialize OpenCode in the current directory',
741
741
  subcommands: [wizardCommand, checkCommand, skillsCommand, hooksCommand, upgradeCommand],
742
742
  options: [
743
743
  {
@@ -1435,7 +1435,7 @@ export const neuralCommand = {
1435
1435
  ],
1436
1436
  action: async () => {
1437
1437
  output.writeln();
1438
- output.writeln(output.bold('RuFlo Neural System'));
1438
+ output.writeln(output.bold('OpenCode Neural System'));
1439
1439
  output.writeln(output.dim('Advanced AI pattern learning and inference'));
1440
1440
  output.writeln();
1441
1441
  output.writeln('Use --help with subcommands for more info');
@@ -552,7 +552,7 @@ export const performanceCommand = {
552
552
  ],
553
553
  action: async () => {
554
554
  output.writeln();
555
- output.writeln(output.bold('RuFlo Performance Suite'));
555
+ output.writeln(output.bold('OpenCode Performance Suite'));
556
556
  output.writeln(output.dim('Advanced performance profiling and optimization'));
557
557
  output.writeln();
558
558
  output.writeln('Subcommands:');
@@ -777,7 +777,7 @@ export const pluginsCommand = {
777
777
  ],
778
778
  action: async () => {
779
779
  output.writeln();
780
- output.writeln(output.bold('RuFlo Plugin System'));
780
+ output.writeln(output.bold('OpenCode Plugin System'));
781
781
  output.writeln(output.dim('Decentralized plugin marketplace via IPFS'));
782
782
  output.writeln();
783
783
  output.writeln('Subcommands:');
@@ -204,7 +204,7 @@ export const providersCommand = {
204
204
  ],
205
205
  action: async () => {
206
206
  output.writeln();
207
- output.writeln(output.bold('RuFlo Provider Management'));
207
+ output.writeln(output.bold('OpenCode Provider Management'));
208
208
  output.writeln(output.dim('Multi-provider AI orchestration'));
209
209
  output.writeln();
210
210
  output.writeln('Subcommands:');
@@ -552,7 +552,7 @@ export const securityCommand = {
552
552
  ],
553
553
  action: async () => {
554
554
  output.writeln();
555
- output.writeln(output.bold('RuFlo Security Suite'));
555
+ output.writeln(output.bold('OpenCode Security Suite'));
556
556
  output.writeln(output.dim('Comprehensive security scanning and vulnerability management'));
557
557
  output.writeln();
558
558
  output.writeln('Subcommands:');
@@ -89,7 +89,7 @@ const startAction = async (ctx) => {
89
89
  const cwd = ctx.cwd;
90
90
  // Check initialization
91
91
  if (!isInitialized(cwd)) {
92
- output.printError('RuFlo is not initialized in this directory');
92
+ output.printError('OpenCode is not initialized in this directory');
93
93
  output.printInfo('Run "ruflo init" first to initialize');
94
94
  return { success: false, exitCode: 1 };
95
95
  }
@@ -102,7 +102,7 @@ const startAction = async (ctx) => {
102
102
  const autoStartMcp = mcpConfig.autoStart !== false && !skipMcp;
103
103
  const mcpPort = port || mcpConfig.serverPort || DEFAULT_PORT;
104
104
  output.writeln();
105
- output.writeln(output.bold('Starting RuFlo V3'));
105
+ output.writeln(output.bold('Starting OpenCode Orchestrator'));
106
106
  output.writeln();
107
107
  const spinner = output.createSpinner({ text: 'Initializing system...' });
108
108
  try {
@@ -151,7 +151,7 @@ const startAction = async (ctx) => {
151
151
  }
152
152
  // Success output
153
153
  output.writeln();
154
- output.printSuccess('RuFlo V3 is running!');
154
+ output.printSuccess('OpenCode Orchestrator is running!');
155
155
  output.writeln();
156
156
  // Status display
157
157
  output.printBox([
@@ -230,7 +230,7 @@ const startAction = async (ctx) => {
230
230
  // Stop subcommand
231
231
  const stopCommand = {
232
232
  name: 'stop',
233
- description: 'Stop the RuFlo system',
233
+ description: 'Stop the OpenCode system',
234
234
  options: [
235
235
  {
236
236
  name: 'force',
@@ -250,11 +250,11 @@ const stopCommand = {
250
250
  const force = ctx.flags.force;
251
251
  const timeout = ctx.flags.timeout;
252
252
  output.writeln();
253
- output.writeln(output.bold('Stopping RuFlo'));
253
+ output.writeln(output.bold('Stopping OpenCode'));
254
254
  output.writeln();
255
255
  if (!force && ctx.interactive) {
256
256
  const confirmed = await confirm({
257
- message: 'Are you sure you want to stop RuFlo?',
257
+ message: 'Are you sure you want to stop OpenCode?',
258
258
  default: false
259
259
  });
260
260
  if (!confirmed) {
@@ -294,7 +294,7 @@ const stopCommand = {
294
294
  fs.unlinkSync(daemonPidPath);
295
295
  }
296
296
  output.writeln();
297
- output.printSuccess('RuFlo stopped successfully');
297
+ output.printSuccess('OpenCode stopped successfully');
298
298
  return {
299
299
  success: true,
300
300
  data: { stopped: true, force, stoppedAt: new Date().toISOString() }
@@ -310,7 +310,7 @@ const stopCommand = {
310
310
  // Restart subcommand
311
311
  const restartCommand = {
312
312
  name: 'restart',
313
- description: 'Restart the RuFlo system',
313
+ description: 'Restart the OpenCode system',
314
314
  options: [
315
315
  {
316
316
  name: 'force',
@@ -322,7 +322,7 @@ const restartCommand = {
322
322
  ],
323
323
  action: async (ctx) => {
324
324
  output.writeln();
325
- output.writeln(output.bold('Restarting RuFlo'));
325
+ output.writeln(output.bold('Restarting OpenCode'));
326
326
  output.writeln();
327
327
  // Stop first
328
328
  const stopCtx = { ...ctx, flags: { ...ctx.flags } };
@@ -372,7 +372,7 @@ const quickCommand = {
372
372
  // Main start command
373
373
  export const startCommand = {
374
374
  name: 'start',
375
- description: 'Start the RuFlo orchestration system',
375
+ description: 'Start the OpenCode orchestration system',
376
376
  subcommands: [stopCommand, restartCommand, quickCommand],
377
377
  options: [
378
378
  {
@@ -152,7 +152,7 @@ function displayStatus(status) {
152
152
  const statusIcon = status.running
153
153
  ? output.success('[RUNNING]')
154
154
  : output.warning('[STOPPED]');
155
- output.writeln(`${output.bold('RuFlo V3')} ${statusIcon}`);
155
+ output.writeln(`${output.bold('OpenCode Orchestrator')} ${statusIcon}`);
156
156
  output.writeln();
157
157
  // Swarm section
158
158
  output.writeln(output.bold('Swarm'));
@@ -267,7 +267,7 @@ const statusAction = async (ctx) => {
267
267
  const cwd = ctx.cwd;
268
268
  // Check initialization
269
269
  if (!isInitialized(cwd)) {
270
- output.printError('RuFlo is not initialized in this directory');
270
+ output.printError('OpenCode is not initialized in this directory');
271
271
  output.printInfo('Run "ruflo init" to initialize');
272
272
  return { success: false, exitCode: 1 };
273
273
  }
@@ -405,7 +405,7 @@ export const storeCommand = {
405
405
  ],
406
406
  action: async () => {
407
407
  output.writeln();
408
- output.writeln(output.bold('RuFlo Pattern Store'));
408
+ output.writeln(output.bold('OpenCode Pattern Store'));
409
409
  output.writeln(output.dim('Decentralized pattern marketplace via IPFS'));
410
410
  output.writeln();
411
411
  output.writeln('Subcommands:');