apex-code 0.0.1-alpha.10 → 0.0.1-alpha.11

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 (130) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +9 -8
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +24 -5
  5. package/dist/config.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +26 -0
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +77 -1
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/bash-executor.d.ts.map +1 -1
  11. package/dist/core/bash-executor.js +7 -0
  12. package/dist/core/bash-executor.js.map +1 -1
  13. package/dist/core/checkpoints/git-checkpoints.d.ts +33 -0
  14. package/dist/core/checkpoints/git-checkpoints.d.ts.map +1 -0
  15. package/dist/core/checkpoints/git-checkpoints.js +230 -0
  16. package/dist/core/checkpoints/git-checkpoints.js.map +1 -0
  17. package/dist/core/checkpoints/session-checkpoints.d.ts +23 -0
  18. package/dist/core/checkpoints/session-checkpoints.d.ts.map +1 -0
  19. package/dist/core/checkpoints/session-checkpoints.js +29 -0
  20. package/dist/core/checkpoints/session-checkpoints.js.map +1 -0
  21. package/dist/core/exec.d.ts.map +1 -1
  22. package/dist/core/exec.js +5 -2
  23. package/dist/core/exec.js.map +1 -1
  24. package/dist/core/extensions/loader.d.ts.map +1 -1
  25. package/dist/core/extensions/loader.js +7 -1
  26. package/dist/core/extensions/loader.js.map +1 -1
  27. package/dist/core/mcp/config.d.ts +16 -0
  28. package/dist/core/mcp/config.d.ts.map +1 -0
  29. package/dist/core/mcp/config.js +152 -0
  30. package/dist/core/mcp/config.js.map +1 -0
  31. package/dist/core/mcp/connector.d.ts +10 -0
  32. package/dist/core/mcp/connector.d.ts.map +1 -0
  33. package/dist/core/mcp/connector.js +70 -0
  34. package/dist/core/mcp/connector.js.map +1 -0
  35. package/dist/core/mcp/contract.d.ts +19 -0
  36. package/dist/core/mcp/contract.d.ts.map +1 -0
  37. package/dist/core/mcp/contract.js +89 -0
  38. package/dist/core/mcp/contract.js.map +1 -0
  39. package/dist/core/mcp/mcp-tool.d.ts +32 -0
  40. package/dist/core/mcp/mcp-tool.d.ts.map +1 -0
  41. package/dist/core/mcp/mcp-tool.js +165 -0
  42. package/dist/core/mcp/mcp-tool.js.map +1 -0
  43. package/dist/core/mcp/metadata-cache.d.ts +29 -0
  44. package/dist/core/mcp/metadata-cache.d.ts.map +1 -0
  45. package/dist/core/mcp/metadata-cache.js +99 -0
  46. package/dist/core/mcp/metadata-cache.js.map +1 -0
  47. package/dist/core/mcp/runtime.d.ts +18 -0
  48. package/dist/core/mcp/runtime.d.ts.map +1 -0
  49. package/dist/core/mcp/runtime.js +35 -0
  50. package/dist/core/mcp/runtime.js.map +1 -0
  51. package/dist/core/mcp/schema.d.ts +22 -0
  52. package/dist/core/mcp/schema.d.ts.map +1 -0
  53. package/dist/core/mcp/schema.js +20 -0
  54. package/dist/core/mcp/schema.js.map +1 -0
  55. package/dist/core/mcp/server-manager.d.ts +43 -0
  56. package/dist/core/mcp/server-manager.d.ts.map +1 -0
  57. package/dist/core/mcp/server-manager.js +142 -0
  58. package/dist/core/mcp/server-manager.js.map +1 -0
  59. package/dist/core/mcp/types.d.ts +98 -0
  60. package/dist/core/mcp/types.d.ts.map +1 -0
  61. package/dist/core/mcp/types.js +8 -0
  62. package/dist/core/mcp/types.js.map +1 -0
  63. package/dist/core/sdk.d.ts.map +1 -1
  64. package/dist/core/sdk.js +14 -1
  65. package/dist/core/sdk.js.map +1 -1
  66. package/dist/core/session-manager.d.ts +13 -1
  67. package/dist/core/session-manager.d.ts.map +1 -1
  68. package/dist/core/session-manager.js +30 -3
  69. package/dist/core/session-manager.js.map +1 -1
  70. package/dist/core/settings-manager.d.ts +7 -0
  71. package/dist/core/settings-manager.d.ts.map +1 -1
  72. package/dist/core/settings-manager.js +3 -0
  73. package/dist/core/settings-manager.js.map +1 -1
  74. package/dist/core/slash-commands.d.ts.map +1 -1
  75. package/dist/core/slash-commands.js +1 -0
  76. package/dist/core/slash-commands.js.map +1 -1
  77. package/dist/core/tools/contract-snapshot.d.ts +58 -0
  78. package/dist/core/tools/contract-snapshot.d.ts.map +1 -0
  79. package/dist/core/tools/contract-snapshot.js +51 -0
  80. package/dist/core/tools/contract-snapshot.js.map +1 -0
  81. package/dist/core/tools/contract.d.ts +4 -2
  82. package/dist/core/tools/contract.d.ts.map +1 -1
  83. package/dist/core/tools/contract.js +4 -2
  84. package/dist/core/tools/contract.js.map +1 -1
  85. package/dist/core/tools/index.d.ts +9 -0
  86. package/dist/core/tools/index.d.ts.map +1 -1
  87. package/dist/core/tools/index.js +3 -0
  88. package/dist/core/tools/index.js.map +1 -1
  89. package/dist/index.d.ts +2 -0
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +2 -0
  92. package/dist/index.js.map +1 -1
  93. package/dist/main.d.ts.map +1 -1
  94. package/dist/main.js +6 -6
  95. package/dist/main.js.map +1 -1
  96. package/dist/modes/interactive/components/assistant-message.d.ts +29 -0
  97. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  98. package/dist/modes/interactive/components/assistant-message.js +182 -23
  99. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  100. package/dist/modes/interactive/components/bash-execution.d.ts +7 -0
  101. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  102. package/dist/modes/interactive/components/bash-execution.js +20 -0
  103. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  104. package/dist/modes/interactive/components/footer.d.ts +8 -0
  105. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  106. package/dist/modes/interactive/components/footer.js +29 -9
  107. package/dist/modes/interactive/components/footer.js.map +1 -1
  108. package/dist/modes/interactive/components/tool-execution.d.ts +12 -0
  109. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  110. package/dist/modes/interactive/components/tool-execution.js +31 -0
  111. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  112. package/dist/modes/interactive/interactive-mode.d.ts +29 -0
  113. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  114. package/dist/modes/interactive/interactive-mode.js +88 -4
  115. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  116. package/dist/package-manager-cli.d.ts.map +1 -1
  117. package/dist/package-manager-cli.js +0 -6
  118. package/dist/package-manager-cli.js.map +1 -1
  119. package/dist/utils/version-check.d.ts.map +1 -1
  120. package/dist/utils/version-check.js +6 -4
  121. package/dist/utils/version-check.js.map +1 -1
  122. package/docs/compaction.md +2 -0
  123. package/docs/environment-variables.md +1 -1
  124. package/examples/extensions/git-checkpoint.ts +24 -36
  125. package/npm-shrinkwrap.json +176 -28
  126. package/package.json +10 -8
  127. package/dist/server/create-harness.d.ts +0 -26
  128. package/dist/server/create-harness.d.ts.map +0 -1
  129. package/dist/server/create-harness.js +0 -107
  130. package/dist/server/create-harness.js.map +0 -1
