@knowsuchagency/fulcrum 4.3.0 → 4.3.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.
- package/README.md +12 -12
- package/bin/fulcrum.js +146 -111
- package/dist/assets/{index-Dq1YCTgS.js → index-CdhwVHRM.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/index.js +3550 -3237
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
|
-
- **
|
|
23
|
+
- **MCP-First Architecture** — 100+ tools exposed via Model Context Protocol. Agents discover what they need.
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## MCP-First Architecture
|
|
26
26
|
|
|
27
|
-
Fulcrum
|
|
27
|
+
Everything in Fulcrum is exposed through MCP (Model Context Protocol):
|
|
28
28
|
|
|
29
|
-
-
|
|
30
|
-
- **
|
|
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
|
|
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
|
-
##
|
|
253
|
+
## MCP Tools
|
|
254
254
|
|
|
255
|
-
|
|
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 `
|
|
276
|
+
Use `search_tools` to discover available tools by keyword or category.
|
|
277
277
|
|
|
278
|
-
For Claude Desktop
|
|
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.
|
|
46747
|
+
version: "4.3.1"
|
|
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.
|
|
49096
|
+
"version": "4.3.1",
|
|
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.
|
|
49119
|
+
"version": "4.3.1",
|
|
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.
|
|
50225
|
+
version: "4.3.1",
|
|
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.
|
|
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
|
-
|
|
50455
|
-
|
|
50456
|
-
|
|
50457
|
-
|
|
50458
|
-
|
|
50459
|
-
|
|
50460
|
-
|
|
50461
|
-
|
|
50462
|
-
|
|
50463
|
-
|
|
50464
|
-
|
|
50465
|
-
|
|
50466
|
-
|
|
50467
|
-
|
|
50468
|
-
}
|
|
50469
|
-
|
|
50470
|
-
|
|
50471
|
-
|
|
50472
|
-
|
|
50473
|
-
|
|
50474
|
-
|
|
50475
|
-
|
|
50476
|
-
|
|
50477
|
-
|
|
50478
|
-
|
|
50479
|
-
|
|
50480
|
-
|
|
50481
|
-
|
|
50482
|
-
}
|
|
50483
|
-
|
|
50484
|
-
|
|
50485
|
-
|
|
50486
|
-
|
|
50487
|
-
|
|
50488
|
-
|
|
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);
|