@knowsuchagency/fulcrum 4.3.0 → 4.4.0

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/README.md CHANGED
@@ -20,19 +20,19 @@ Fulcrum doesn't replace your tools—it gives you leverage over them. You config
20
20
  - **Project Management** — Tasks with dependencies, due dates, time estimates, priority levels, recurrence, labels, and attachments. Visual kanban boards.
21
21
  - **Production Deployment** — Docker Compose with automatic Traefik routing and Cloudflare DNS/tunnels.
22
22
  - **Agent Memory** — Persistent knowledge store with full-text search. Agents remember across sessions.
23
- - **Skills-First Architecture** — Agents discover capabilities through skills and the `fulcrum api` CLI. MCP available for clients that support it.
23
+ - **MCP-First Architecture** — 100+ tools exposed via Model Context Protocol. Agents discover what they need.
24
24
 
25
- ## Skills-First Architecture
25
+ ## MCP-First Architecture
26
26
 
27
- Fulcrum's capabilities are exposed through skills and a unified CLI:
27
+ Everything in Fulcrum is exposed through MCP (Model Context Protocol):
28
28
 
29
- - **`fulcrum api` CLI** — Resource/action CLI to all 100+ API endpoints. `fulcrum api tools` prints a compact reference (~2K tokens) for context injection
30
- - **Skills for Claude Code** — The Fulcrum skill teaches agents how to use `current-task`, notifications, config, and the API
31
- - **MCP for other clients** — Claude Desktop, OpenCode, and other MCP-compatible agents can use the full MCP server
32
- - **No context bloat** — Skills load on demand; `fulcrum api tools` replaces ~45K tokens of MCP definitions with ~2K tokens
29
+ - **100+ MCP tools** for tasks, projects, apps, repos, notifications, and remote execution
30
+ - **Smart tool discovery** — `search_tools` lets agents find relevant tools without loading everything into context
33
31
  - **Integrated assistant** — Built-in AI assistant with full context of your tasks, projects, and apps
32
+ - **External agent support** — Connect Claude Desktop, Clawdbot, or any MCP-compatible agent
33
+ - **No context bloat** — Agents discover and use only the tools they need
34
34
 
35
- Whether you use Claude Code with skills, Claude Desktop with MCP, or any other agent, Fulcrum provides seamless access to your entire workflow.
35
+ Whether you use Fulcrum's built-in assistant or an external agent like Claude Desktop, AI has seamless access to your entire workflow.
36
36
 
37
37
  ## Proactive Digital Concierge
38
38
 
@@ -250,9 +250,9 @@ fulcrum opencode install # Install plugin + MCP server
250
250
  fulcrum opencode uninstall # Remove both
251
251
  ```
252
252
 
253
- ## Skills & API
253
+ ## MCP Tools
254
254
 
255
- Fulcrum exposes 100+ API endpoints that agents access through skills and the `fulcrum api` CLI:
255
+ Both plugins include an MCP server with 100+ tools:
256
256
 
257
257
  | Category | Description |
258
258
  |----------|-------------|
@@ -273,9 +273,9 @@ Fulcrum exposes 100+ API endpoints that agents access through skills and the `fu
273
273
  | **Jobs** | List, create, update, delete, enable/disable, and run systemd timers and launchd jobs |
274
274
  | **Assistant** | Send messages via channels (WhatsApp, Discord, Telegram, Slack, Gmail); query sweep history |
275
275
 
276
- Use `fulcrum api tools` for a compact reference of all resources and actions, or `fulcrum api routes --search <keyword>` for detailed route discovery.
276
+ Use `search_tools` to discover available tools by keyword or category.
277
277
 
278
- For Claude Desktop (MCP), add to your `claude_desktop_config.json`:
278
+ For Claude Desktop, add to your `claude_desktop_config.json`:
279
279
 
