frontmcp 1.1.0 → 1.1.2-beta.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 (53) hide show
  1. package/package.json +5 -5
  2. package/src/commands/build/adapters/cloudflare.js +56 -4
  3. package/src/commands/build/adapters/cloudflare.js.map +1 -1
  4. package/src/commands/build/adapters/distributed.js +4 -1
  5. package/src/commands/build/adapters/distributed.js.map +1 -1
  6. package/src/commands/build/adapters/lambda.js +32 -0
  7. package/src/commands/build/adapters/lambda.js.map +1 -1
  8. package/src/commands/build/bundler.js +23 -1
  9. package/src/commands/build/bundler.js.map +1 -1
  10. package/src/commands/build/exec/cli-runtime/extract-public-message.snippet.d.ts +18 -0
  11. package/src/commands/build/exec/cli-runtime/extract-public-message.snippet.js +58 -0
  12. package/src/commands/build/exec/cli-runtime/extract-public-message.snippet.js.map +1 -0
  13. package/src/commands/build/exec/cli-runtime/generate-cli-entry.d.ts +2 -2
  14. package/src/commands/build/exec/cli-runtime/generate-cli-entry.js +195 -47
  15. package/src/commands/build/exec/cli-runtime/generate-cli-entry.js.map +1 -1
  16. package/src/commands/build/exec/cli-runtime/schema-extractor.d.ts +7 -0
  17. package/src/commands/build/exec/cli-runtime/schema-extractor.js +17 -1
  18. package/src/commands/build/exec/cli-runtime/schema-extractor.js.map +1 -1
  19. package/src/commands/build/exec/index.d.ts +11 -0
  20. package/src/commands/build/exec/index.js +68 -20
  21. package/src/commands/build/exec/index.js.map +1 -1
  22. package/src/commands/build/exec/installer-script.d.ts +8 -2
  23. package/src/commands/build/exec/installer-script.js +34 -15
  24. package/src/commands/build/exec/installer-script.js.map +1 -1
  25. package/src/commands/build/exec/manifest.d.ts +16 -3
  26. package/src/commands/build/exec/manifest.js +17 -5
  27. package/src/commands/build/exec/manifest.js.map +1 -1
  28. package/src/commands/build/exec/runner-script.d.ts +9 -1
  29. package/src/commands/build/exec/runner-script.js +60 -2
  30. package/src/commands/build/exec/runner-script.js.map +1 -1
  31. package/src/commands/build/index.js +86 -22
  32. package/src/commands/build/index.js.map +1 -1
  33. package/src/commands/build/load-entry-config.d.ts +33 -0
  34. package/src/commands/build/load-entry-config.js +206 -0
  35. package/src/commands/build/load-entry-config.js.map +1 -0
  36. package/src/commands/build/mcpb/manifest.d.ts +14 -0
  37. package/src/commands/build/mcpb/manifest.js +29 -0
  38. package/src/commands/build/mcpb/manifest.js.map +1 -1
  39. package/src/commands/build/types.d.ts +36 -1
  40. package/src/commands/build/types.js.map +1 -1
  41. package/src/commands/dev/doctor.js +7 -3
  42. package/src/commands/dev/doctor.js.map +1 -1
  43. package/src/commands/package/install.d.ts +1 -1
  44. package/src/commands/package/install.js +10 -8
  45. package/src/commands/package/install.js.map +1 -1
  46. package/src/commands/package/types.d.ts +2 -1
  47. package/src/commands/package/types.js.map +1 -1
  48. package/src/config/frontmcp-config.loader.d.ts +20 -0
  49. package/src/config/frontmcp-config.loader.js +152 -5
  50. package/src/config/frontmcp-config.loader.js.map +1 -1
  51. package/src/config/index.d.ts +1 -1
  52. package/src/config/index.js +2 -1
  53. package/src/config/index.js.map +1 -1
@@ -8,6 +8,7 @@ exports.RESERVED_COMMANDS = void 0;
8
8
  exports.resolveToolCommandName = resolveToolCommandName;