@@ -317,6 +317,11 @@ export class InteractiveMode {
317
317
  firstUseHints;
318
318
  // Track current bash execution component
319
319
  bashComponent = undefined;
320
+ // Reentrancy guard: session.isBashRunning only turns true inside
321
+ // executeBash, so a second `!cmd` submitted during the extension
322
+ // emitUserBash await would otherwise overwrite the in-flight component
323
+ // and orphan the first command's output callback.
324
+ isHandlingBashCommand = false;
320
325
  // Track pending bash components (shown in pending area, moved to chat on submit)
321
326
  pendingBashComponents = [];
322
327
  // Auto-compaction state
@@ -479,8 +484,21 @@ export class InteractiveMode {
479
484
  path: command.sourceInfo.path,
480
485
  }));
481
486
  }
482
- createBaseAutocompleteProvider() {
483
- // Define commands for autocomplete
487
+ /**
488
+ * Every *registered* command: builtin, prompt template, extension, and skill.
489
+ *
490
+ * One function rather than two because `/help` renders this list and autocomplete
491
+ * completes it. Built in two places they would disagree the first time either grew a
492
+ * source, and the disagreement would show up as a command a user can complete but not
493
+ * find, or find but not run.
494
+ *
495
+ * A few commands are dispatched without being registered -- `/debug`, and the
496
+ * `/arminsayshi` and `/dementedelves` easter eggs. They are absent here on purpose,
497
+ * which is also why autocomplete has never offered them. "Registered" is the boundary
498
+ * both surfaces share; listing them in `/help` would advertise what completion cannot
499
+ * complete.
500
+ */
501
+ collectSessionCommands() {
484
502
  const slashCommands = BUILTIN_SLASH_COMMANDS.map((command) => ({
485
503
  name: command.name,
486
504
  description: command.description,
@@ -557,7 +575,10 @@ export class InteractiveMode {
557
575
  });
558
576
  }
559
577
  }
560
- return new CombinedAutocompleteProvider([...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList], this.sessionManager.getCwd(), this.fdPath);
578
+ return [...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList];
579
+ }
580
+ createBaseAutocompleteProvider() {
581
+ return new CombinedAutocompleteProvider(this.collectSessionCommands(), this.sessionManager.getCwd(), this.fdPath);
561
582
  }
562
583
  setupAutocompleteProvider() {
563
584
  let provider = this.createBaseAutocompleteProvider();
@@ -1666,6 +1687,15 @@ export class InteractiveMode {
1666
1687
  this.compactionQueuedMessages = [];
1667
1688
  this.streamingComponent = undefined;
1668
1689
  this.streamingMessage = undefined;
1690
+ // The clears above detach children without stopping their animation
1691
+ // timers. Bash components embed an animated loader; dispose them
1692
+ // explicitly so an in-flight `!cmd` cannot keep rendering (or get
1693
+ // flushed back into a fresh session by flushPendingBashComponents).
1694
+ for (const component of this.pendingBashComponents)
1695
+ component.dispose();
1696
+ this.pendingBashComponents = [];
1697
+ this.bashComponent?.dispose();
1698
+ this.bashComponent = undefined;
1669
1699
  this.clearPendingTools();
1670
1700
  this.renderInitialMessages();
1671
1701
  }
@@ -2129,10 +2159,24 @@ export class InteractiveMode {
2129
2159
  this.showTrustSelector();
2130
2160
  break;
2131
2161
  case "Resources, extensions, and MCP adapters":
2132
- this.showStatus("Run apex-code config to manage resources, extensions, and MCP adapters.");
2162
+ this.showStatus(this.describeMcpServers());
2133
2163
  break;
2134
2164
  }
2135
2165
  }
2166
+ /**
2167
+ * Report configured MCP servers and their live connection state. Replaces a string
2168
+ * that offered MCP management from `apex-code config`, which manages package
2169
+ * resources and has never been able to configure a server.
2170
+ */
2171
+ describeMcpServers() {
2172
+ const runtime = this.session.mcpRuntime;
2173
+ const servers = runtime ? [...runtime.servers.keys()] : [];
2174
+ if (servers.length === 0) {
2175
+ return "Run apex-code config to manage resources and extensions. No MCP server is configured; add one to .mcp.json.";
2176
+ }
2177
+ const states = servers.map((name) => `${name} (${runtime?.manager.state(name).kind ?? "disconnected"})`);
2178
+ return `Run apex-code config to manage resources and extensions. MCP servers: ${states.join(", ")}.`;
2179
+ }
2136
2180
  /**
2137
2181
  * Show a confirmation dialog for extensions.
2138
2182
  */
@@ -2583,6 +2627,11 @@ export class InteractiveMode {
2583
2627
  this.editor.setText("");
2584
2628
  return;
2585
2629
  }
2630
+ if (text === "/help") {
2631
+ this.handleHelpCommand();
2632
+ this.editor.setText("");
2633
+ return;
2634
+ }
2586
2635
  if (text === "/fork") {
2587
2636
  this.showUserMessageSelector();
2588
2637
  this.editor.setText("");
@@ -5667,6 +5716,28 @@ export class InteractiveMode {
5667
5716
  this.chatContainer.addChild(new DynamicBorder());
5668
5717
  this.ui.requestRender();
5669
5718
  }
5719
+ /**
5720
+ * Renders what `collectSessionCommands` returns, so the list a user reads and the list
5721
+ * autocomplete offers are the same list rather than two that agree today. Unregistered
5722
+ * dispatch-only commands are outside that boundary; see the note there.
5723
+ */
5724
+ handleHelpCommand() {
5725
+ const commands = this.collectSessionCommands();
5726
+ const rows = commands
5727
+ .map((command) => {
5728
+ const invocation = command.argumentHint ? `/${command.name} ${command.argumentHint}` : `/${command.name}`;
5729
+ return `| \`${invocation}\` | ${command.description ?? ""} |`;
5730
+ })
5731
+ .join("\n");
5732
+ const help = `| Command | Description |\n|---------|-------------|\n${rows}\n\nType \`/\` to filter these, or \`/hotkeys\` for keyboard shortcuts.`;
5733
+ this.chatContainer.addChild(new Spacer(1));
5734
+ this.chatContainer.addChild(new DynamicBorder());
5735
+ this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Commands")), 1, 0));
5736
+ this.chatContainer.addChild(new Spacer(1));
5737
+ this.chatContainer.addChild(new Markdown(help, 1, 1, this.getMarkdownThemeWithSettings()));
5738
+ this.chatContainer.addChild(new DynamicBorder());
5739
+ this.ui.requestRender();
5740
+ }
5670
5741
  async handleClearCommand() {
5671
5742
  this.clearStatusIndicator();
5672
5743
  try {
@@ -5730,6 +5801,19 @@ export class InteractiveMode {
5730
5801
  }
5731
5802
  }
5732
5803
  async handleBashCommand(command, excludeFromContext = false) {
5804
+ if (this.isHandlingBashCommand) {
5805
+ this.showWarning("A bash command is already running; wait for it to finish");
5806
+ return;
5807
+ }
5808
+ this.isHandlingBashCommand = true;
5809
+ try {
5810
+ await this.runBashCommand(command, excludeFromContext);
5811
+ }
5812
+ finally {
5813
+ this.isHandlingBashCommand = false;
5814
+ }
5815
+ }
5816
+ async runBashCommand(command, excludeFromContext = false) {
5733
5817
  const extensionRunner = this.session.extensionRunner;
5734
5818
  // Emit user_bash event to let extensions intercept
5735
5819
  const eventResult = await extensionRunner.emitUserBash({