@knowsuchagency/fulcrum 5.0.1 → 5.1.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
@@ -316,7 +316,7 @@ For browser-only access, use Tailscale or Cloudflare Tunnels to expose your serv
316
316
  <details>
317
317
  <summary><strong>Configuration</strong></summary>
318
318
 
319
- All configuration is managed by [fnox](https://github.com/yarlson/fnox) — a single `.fnox.toml` file stores both plain and encrypted settings. Sensitive credentials (API keys, tokens, webhook URLs) are encrypted with age; the age key (`age.txt`) lives alongside `.fnox.toml` in the fulcrum directory. Existing `settings.json` files are automatically migrated to fnox on server start.
319
+ All configuration is managed by [fnox](https://github.com/yarlson/fnox) — a single `config/fnox.toml` file inside the fulcrum directory stores both plain and encrypted settings. Sensitive credentials (API keys, tokens, webhook URLs) are encrypted with age; the age key (`age.txt`) lives in the fulcrum directory root. The config is nested under `config/` so fnox's upward directory walk from task worktrees does not merge Fulcrum's recipients into user-invoked `fnox` commands. Existing `settings.json` files are automatically migrated to fnox on server start.
320
320
 
321
321
  The fulcrum directory is resolved in this order:
322
322
 
package/bin/fulcrum.js CHANGED
@@ -795,8 +795,18 @@ function expandPath(p) {
795
795
  }
796
796
  return p;
797
797
  }
798
+ function resolveFnoxConfigPath(fulcrumDir) {
799
+ const preferred = join(fulcrumDir, "config", "fnox.toml");
800
+ if (existsSync(preferred))
801
+ return preferred;
802
+ for (const legacy of [join(fulcrumDir, ".fnox.toml"), join(fulcrumDir, "fnox.toml")]) {
803
+ if (existsSync(legacy))
804
+ return legacy;
805
+ }
806
+ return preferred;
807
+ }
798
808
  function getPortFromFnox(fulcrumDir) {
799
- const fnoxConfigPath = join(fulcrumDir, ".fnox.toml");
809
+ const fnoxConfigPath = resolveFnoxConfigPath(fulcrumDir);
800
810
  const ageKeyPath = join(fulcrumDir, "age.txt");
801
811
  if (!existsSync(fnoxConfigPath) || !existsSync(ageKeyPath))
802
812
  return null;
@@ -843,7 +853,7 @@ function discoverServerUrl(urlOverride, portOverride) {
843
853
  }
844
854
  function updateSettingsPort(port) {
845
855
  const fulcrumDir = getFulcrumDir();
846
- const fnoxConfigPath = join(fulcrumDir, ".fnox.toml");
856
+ const fnoxConfigPath = resolveFnoxConfigPath(fulcrumDir);
847
857
  const ageKeyPath = join(fulcrumDir, "age.txt");
848
858
  if (!existsSync(fulcrumDir)) {
849
859
  mkdirSync(fulcrumDir, { recursive: true });
@@ -44633,7 +44643,7 @@ function getTodayInTimezone(timezone) {
44633
44643
  }
44634
44644
 
44635
44645
  // cli/src/mcp/tools/tasks.ts
44636
- import { basename as basename2 } from "path";
44646
+ import { basename as basename3 } from "path";
44637
44647
  function registerListTasks(server, client) {
44638
44648
  server.tool("list_tasks", "List all Fulcrum tasks with flexible filtering. Supports text search across title/tags/project, multi-tag filtering (OR logic), multi-status filtering, date range, and overdue detection.", {
44639
44649
  status: exports_external.optional(TaskStatusSchema2).describe("Filter by single task status (use statuses for multiple)"),
@@ -44776,7 +44786,7 @@ function registerCreateTask(server, client) {
44776
44786
  recurrenceEndDate
44777
44787
  }) => {
44778
44788
  try {
44779
- const repoName = repoPath ? basename2(repoPath) : null;
44789
+ const repoName = repoPath ? basename3(repoPath) : null;
44780
44790
  const effectiveBaseBranch = baseBranch ?? "main";
44781
44791
  const task = await client.createTask({
44782
44792
  title,
@@ -46828,7 +46838,7 @@ async function runMcpServer(urlOverride, portOverride) {
46828
46838
  const client = new FulcrumClient(urlOverride, portOverride);
46829
46839
  const server = new McpServer({
46830
46840
  name: "fulcrum",
46831
- version: "5.0.1"
46841
+ version: "5.1.0"
46832
46842
  });
46833
46843
  registerTools(server, client);
46834
46844
  const transport = new StdioServerTransport;
@@ -49177,7 +49187,7 @@ var marketplace_default = `{
49177
49187
  "name": "fulcrum",
49178
49188
  "source": "./",
49179
49189
  "description": "Task orchestration for Claude Code",
49180
- "version": "5.0.1",
49190
+ "version": "5.1.0",
49181
49191
  "skills": [
49182
49192
  "./skills/fulcrum"
49183
49193
  ],
@@ -49200,7 +49210,7 @@ var marketplace_default = `{
49200
49210
  var plugin_default = `{
49201
49211
  "name": "fulcrum",
49202
49212
  "description": "Fulcrum task orchestration for Claude Code",
49203
- "version": "5.0.1",
49213
+ "version": "5.1.0",
49204
49214
  "author": {
49205
49215
  "name": "Fulcrum"
49206
49216
  },
@@ -49736,7 +49746,7 @@ var notifyCommand = defineCommand({
49736
49746
  // cli/src/commands/up.ts
49737
49747
  import { spawn as spawn2 } from "child_process";
49738
49748
  import { existsSync as existsSync6 } from "fs";
49739
- import { dirname as dirname3, join as join6 } from "path";
49749
+ import { dirname as dirname4, join as join6 } from "path";
49740
49750
  import { fileURLToPath } from "url";
49741
49751
  init_errors();
49742
49752
 
@@ -50061,17 +50071,21 @@ function installAge() {
50061
50071
  // cli/src/utils/fnox-setup.ts
50062
50072
  init_errors();
50063
50073
  import { execSync as execSync3 } from "child_process";
50064
- import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, chmodSync, renameSync as renameSync2 } from "fs";
50065
- import { join as join5 } from "path";
50074
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, chmodSync, mkdirSync as mkdirSync5, renameSync as renameSync2 } from "fs";
50075
+ import { basename as basename2, dirname as dirname3, join as join5 } from "path";
50066
50076
  function ensureFnoxSetup(fulcrumDir) {
50067
- const oldFnoxPath = join5(fulcrumDir, "fnox.toml");
50068
- const newFnoxPath = join5(fulcrumDir, ".fnox.toml");
50069
- if (existsSync5(oldFnoxPath) && !existsSync5(newFnoxPath)) {
50070
- renameSync2(oldFnoxPath, newFnoxPath);
50071
- console.error("Migrated fnox.toml \u2192 .fnox.toml");
50072
- }
50073
50077
  const ageKeyPath = join5(fulcrumDir, "age.txt");
50074
- const fnoxConfigPath = join5(fulcrumDir, ".fnox.toml");
50078
+ const fnoxConfigPath = join5(fulcrumDir, "config", "fnox.toml");
50079
+ if (!existsSync5(fnoxConfigPath)) {
50080
+ for (const legacy of [join5(fulcrumDir, ".fnox.toml"), join5(fulcrumDir, "fnox.toml")]) {
50081
+ if (existsSync5(legacy)) {
50082
+ mkdirSync5(dirname3(fnoxConfigPath), { recursive: true });
50083
+ renameSync2(legacy, fnoxConfigPath);
50084
+ console.error(`Migrated ${basename2(legacy)} \u2192 config/fnox.toml`);
50085
+ break;
50086
+ }
50087
+ }
50088
+ }
50075
50089
  let publicKey;
50076
50090
  if (!existsSync5(ageKeyPath)) {
50077
50091
  console.error("Generating age encryption key...");
@@ -50097,6 +50111,7 @@ function ensureFnoxSetup(fulcrumDir) {
50097
50111
  }
50098
50112
  if (!existsSync5(fnoxConfigPath)) {
50099
50113
  console.error("Creating fnox configuration...");
50114
+ mkdirSync5(dirname3(fnoxConfigPath), { recursive: true });
50100
50115
  const config = `[providers.plain]
50101
50116
  type = "plain"
50102
50117
 
@@ -50212,7 +50227,7 @@ function compareVersions(v1, v2) {
50212
50227
  var package_default = {
50213
50228
  name: "@knowsuchagency/fulcrum",
50214
50229
  private: true,
50215
- version: "5.0.1",
50230
+ version: "5.1.0",
50216
50231
  description: "Harness Attention. Orchestrate Agents. Ship.",
50217
50232
  license: "PolyForm-Perimeter-1.0.0",
50218
50233
  type: "module",
@@ -50487,14 +50502,14 @@ var updateCommand = defineCommand({
50487
50502
  // cli/src/commands/up.ts
50488
50503
  function getPackageRoot() {
50489
50504
  const currentFile = fileURLToPath(import.meta.url);
50490
- let dir = dirname3(currentFile);
50505
+ let dir = dirname4(currentFile);
50491
50506
  for (let i2 = 0;i2 < 5; i2++) {
50492
50507
  if (existsSync6(join6(dir, "server", "index.js"))) {
50493
50508
  return dir;
50494
50509
  }
50495
- dir = dirname3(dir);
50510
+ dir = dirname4(dir);
50496
50511
  }
50497
- return dirname3(dirname3(dirname3(currentFile)));
50512
+ return dirname4(dirname4(dirname4(currentFile)));
50498
50513
  }
50499
50514
  async function ensureDependency(spec, autoYes) {
50500
50515
  if (spec.isInstalled())