280
280
  ```json
281
281
  {
package/bin/fulcrum.js CHANGED
@@ -43850,6 +43850,13 @@ var init_registry = __esm(() => {
43850
43850
  keywords: ["app", "create", "new", "deploy", "docker", "compose"],
43851
43851
  defer_loading: true
43852
43852
  },
43853
+ {
43854
+ name: "update_app",
43855
+ description: "Update app settings including service exposure, environment variables, and deployment options",
43856
+ category: "apps",
43857
+ keywords: ["app", "update", "configure", "service", "exposure", "domain", "tunnel", "dns", "environment"],
43858
+ defer_loading: true
43859
+ },
43853
43860
  {
43854
43861
  name: "deploy_app",
43855
43862
  description: "Trigger a deployment for an app",
@@ -45531,6 +45538,31 @@ var registerAppTools = (server, client) => {
45531
45538
  return handleToolError(err);
45532
45539
  }
45533
45540
  });
45541
+ server.tool("update_app", "Update app settings including service exposure, environment variables, and deployment options", {
45542
+ id: exports_external.string().describe("App ID"),
45543
+ name: exports_external.optional(exports_external.string()).describe("App name"),
45544
+ branch: exports_external.optional(exports_external.string()).describe("Git branch"),
45545
+ autoDeployEnabled: exports_external.optional(exports_external.boolean()).describe("Enable auto-deploy on git push"),
45546
+ autoPortAllocation: exports_external.optional(exports_external.boolean()).describe("Auto-allocate host ports on conflicts"),
45547
+ environmentVariables: exports_external.optional(exports_external.record(exports_external.string(), exports_external.string())).describe("Environment variables (key-value pairs)"),
45548
+ noCacheBuild: exports_external.optional(exports_external.boolean()).describe("Disable Docker build cache"),
45549
+ notificationsEnabled: exports_external.optional(exports_external.boolean()).describe("Send notifications on deploy success/failure"),
45550
+ services: exports_external.optional(exports_external.array(exports_external.object({
45551
+ id: exports_external.optional(exports_external.string()).describe("Service ID (for updating existing)"),
45552
+ serviceName: exports_external.string().describe("Service name (must match compose file)"),
45553
+ containerPort: exports_external.optional(exports_external.number()).describe("Port the container listens on"),
45554
+ exposed: exports_external.boolean().describe("Make publicly accessible"),
45555
+ domain: exports_external.optional(exports_external.string()).describe("Domain to route traffic to this service"),
45556
+ exposureMethod: exports_external.optional(exports_external.enum(["dns", "tunnel"])).describe("Exposure method: dns (Traefik + Cloudflare A record) or tunnel (Cloudflare Tunnel)")
45557
+ }))).describe("Service exposure configuration")
45558
+ }, async ({ id, ...rest }) => {
45559
+ try {
45560
+ const app = await client.updateApp(id, rest);
45561
+ return formatSuccess(app);
45562
+ } catch (err) {
45563
+ return handleToolError(err);
45564
+ }
45565
+ });
45534
45566
  server.tool("deploy_app", "Trigger a deployment for an app", {
45535
45567
  id: exports_external.string().describe("App ID")
45536
45568
  }, async ({ id }) => {
@@ -46561,7 +46593,7 @@ var JobScopeSchema, registerJobTools = (server, client) => {
46561
46593
  schedule: exports_external.string().describe('systemd OnCalendar schedule (e.g., "daily", "*-*-* 09:00:00", "Mon..Fri 09:00")'),
46562
46594
  command: exports_external.string().describe("Command to execute"),
46563
46595
  workingDirectory: exports_external.optional(exports_external.string()).describe("Working directory for the command"),
46564
- environment: exports_external.optional(exports_external.record(exports_external.string())).describe("Environment variables as key-value pairs"),
46596
+ environment: exports_external.optional(exports_external.record(exports_external.string(), exports_external.string())).describe("Environment variables as key-value pairs"),
46565
46597
  persistent: exports_external.optional(exports_external.boolean()).describe("Run missed executions on next boot (default: true)")
46566
46598
  }, async ({ name, description, schedule, command, workingDirectory, environment, persistent }) => {
46567
46599
  try {
@@ -46585,7 +46617,7 @@ var JobScopeSchema, registerJobTools = (server, client) => {
46585
46617
  schedule: exports_external.optional(exports_external.string()).describe("New schedule"),
46586
46618
  command: exports_external.optional(exports_external.string()).describe("New command"),
46587
46619
  workingDirectory: exports_external.optional(exports_external.string()).describe("New working directory"),
46588
- environment: exports_external.optional(exports_external.record(exports_external.string())).describe("New environment variables"),
46620
+ environment: exports_external.optional(exports_external.record(exports_external.string(), exports_external.string())).describe("New environment variables"),
46589
46621
  persistent: exports_external.optional(exports_external.boolean()).describe("Run missed executions on next boot")
46590
46622
  }, async ({ name, description, schedule, command, workingDirectory, environment, persistent }) => {
46591
46623
  try {
@@ -46712,7 +46744,7 @@ async function runMcpServer(urlOverride, portOverride) {
46712
46744
  const client = new FulcrumClient(urlOverride, portOverride);
46713
46745
  const server = new McpServer({
46714
46746
  name: "fulcrum",
46715
- version: "4.3.0"
46747
+ version: "4.4.0"
46716
46748
  });
46717
46749
  registerTools(server, client);
46718
46750
  const transport = new StdioServerTransport;
@@ -49061,7 +49093,7 @@ var marketplace_default = `{
49061
49093
  "name": "fulcrum",
49062
49094
  "source": "./",
49063
49095
  "description": "Task orchestration for Claude Code",
49064
- "version": "4.3.0",
49096
+ "version": "4.4.0",
49065
49097
  "skills": [
49066
49098
  "./skills/fulcrum"
49067
49099
  ],
@@ -49084,11 +49116,12 @@ var marketplace_default = `{
49084
49116
  var plugin_default = `{
49085
49117
  "name": "fulcrum",
49086
49118
  "description": "Fulcrum task orchestration for Claude Code",
49087
- "version": "4.3.0",
49119
+ "version": "4.4.0",
49088
49120
  "author": {
49089
49121
  "name": "Fulcrum"
49090
49122
  },
49091
49123
  "hooks": "./hooks/hooks.json",
49124
+ "mcpServers": "./.mcp.json",
49092
49125
  "skills": "./skills/",
49093
49126
  "commands": "./commands/"
49094
49127
  }
@@ -49121,6 +49154,17 @@ var hooks_default = `{
49121
49154
  }
49122
49155
  `;
49123
49156
 
49157
+ // plugins/fulcrum/.mcp.json
49158
+ var _mcp_default = `{
49159
+ "mcpServers": {
49160
+ "fulcrum": {
49161
+ "command": "fulcrum",
49162
+ "args": ["mcp"]
49163
+ }
49164
+ }
49165
+ }
49166
+ `;
49167
+
49124
49168
  // plugins/fulcrum/commands/pr.md
49125
49169
  var pr_default = `---
49126
49170
  description: Link a GitHub PR to the current fulcrum task
@@ -49313,6 +49357,44 @@ fulcrum notify "Need Input" "Which approach should I use for the database migrat
49313
49357
  - \`DONE\` \u2014 Task is finished
49314
49358
  - \`CANCELED\` \u2014 Task was abandoned
49315
49359
 
49360
+ ## MCP Tools Reference
49361
+
49362
+ When using Fulcrum via MCP (Claude Desktop, built-in assistant), these tools are available:
49363
+
49364
+ **Tasks:** \`list_tasks\`, \`get_task\`, \`create_task\`, \`update_task\`, \`move_task\`, \`delete_task\`, \`add_task_tag\`, \`remove_task_tag\`, \`set_task_due_date\`, \`add_task_dependency\`, \`remove_task_dependency\`, \`upload_task_attachment\`, \`list_task_attachments\`, \`add_task_link\`, \`list_task_links\`
49365
+
49366
+ **Projects:** \`list_projects\`, \`get_project\`, \`create_project\`, \`update_project\`, \`delete_project\`, \`add_project_tag\`, \`remove_project_tag\`, \`upload_project_attachment\`, \`list_project_attachments\`, \`add_project_link\`, \`list_project_links\`
49367
+
49368
+ **Repos:** \`list_repositories\`, \`get_repository\`, \`add_repository\`, \`update_repository\`, \`link_repository_to_project\`, \`unlink_repository_from_project\`
49369
+
49370
+ **Apps:** \`list_apps\`, \`get_app\`, \`create_app\`, \`update_app\`, \`delete_app\`, \`deploy_app\`, \`stop_app\`, \`get_app_logs\`, \`get_app_status\`, \`list_deployments\`
49371
+
49372
+ **Jobs:** \`list_jobs\`, \`get_job\`, \`get_job_logs\`, \`create_job\`, \`update_job\`, \`delete_job\`, \`enable_job\`, \`disable_job\`, \`run_job_now\`
49373
+
49374
+ **Files:** \`read_file\`, \`write_file\`, \`edit_file\`, \`list_directory\`, \`get_file_tree\`, \`file_stat\`
49375
+
49376
+ **Exec:** \`execute_command\`, \`list_exec_sessions\`, \`destroy_exec_session\`
49377
+
49378
+ **Notifications:** \`send_notification\`
49379
+
49380
+ **Settings:** \`list_settings\`, \`get_setting\`, \`update_setting\`, \`reset_setting\`, \`get_notification_settings\`, \`update_notification_settings\`
49381
+
49382
+ **Backup:** \`list_backups\`, \`create_backup\`, \`get_backup\`, \`restore_backup\`, \`delete_backup\`
49383
+
49384
+ **Search:** \`search\` (unified FTS5 across tasks, projects, messages, events, memories, conversations, gmail)
49385
+
49386
+ **Memory:** \`memory_file_read\`, \`memory_file_update\`, \`memory_store\`, \`memory_search\`, \`memory_list\`, \`memory_delete\`
49387
+
49388
+ **Assistant:** \`message\` (send to WhatsApp/Discord/Telegram/Slack/Gmail), \`get_last_sweep\`
49389
+
49390
+ **Calendar:** \`list_caldav_accounts\`, \`create_caldav_account\`, \`delete_caldav_account\`, \`sync_caldav_account\`, \`list_caldav_copy_rules\`, \`create_caldav_copy_rule\`, \`delete_caldav_copy_rule\`, \`execute_caldav_copy_rule\`
49391
+
49392
+ **Gmail:** \`list_google_accounts\`, \`list_gmail_drafts\`, \`create_gmail_draft\`, \`update_gmail_draft\`, \`delete_gmail_draft\`
49393
+
49394
+ **Email:** \`list_emails\`, \`get_email\`, \`search_emails\`, \`fetch_emails\`
49395
+
49396
+ **Utilities:** \`list_tags\`, \`delete_tag\`, \`get_task_dependency_graph\`, \`is_git_repo\`
49397
+
49316
49398
  ## Best Practices
49317
49399
 
49318
49400
  1. **Use \`current-task\` inside worktrees** \u2014 It auto-detects which task you're in
@@ -49331,6 +49413,7 @@ var PLUGIN_FILES = [
49331
49413
  { path: ".claude-plugin/marketplace.json", content: marketplace_default },
49332
49414
  { path: ".claude-plugin/plugin.json", content: plugin_default },
49333
49415
  { path: "hooks/hooks.json", content: hooks_default },
49416
+ { path: ".mcp.json", content: _mcp_default },
49334
49417
  { path: "commands/pr.md", content: pr_default },
49335
49418
  { path: "commands/task-info.md", content: task_info_default },
49336
49419
  { path: "commands/notify.md", content: notify_default },
@@ -50139,7 +50222,7 @@ function compareVersions(v1, v2) {
50139
50222
  var package_default = {
50140
50223
  name: "@knowsuchagency/fulcrum",
50141
50224
  private: true,
50142
- version: "4.3.0",
50225
+ version: "4.4.0",
50143
50226
  description: "Harness Attention. Orchestrate Agents. Ship.",
50144
50227
  license: "PolyForm-Perimeter-1.0.0",
50145
50228
  type: "module",
@@ -50155,7 +50238,7 @@ var package_default = {
50155
50238
  "db:studio": "drizzle-kit studio"
50156
50239
  },
50157
50240
  dependencies: {
50158
- "@anthropic-ai/claude-agent-sdk": "0.2.45",
50241
+ "@anthropic-ai/claude-agent-sdk": "^0.2.47",
50159
50242
  "@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
50160
50243
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
50161
50244
  "@azurity/pure-nerd-font": "^3.0.5",
@@ -50424,6 +50507,24 @@ function getPackageRoot() {
50424
50507
  }
50425
50508
  return dirname3(dirname3(dirname3(currentFile)));
50426
50509
  }
50510
+ async function ensureDependency(spec, autoYes) {
50511
+ if (spec.isInstalled())
50512
+ return;
50513
+ const dep = getDependency(spec.name);
50514
+ const method = getInstallMethod(dep);
50515
+ console.error(spec.reason);
50516
+ console.error(` ${spec.description}`);
50517
+ const shouldInstall = autoYes || await confirm(`Would you like to install ${spec.name} via ${method}?`);
50518
+ if (shouldInstall) {
50519
+ const success = spec.install();
50520
+ if (!success) {
50521
+ throw new CliError("INSTALL_FAILED", `Failed to install ${spec.name}`, ExitCodes.ERROR);
50522
+ }
50523
+ console.error(`${spec.name} installed successfully!`);
50524
+ } else {
50525
+ throw new CliError("MISSING_DEPENDENCY", `${spec.name} is required. Install manually: ${getInstallCommand(dep)}`, ExitCodes.ERROR);
50526
+ }
50527
+ }
50427
50528
  async function handleUpCommand(flags) {
50428
50529
  const autoYes = flags.yes === "true" || flags.y === "true";
50429
50530
  const shouldUpdate = flags.update === "true";
@@ -50451,85 +50552,45 @@ Found existing Vibora data at ${viboraDir}`);
50451
50552
  console.error('Run "fulcrum migrate-from-vibora" to copy your data to ~/.fulcrum');