9
9
  exports.generateCliEntry = generateCliEntry;
10
10
  exports.extractTemplateParams = extractTemplateParams;
11
+ const extract_public_message_snippet_1 = require("./extract-public-message.snippet");
11
12
  const schema_extractor_1 = require("./schema-extractor");
12
13
  const schema_to_commander_1 = require("./schema-to-commander");
13
14
  exports.RESERVED_COMMANDS = new Set([
@@ -15,6 +16,9 @@ exports.RESERVED_COMMANDS = new Set([
15
16
  'login', 'logout', 'connect', 'serve', 'daemon',
16
17
  'doctor', 'install', 'uninstall', 'sessions', 'help', 'version',
17
18
  'skills', 'job', 'workflow',
19
+ // Reserved by the symmetric `prompt get <name>` / `resource read <uri>`
20
+ // sub-API; included so a user-defined entry can never shadow them.
21
+ 'get', 'list', 'read',
18
22
  ]);
19
23
  /**
20
24
  * Resolve tool command name, appending '-tool' suffix if it conflicts with a built-in command.
@@ -193,7 +197,31 @@ async function closeClient() {
193
197
  // Flag set by long-running commands (serve, daemon) to prevent the footer from calling process.exit().
194
198
  var _isLongRunning = false;
195
199
 
200
+ ${extract_public_message_snippet_1.EXTRACT_PUBLIC_MESSAGE_SNIPPET}
201
+
196
202
  var program = new Command();
203
+ // Make Commander's own usage errors (unknown subcommand, missing required option,
204
+ // invalid value) exit with code 2 instead of the default 0 — matches POSIX
205
+ // convention and lets shell scripts/CI distinguish runtime failures from usage.
206
+ //
207
+ // Sets process.exitCode and re-throws so the parseAsync() footer can run
208
+ // closeClient() / native-addon teardown before the actual exit. Calling
209
+ // process.exit() directly here would skip that and could leave better-sqlite3
210
+ // / ONNX / file handles in a corrupt state for short-lived runs.
211
+ program.exitOverride(function(err) {
212
+ if (err.code === 'commander.helpDisplayed' || err.code === 'commander.help' || err.code === 'commander.version') {
213
+ process.exitCode = 0;
214
+ } else if (err.code === 'commander.unknownCommand' || err.code === 'commander.unknownOption' ||
215
+ err.code === 'commander.missingArgument' || err.code === 'commander.missingMandatoryOptionValue' ||
216
+ err.code === 'commander.invalidArgument' || err.code === 'commander.optionMissingArgument' ||
217
+ err.code === 'commander.invalidOptionArgument' || err.code === 'commander.excessArguments') {
218
+ process.exitCode = 2;
219
+ } else {
220
+ process.exitCode = 1;
221
+ }
222
+ // Re-throw so parseAsync().catch in the footer runs cleanup before exit.
223
+ throw err;
224
+ });
197
225
  program
198
226
  .name(${JSON.stringify(appName)})
199
227
  .version(${JSON.stringify(appVersion)})
@@ -280,16 +308,28 @@ ${optionLines}
280
308
  var result = await client.callTool(${JSON.stringify(tool.name)}, args);
281
309
  var mode = program.opts().output || ${JSON.stringify('text')};
282
310
  console.log(fmt.formatToolResult(result, mode));
311
+ // The SDK converts thrown errors into a CallToolResult with isError:true
312
+ // (so HTTP/JSON-RPC clients still get a structured response). Detect
313
+ // that here and map to a non-zero exit code so shell scripts can gate
314
+ // on success — Zod input validation errors → exit 2 (usage), all
315
+ // other tool errors → exit 1 (runtime).
316
+ if (result && result.isError === true) {
317
+ var rmeta = (result && result._meta) || {};
318
+ process.exitCode = (rmeta.code === 'INVALID_INPUT') ? 2 : 1;
319
+ }
283
320
  } catch (err) {
284
321
  var meta = err && err._meta ? err._meta : (err && err.data && err.data._meta ? err.data._meta : null);
285
322
  if (meta && meta.authorization_required) {
286
323
  console.error('Authorization required' + (meta.app ? ' for ' + meta.app : ''));
287
324
  if (meta.auth_url) console.error('Authorize at: ' + meta.auth_url);
288
325
  console.error('Or run: ' + ${JSON.stringify(appName)} + ' login');
326
+ process.exitCode = 1;
289
327
  } else {
290
- console.error('Error:', err.message || err);
328
+ // Thrown error path (transport / DI / pre-flow failure) — same
329
+ // mapping as the isError result path above.
330
+ var isUsage = err && err.code === 'INVALID_INPUT';
331
+ _exitWithError(err, isUsage ? 2 : 1);
291
332
  }
292
- process.exitCode = 1;
293
333
  }
294
334
  });`;
295
335
  });
@@ -362,8 +402,7 @@ resourceCmd
362
402
  });
363
403
  }
364
404
  } catch (err) {
365
- console.error('Error:', err.message || err);
366
- process.exitCode = 1;
405
+ _exitWithError(err, 1);
367
406
  }
368
407
  });
369
408
 
@@ -377,8 +416,7 @@ resourceCmd
377
416
  var mode = program.opts().output || 'text';
378
417
  console.log(fmt.formatResourceResult(result, mode));
379
418
  } catch (err) {
380
- console.error('Error:', err.message || err);
381
- process.exitCode = 1;
419
+ _exitWithError(err, 1);
382
420
  }
383
421
  });`;
384
422
  }
@@ -412,8 +450,7 @@ ${optionLines}
412
450
  var mode = program.opts().output || 'text';
413
451
  console.log(fmt.formatResourceResult(result, mode));
414
452
  } catch (err) {
415
- console.error('Error:', err.message || err);
416
- process.exitCode = 1;
453
+ _exitWithError(err, 1);
417
454
  }
418
455
  });`;
419
456
  });
@@ -437,14 +474,44 @@ templateCmd
437
474
  });
438
475
  }
439
476
  } catch (err) {
440
- console.error('Error:', err.message || err);
441
- process.exitCode = 1;
477
+ _exitWithError(err, 1);
442
478
  }
443
479
  });
444
480
 
445
481
  ${subcommands.join('\n\n')}`;
446
482
  }
447
483
  function generatePromptCommands(prompts) {
484
+ // Map known prompts → option specs so `prompt get <name>` knows which flags
485
+ // to accept per prompt. Unknown prompt names still call getPrompt() and
486
+ // surface the server's error to the user.
487
+ const promptArgsMap = prompts.map((p) => {
488
+ const args = (p.arguments || []).map((a) => ({
489
+ name: a.name,
490
+ kebab: (0, schema_to_commander_1.camelToKebab)(a.name),
491
+ camel: kebabToCamel((0, schema_to_commander_1.camelToKebab)(a.name)),
492
+ required: !!a.required,
493
+ }));
494
+ return `${JSON.stringify(p.name)}: ${JSON.stringify(args)}`;
495
+ }).join(',\n ');
496
+ // #382 round-2 — collect the union of all known prompt-arg kebab names so we
497
+ // can register them as `.option(--<name> <value>)` on `prompt get`. Without
498
+ // these registrations, Commander treats the value tokens (e.g. `add` after
499
+ // `--op`) as extra positional args and rejects them with
500
+ // `too many arguments for 'get'. Expected 1 argument but got 7.` —
501
+ // breaking every prompt that takes arguments. Per-prompt validation still
502
+ // happens inside the action handler against `promptArgs[name]`, so a user
503
+ // that types `--op` for a prompt that doesn't declare it gets a clear
504
+ // "unknown option(s) for prompt" error rather than silent acceptance.
505
+ const allKebabNames = new Set();
506
+ for (const p of prompts) {
507
+ for (const a of p.arguments || []) {
508
+ allKebabNames.add((0, schema_to_commander_1.camelToKebab)(a.name));
509
+ }
510
+ }
511
+ const promptGetOptionLines = Array.from(allKebabNames)
512
+ .sort()
513
+ .map((kebab) => ` .option(${JSON.stringify(`--${kebab} <value>`)}, '')`)
514
+ .join('\n');
448
515
  const subcommands = prompts.map((prompt) => {
449
516
  const cmdName = (0, schema_to_commander_1.camelToKebab)(prompt.name).replace(/_/g, '-');
450
517
  const argOptions = (prompt.arguments || [])
@@ -458,7 +525,7 @@ function generatePromptCommands(prompts) {
458
525
  .join('\n');
459
526
  return `promptCmd
460
527
  .command(${JSON.stringify(cmdName)})
461
- .description(${JSON.stringify(prompt.description || '')})
528
+ .description(${JSON.stringify((prompt.description || '') + ' (deprecated alias — use `prompt get ' + cmdName + '`)')})
462
529
  ${argOptions}
463
530
  .action(async function(opts) {
464
531
  try {
@@ -473,8 +540,7 @@ ${argOptions}
473
540
  var mode = program.opts().output || 'text';
474
541
  console.log(fmt.formatPromptResult(result, mode));
475
542
  } catch (err) {
476
- console.error('Error:', err.message || err);
477
- process.exitCode = 1;
543
+ _exitWithError(err, 1);
478
544
  }
479
545
  });`;
480
546
  });
@@ -498,8 +564,94 @@ promptCmd
498
564
  });
499
565
  }
500
566
  } catch (err) {
501
- console.error('Error:', err.message || err);
502
- process.exitCode = 1;
567
+ _exitWithError(err, 1);
568
+ }
569
+ });
570
+
571
+ // Symmetric \`prompt get <name>\` to mirror \`resource read <uri>\`. Looks up
572
+ // per-prompt argument metadata from \`promptArgs\` and forwards as MCP
573
+ // \`prompts/get\` request arguments. Unknown / missing required flags exit 2.
574
+ //
575
+ // Robust flag parser supports:
576
+ // --key value (canonical form)
577
+ // --key=value (single-token form)
578
+ // --bool (boolean — value defaults to "true")
579
+ // -- (end-of-options marker; everything after is ignored)
580
+ // Unknown flags fail-fast with exit 2 instead of being silently dropped.
581
+ var promptArgs = {
582
+ ${promptArgsMap}
583
+ };
584
+ var _getCmd = promptCmd
585
+ .command('get <name>')
586
+ .description('Render a prompt by name')
587
+ ${promptGetOptionLines}
588
+ .allowUnknownOption(true)
589
+ .action(async function(name) {
590
+ try {
591
+ var spec = promptArgs[name];
592
+ if (!spec) {
593
+ console.error('Error: Unknown prompt: ' + name);
594
+ process.exitCode = 1;
595
+ return;
596
+ }
597
+ // Commander parsed registered options into rawOpts (camelCased). For
598
+ // unregistered prompts (a flag a different prompt declares but this one
599
+ // doesn't), fall back to scanning the raw token stream — that way an
600
+ // out-of-spec --foo for "this" prompt still surfaces as an explicit
601
+ // "unknown option(s)" error rather than being silently dropped.
602
+ var rawOpts = this.opts();
603
+ var rawTokens = this.args.slice(1);
604
+ var args = {};
605
+ var unknown = [];
606
+ var byKebab = {};
607
+ var byCamel = {};
608
+ for (var s = 0; s < spec.length; s++) {
609
+ byKebab[spec[s].kebab] = spec[s];
610
+ byCamel[spec[s].camel] = spec[s];
611
+ }
612
+ // 1. Pull values from Commander-parsed options (registered names).
613
+ for (var camelKey in rawOpts) {
614
+ if (Object.prototype.hasOwnProperty.call(rawOpts, camelKey)) {
615
+ var matchByCamel = byCamel[camelKey];
616
+ if (matchByCamel) {
617
+ args[matchByCamel.name] = rawOpts[camelKey];
618
+ }
619
+ }
620
+ }
621
+ // 2. Scan rawTokens for any --<flag> not in this prompt's spec — those
622
+ // are real "unknown for this prompt" errors. (Commander already
623
+ // consumed the registered ones; only out-of-spec flags survive here
624
+ // via .allowUnknownOption(true).)
625
+ for (var i = 0; i < rawTokens.length; i++) {
626
+ var tok = rawTokens[i];
627
+ if (tok === '--') break;
628
+ if (typeof tok !== 'string' || tok.indexOf('--') !== 0) continue;
629
+ var keyAndVal = tok.slice(2);
630
+ var eq = keyAndVal.indexOf('=');
631
+ var key = eq >= 0 ? keyAndVal.slice(0, eq) : keyAndVal;
632
+ if (!byKebab[key]) {
633
+ unknown.push('--' + key);
634
+ }
635
+ }
636
+ if (unknown.length > 0) {
637
+ console.error('Error: unknown option(s) for prompt "' + name + '": ' + unknown.join(', '));
638
+ process.exitCode = 2;
639
+ return;
640
+ }
641
+ // 3. Validate required args.
642
+ for (var r = 0; r < spec.length; r++) {
643
+ if (spec[r].required && args[spec[r].name] === undefined) {
644
+ console.error('Error: missing required option --' + spec[r].kebab);
645
+ process.exitCode = 2;
646
+ return;
647
+ }
648
+ }
649
+ var client = await getClient();
650
+ var result = await client.getPrompt(name, args);
651
+ var mode = program.opts().output || 'text';
652
+ console.log(fmt.formatPromptResult(result, mode));
653
+ } catch (err) {
654
+ _exitWithError(err, 1);
503
655
  }
504
656
  });
505
657
 
@@ -535,8 +687,7 @@ skillsCmd
535
687
  console.log(" Use '" + program.name() + " skills load <name>' to load a skill.\\n");
536
688
  }
537
689
  } catch (err) {
538
- console.error('Error:', err.message || err);
539
- process.exitCode = 1;
690
+ _exitWithError(err, 1);
540
691
  }
541
692
  });
542
693
 
@@ -557,8 +708,7 @@ skillsCmd
557
708
  }
558
709
  }
559
710
  } catch (err) {
560
- console.error('Error:', err.message || err);
561
- process.exitCode = 1;
711
+ _exitWithError(err, 1);
562
712
  }
563
713
  });
564
714
 
@@ -594,8 +744,7 @@ skillsCmd
594
744
  console.log(" Load: " + program.name() + " skills load " + name + '\\n');
595
745
  }
596
746
  } catch (err) {
597
- console.error('Error:', err.message || err);
598
- process.exitCode = 1;
747
+ _exitWithError(err, 1);
599
748
  }
600
749
  });
601
750
 
@@ -623,8 +772,7 @@ skillsCmd
623
772
  console.log(" Use '" + program.name() + " skills read <name>' for full details.\\n");
624
773
  }
625
774
  } catch (err) {
626
- console.error('Error:', err.message || err);
627
- process.exitCode = 1;
775
+ _exitWithError(err, 1);
628
776
  }
629
777
  });`;
630
778
  }
@@ -659,8 +807,7 @@ ${optionLines}
659
807
  }
660
808
  }
661
809
  } catch (err) {
662
- console.error('Error:', err.message || err);
663
- process.exitCode = 1;
810
+ _exitWithError(err, 1);
664
811
  }
665
812
  });`;
666
813
  }
@@ -690,8 +837,7 @@ ${optionLines}
690
837
  }
691
838
  }
692
839
  } catch (err) {
693
- console.error('Error:', err.message || err);
694
- process.exitCode = 1;
840
+ _exitWithError(err, 1);
695
841
  }
696
842
  });`;
697
843
  });
@@ -721,8 +867,7 @@ ${optionLines}
721
867
  }
722
868
  }
723
869
  } catch (err) {
724
- console.error('Error:', err.message || err);
725
- process.exitCode = 1;
870
+ _exitWithError(err, 1);
726
871
  }
727
872
  });`;
728
873
  return `var jobCmd = program.command('job').description('Job operations');
@@ -749,8 +894,7 @@ jobCmd
749
894
  }
750
895
  }
751
896
  } catch (err) {
752
- console.error('Error:', err.message || err);
753
- process.exitCode = 1;
897
+ _exitWithError(err, 1);
754
898
  }
755
899
  });
756
900
 
@@ -782,8 +926,7 @@ ${jobs.length > 0 ? genericRun : `jobRunCmd
782
926
  }
783
927
  }
784
928
  } catch (err) {
785
- console.error('Error:', err.message || err);
786
- process.exitCode = 1;
929
+ _exitWithError(err, 1);
787
930
  }
788
931
  });`}
789
932
 
@@ -801,8 +944,7 @@ jobCmd
801
944
  console.log('Status: ' + (result.status || JSON.stringify(result)));
802
945
  }
803
946
  } catch (err) {
804
- console.error('Error:', err.message || err);
805
- process.exitCode = 1;
947
+ _exitWithError(err, 1);
806
948
  }
807
949
  });`;
808
950
  }
@@ -831,8 +973,7 @@ workflowCmd
831
973
  }
832
974
  }
833
975
  } catch (err) {
834
- console.error('Error:', err.message || err);
835
- process.exitCode = 1;
976
+ _exitWithError(err, 1);
836
977
  }
837
978
  });
838
979
 
@@ -861,8 +1002,7 @@ workflowCmd
861
1002
  }
862
1003
  }
863
1004
  } catch (err) {
864
- console.error('Error:', err.message || err);
865
- process.exitCode = 1;
1005
+ _exitWithError(err, 1);
866
1006
  }
867
1007
  });
868
1008
 
@@ -880,8 +1020,7 @@ workflowCmd
880
1020
  console.log('Status: ' + (result.status || JSON.stringify(result)));
881
1021
  }
882
1022
  } catch (err) {
883
- console.error('Error:', err.message || err);
884
- process.exitCode = 1;
1023
+ _exitWithError(err, 1);
885
1024
  }
886
1025
  });`;
887
1026
  }
@@ -933,8 +1072,7 @@ subscribeCmd
933
1072
  setInterval(function() {}, 2147483647);
934
1073
  await new Promise(function() {});
935
1074
  } catch (err) {
936
- console.error('Error:', err.message || err);
937
- process.exitCode = 1;
1075
+ _exitWithError(err, 1);
938
1076
  }
939
1077
  });
940
1078
 
@@ -962,8 +1100,7 @@ subscribeCmd
962
1100
  setInterval(function() {}, 2147483647);
963
1101
  await new Promise(function() {});
964
1102
  } catch (err) {
965
- console.error('Error:', err.message || err);
966
- process.exitCode = 1;
1103
+ _exitWithError(err, 1);
967
1104
  }
968
1105
  });`;
969
1106
  }
@@ -1521,9 +1658,20 @@ program.parseAsync(process.argv).then(async function() {
1521
1658
  // (ONNX runtime, etc.) can release mutexes before V8 tears down.
1522
1659
  setImmediate(function() { process.exit(process.exitCode || 0); });
1523
1660
  }).catch(async function(err) {
1524
- console.error('Fatal:', err.message || err);
1661
+ // Commander errors come through exitOverride with the code already set on
1662
+ // process.exitCode. They are user-facing usage errors, not fatals — don't
1663
+ // re-print "Fatal:" / "Unknown error" for them.
1664
+ var isCommanderErr = err && typeof err.code === 'string' && err.code.indexOf('commander.') === 0;
1665
+ if (!isCommanderErr) {
1666
+ console.error('Fatal:', err.message || err);
1667
+ }
1525
1668
  await closeClient();
1526
- process.exit(1);
1669
+ // Use the exit code set by exitOverride (which can legitimately be 0 for
1670
+ // --help / --version). Only fall back to 1 when no code was set.
1671
+ setImmediate(function() {
1672
+ var code = (typeof process.exitCode === 'number') ? process.exitCode : 1;
1673
+ process.exit(code);
1674
+ });
1527
1675
  });`;
1528
1676
  }
1529
1677
  /**