50452
50553
  console.error("");
50453
50554
  }
50454
- if (!isBunInstalled()) {
50455
- const bunDep = getDependency("bun");
50456
- const method = getInstallMethod(bunDep);
50457
- console.error("Bun is required to run Fulcrum but is not installed.");
50458
- console.error(" Bun is the JavaScript runtime that powers Fulcrum.");
50459
- const shouldInstall = autoYes || await confirm(`Would you like to install bun via ${method}?`);
50460
- if (shouldInstall) {
50461
- const success = installBun();
50462
- if (!success) {
50463
- throw new CliError("INSTALL_FAILED", "Failed to install bun", ExitCodes.ERROR);
50464
- }
50465
- console.error("Bun installed successfully!");
50466
- } else {
50467
- throw new CliError("MISSING_DEPENDENCY", `Bun is required. Install manually: ${getInstallCommand(bunDep)}`, ExitCodes.ERROR);
50468
- }
50469
- }
50470
- if (!isDtachInstalled()) {
50471
- const dtachDep = getDependency("dtach");
50472
- const method = getInstallMethod(dtachDep);
50473
- console.error("dtach is required for terminal persistence but is not installed.");
50474
- console.error(" dtach enables persistent terminal sessions that survive disconnects.");
50475
- const shouldInstall = autoYes || await confirm(`Would you like to install dtach via ${method}?`);
50476
- if (shouldInstall) {
50477
- const success = installDtach();
50478
- if (!success) {
50479
- throw new CliError("INSTALL_FAILED", "Failed to install dtach", ExitCodes.ERROR);
50480
- }
50481
- console.error("dtach installed successfully!");
50482
- } else {
50483
- throw new CliError("MISSING_DEPENDENCY", `dtach is required. Install manually: ${getInstallCommand(dtachDep)}`, ExitCodes.ERROR);
50484
- }
50485
- }
50486
- if (!isUvInstalled()) {
50487
- const uvDep = getDependency("uv");
50488
- const method = getInstallMethod(uvDep);
50489
- console.error("uv is required but is not installed.");
50490
- console.error(" uv is a fast Python package manager used by Claude Code.");
50491
- const shouldInstall = autoYes || await confirm(`Would you like to install uv via ${method}?`);
50492
- if (shouldInstall) {
50493
- const success = installUv();
50494
- if (!success) {
50495
- throw new CliError("INSTALL_FAILED", "Failed to install uv", ExitCodes.ERROR);
50496
- }
50497
- console.error("uv installed successfully!");
50498
- } else {
50499
- throw new CliError("MISSING_DEPENDENCY", `uv is required. Install manually: ${getInstallCommand(uvDep)}`, ExitCodes.ERROR);
50500
- }
50501
- }
50502
- if (!isFnoxInstalled()) {
50503
- const fnoxDep = getDependency("fnox");
50504
- const method = getInstallMethod(fnoxDep);
50505
- console.error("fnox is required for encrypted secrets management but is not installed.");
50506
- console.error(" fnox encrypts sensitive settings like API keys and tokens.");
50507
- const shouldInstall = autoYes || await confirm(`Would you like to install fnox via ${method}?`);
50508
- if (shouldInstall) {
50509
- const success = installFnox();
50510
- if (!success) {
50511
- throw new CliError("INSTALL_FAILED", "Failed to install fnox", ExitCodes.ERROR);
50512
- }
50513
- console.error("fnox installed successfully!");
50514
- } else {
50515
- throw new CliError("MISSING_DEPENDENCY", `fnox is required. Install manually: ${getInstallCommand(fnoxDep)}`, ExitCodes.ERROR);
50516
- }
50517
- }
50518
- if (!isAgeInstalled()) {
50519
- const ageDep = getDependency("age");
50520
- const method = getInstallMethod(ageDep);
50521
- console.error("age is required for encryption but is not installed.");
50522
- console.error(" age generates encryption keys used by fnox to encrypt secrets.");
50523
- const shouldInstall = autoYes || await confirm(`Would you like to install age via ${method}?`);
50524
- if (shouldInstall) {
50525
- const success = installAge();
50526
- if (!success) {
50527
- throw new CliError("INSTALL_FAILED", "Failed to install age", ExitCodes.ERROR);
50528
- }
50529
- console.error("age installed successfully!");
50530
- } else {
50531
- throw new CliError("MISSING_DEPENDENCY", `age is required. Install manually: ${getInstallCommand(ageDep)}`, ExitCodes.ERROR);
50555
+ const requiredDeps = [
50556
+ {
50557
+ name: "bun",
50558
+ isInstalled: isBunInstalled,
50559
+ install: installBun,
50560
+ reason: "Bun is required to run Fulcrum but is not installed.",
50561
+ description: "Bun is the JavaScript runtime that powers Fulcrum."
50562
+ },
50563
+ {
50564
+ name: "dtach",
50565
+ isInstalled: isDtachInstalled,
50566
+ install: installDtach,
50567
+ reason: "dtach is required for terminal persistence but is not installed.",
50568
+ description: "dtach enables persistent terminal sessions that survive disconnects."
50569
+ },
50570
+ {
50571
+ name: "uv",
50572
+ isInstalled: isUvInstalled,
50573
+ install: installUv,
50574
+ reason: "uv is required but is not installed.",
50575
+ description: "uv is a fast Python package manager used by Claude Code."
50576
+ },
50577
+ {
50578
+ name: "fnox",
50579
+ isInstalled: isFnoxInstalled,
50580
+ install: installFnox,
50581
+ reason: "fnox is required for encrypted secrets management but is not installed.",
50582
+ description: "fnox encrypts sensitive settings like API keys and tokens."
50583
+ },
50584
+ {
50585
+ name: "age",
50586
+ isInstalled: isAgeInstalled,
50587
+ install: installAge,
50588
+ reason: "age is required for encryption but is not installed.",
50589
+ description: "age generates encryption keys used by fnox to encrypt secrets."
50532
50590
  }
50591
+ ];
50592
+ for (const dep of requiredDeps) {
50593
+ await ensureDependency(dep, autoYes);
50533
50594
  }
50534
50595
  if (isClaudeInstalled() && needsPluginUpdate()) {
50535
50596
  console.error("Updating Fulcrum plugin for Claude Code...");
@@ -51408,28 +51469,6 @@ function getRawArgsAfterApi() {
51408
51469
  return [];
51409
51470
  return argv2.slice(apiIdx + 1);
51410
51471
  }
51411
- var routesCommand = defineCommand({
51412
- meta: { name: "routes", description: "List available API routes" },
51413
- args: {
51414
- ...globalArgs,
51415
- category: { type: "string", description: "Filter by category" },
51416
- search: { type: "string", description: "Search routes by keyword" }
51417
- },
51418
- async run({ args }) {
51419
- setupJsonOutput(args);
51420
- await handleRoutes(toFlags(args));
51421
- }
51422
- });
51423
- var toolsCommand = defineCommand({
51424
- meta: { name: "tools", description: "Print compact tool reference for context window injection" },
51425
- args: {
51426
- ...globalArgs
51427
- },
51428
- async run({ args }) {
51429
- setupJsonOutput(args);
51430
- await handleTools(toFlags(args));
51431
- }
51432
- });
51433
51472
  var apiCommand = defineCommand({
51434
51473
  meta: { name: "api", description: "REST API access \u2014 route discovery, HTTP proxy, and resource/action CLI" },
51435
51474
  args: {
@@ -51440,10 +51479,6 @@ var apiCommand = defineCommand({
51440
51479
  category: { type: "string", description: "Filter routes by category" },
51441
51480
  search: { type: "string", description: "Search routes by keyword" }
51442
51481
  },
51443
- subCommands: {
51444
- routes: routesCommand,
51445
- tools: toolsCommand
51446
- },
51447
51482
  async run({ args }) {
51448
51483
  setupJsonOutput(args);
51449
51484
  const flags = toFlags(args);