@storybloq/storybloq 1.4.2 → 1.4.3

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/dist/cli.js CHANGED
@@ -1809,7 +1809,7 @@ var init_init = __esm({
1809
1809
  init_esm_shims();
1810
1810
  init_project_loader();
1811
1811
  init_errors();
1812
- STORY_GITIGNORE_ENTRIES = ["snapshots/", "status.json", "sessions/"];
1812
+ STORY_GITIGNORE_ENTRIES = ["snapshots/", "status.json", "sessions/", "federation-cache.json"];
1813
1813
  }
1814
1814
  });
1815
1815
 
@@ -9424,7 +9424,7 @@ async function scanNodeSummary(storyDir, signal) {
9424
9424
  };
9425
9425
  }
9426
9426
  function withTimeout(promise, ms, controller) {
9427
- return new Promise((resolve15, reject) => {
9427
+ return new Promise((resolve16, reject) => {
9428
9428
  const timer = setTimeout(() => {
9429
9429
  controller.abort();
9430
9430
  reject(new Error("timeout"));
@@ -9432,7 +9432,7 @@ function withTimeout(promise, ms, controller) {
9432
9432
  promise.then(
9433
9433
  (val) => {
9434
9434
  clearTimeout(timer);
9435
- resolve15(val);
9435
+ resolve16(val);
9436
9436
  },
9437
9437
  (err) => {
9438
9438
  clearTimeout(timer);
@@ -11240,17 +11240,17 @@ __export(git_inspector_exports, {
11240
11240
  });
11241
11241
  import { execFile } from "child_process";
11242
11242
  async function git(cwd, args, parse) {
11243
- return new Promise((resolve15) => {
11243
+ return new Promise((resolve16) => {
11244
11244
  execFile("git", args, { cwd, timeout: GIT_TIMEOUT, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
11245
11245
  if (err) {
11246
11246
  const message = stderr?.trim() || err.message || "unknown git error";
11247
- resolve15({ ok: false, reason: "git_error", message });
11247
+ resolve16({ ok: false, reason: "git_error", message });
11248
11248
  return;
11249
11249
  }
11250
11250
  try {
11251
- resolve15({ ok: true, data: parse(stdout) });
11251
+ resolve16({ ok: true, data: parse(stdout) });
11252
11252
  } catch (parseErr) {
11253
- resolve15({ ok: false, reason: "parse_error", message: parseErr.message });
11253
+ resolve16({ ok: false, reason: "parse_error", message: parseErr.message });
11254
11254
  }
11255
11255
  });
11256
11256
  });
@@ -11357,22 +11357,22 @@ async function gitIsAncestor(cwd, ancestor, descendant) {
11357
11357
  if (!SAFE_REF.test(ancestor) || !SAFE_REF.test(descendant)) {
11358
11358
  return { ok: false, reason: "git_error", message: "invalid ref format" };
11359
11359
  }
11360
- return new Promise((resolve15) => {
11360
+ return new Promise((resolve16) => {
11361
11361
  execFile(
11362
11362
  "git",
11363
11363
  ["merge-base", "--is-ancestor", ancestor, descendant],
11364
11364
  { cwd, timeout: GIT_TIMEOUT },
11365
11365
  (err) => {
11366
11366
  if (!err) {
11367
- resolve15({ ok: true, data: true });
11367
+ resolve16({ ok: true, data: true });
11368
11368
  return;
11369
11369
  }
11370
11370
  const code = err.code;
11371
11371
  if (code === 1) {
11372
- resolve15({ ok: true, data: false });
11372
+ resolve16({ ok: true, data: false });
11373
11373
  return;
11374
11374
  }
11375
- resolve15({ ok: false, reason: "git_error", message: err.message });
11375
+ resolve16({ ok: false, reason: "git_error", message: err.message });
11376
11376
  }
11377
11377
  );
11378
11378
  });
@@ -11394,14 +11394,14 @@ async function gitLogRange(cwd, from, to, limit = 20) {
11394
11394
  );
11395
11395
  }
11396
11396
  async function gitHeadHash(cwd) {
11397
- return new Promise((resolve15) => {
11397
+ return new Promise((resolve16) => {
11398
11398
  execFile("git", ["rev-parse", "HEAD"], { cwd, timeout: 3e3 }, (err, stdout) => {
11399
11399
  if (err) {
11400
11400
  const message = err.stderr?.trim() || err.message || "unknown git error";
11401
- resolve15({ ok: false, reason: "git_error", message });
11401
+ resolve16({ ok: false, reason: "git_error", message });
11402
11402
  return;
11403
11403
  }
11404
- resolve15({ ok: true, data: stdout.trim() });
11404
+ resolve16({ ok: true, data: stdout.trim() });
11405
11405
  });
11406
11406
  });
11407
11407
  }
@@ -11419,7 +11419,7 @@ async function gitResolveCommit(cwd, hash) {
11419
11419
  if (!SAFE_REF.test(hash)) {
11420
11420
  return { ok: false, reason: "git_error", message: "invalid ref format" };
11421
11421
  }
11422
- return new Promise((resolve15) => {
11422
+ return new Promise((resolve16) => {
11423
11423
  execFile(
11424
11424
  "git",
11425
11425
  ["rev-parse", "--verify", `${hash}^{commit}`],
@@ -11427,10 +11427,10 @@ async function gitResolveCommit(cwd, hash) {
11427
11427
  (err, stdout, stderr) => {
11428
11428
  if (err) {
11429
11429
  const message = stderr?.trim() || err.message || "unknown git error";
11430
- resolve15({ ok: false, reason: "git_error", message });
11430
+ resolve16({ ok: false, reason: "git_error", message });
11431
11431
  return;
11432
11432
  }
11433
- resolve15({ ok: true, data: stdout.trim() });
11433
+ resolve16({ ok: true, data: stdout.trim() });
11434
11434
  }
11435
11435
  );
11436
11436
  });
@@ -11452,18 +11452,18 @@ async function gitCheckoutNewBranch(cwd, branchName, base) {
11452
11452
  return git(cwd, ["checkout", "-b", branchName, base], () => void 0);
11453
11453
  }
11454
11454
  async function gitBranchExists(cwd, branchName) {
11455
- return new Promise((resolve15) => {
11455
+ return new Promise((resolve16) => {
11456
11456
  execFile("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`], { cwd, timeout: GIT_TIMEOUT }, (err) => {
11457
11457
  if (err) {
11458
11458
  const exitCode = err.code;
11459
11459
  if (exitCode === 1) {
11460
- resolve15({ ok: true, data: false });
11460
+ resolve16({ ok: true, data: false });
11461
11461
  } else {
11462
- resolve15({ ok: false, reason: "git_error", message: err.message });
11462
+ resolve16({ ok: false, reason: "git_error", message: err.message });
11463
11463
  }
11464
11464
  return;
11465
11465
  }
11466
- resolve15({ ok: true, data: true });
11466
+ resolve16({ ok: true, data: true });
11467
11467
  });
11468
11468
  });
11469
11469
  }
@@ -11471,13 +11471,13 @@ async function gitCheckoutBranch(cwd, branchName) {
11471
11471
  return git(cwd, ["checkout", branchName], () => void 0);
11472
11472
  }
11473
11473
  async function gitCheckRefFormat(cwd, refName) {
11474
- return new Promise((resolve15) => {
11474
+ return new Promise((resolve16) => {
11475
11475
  execFile("git", ["check-ref-format", "--branch", refName], { cwd, timeout: GIT_TIMEOUT }, (err) => {
11476
11476
  if (err) {
11477
- resolve15({ ok: true, data: false });
11477
+ resolve16({ ok: true, data: false });
11478
11478
  return;
11479
11479
  }
11480
- resolve15({ ok: true, data: true });
11480
+ resolve16({ ok: true, data: true });
11481
11481
  });
11482
11482
  });
11483
11483
  }
@@ -17571,7 +17571,7 @@ function getInstalledVersion() {
17571
17571
  }
17572
17572
  }
17573
17573
  function getRunningVersion() {
17574
- return "1.4.2";
17574
+ return "1.4.3";
17575
17575
  }
17576
17576
  var init_version_check = __esm({
17577
17577
  "src/autonomous/version-check.ts"() {
@@ -19863,7 +19863,7 @@ function registerAllTools(server, pinnedRoot) {
19863
19863
  const result = await runMcpReadTool(pinnedRoot, handleStatus);
19864
19864
  try {
19865
19865
  const { readUpdateCacheSync: readUpdateCacheSync2, refreshUpdateCacheInBackground: refreshUpdateCacheInBackground2 } = await Promise.resolve().then(() => (init_update_check(), update_check_exports));
19866
- const running = "1.4.2";
19866
+ const running = "1.4.3";
19867
19867
  const info = readUpdateCacheSync2(running);
19868
19868
  refreshUpdateCacheInBackground2();
19869
19869
  if (info?.updateAvailable && result.content[0]?.type === "text") {
@@ -21506,7 +21506,7 @@ var init_mcp = __esm({
21506
21506
  ENV_VAR2 = "STORYBLOQ_PROJECT_ROOT";
21507
21507
  LEGACY_ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
21508
21508
  CONFIG_PATH2 = ".story/config.json";
21509
- version = "1.4.2";
21509
+ version = "1.4.3";
21510
21510
  main().catch((err) => {
21511
21511
  process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
21512
21512
  `);
@@ -22973,7 +22973,7 @@ function codePrompt(sessionId) {
22973
22973
  ].join(" ");
22974
22974
  }
22975
22975
  async function runCodexExec(root, prompt, schemaPath, outputPath, timeoutMs) {
22976
- await new Promise((resolve15, reject) => {
22976
+ await new Promise((resolve16, reject) => {
22977
22977
  const child = spawn3("codex", [
22978
22978
  "exec",
22979
22979
  "--ephemeral",
@@ -23016,7 +23016,7 @@ async function runCodexExec(root, prompt, schemaPath, outputPath, timeoutMs) {
23016
23016
  if (timedOut) {
23017
23017
  finish(() => reject(new Error(`codex exec timed out after ${Math.round(timeoutMs / 1e3)} seconds`)));
23018
23018
  } else if (code === 0) {
23019
- finish(() => resolve15());
23019
+ finish(() => resolve16());
23020
23020
  } else {
23021
23021
  finish(() => reject(new Error(`codex exec exited with status ${code}: ${stderr.trim()}`)));
23022
23022
  }
@@ -23110,6 +23110,64 @@ var init_codex_review = __esm({
23110
23110
  }
23111
23111
  });
23112
23112
 
23113
+ // src/core/symlink-write.ts
23114
+ import { lstat as lstat3, mkdir as mkdir7, readlink, realpath as realpath2, rename as rename3, unlink as unlink4, writeFile as writeFile4 } from "fs/promises";
23115
+ import { dirname as dirname8, isAbsolute as isAbsolute3, resolve as resolve15 } from "path";
23116
+ async function resolveSymlinkTarget(path2) {
23117
+ try {
23118
+ return await realpath2(path2);
23119
+ } catch (e) {
23120
+ if (e.code !== "ENOENT") throw e;
23121
+ let cur = path2;
23122
+ for (let depth = 0; depth < MAX_SYMLINK_DEPTH; depth++) {
23123
+ const link = await readlink(cur);
23124
+ const next = isAbsolute3(link) ? link : resolve15(dirname8(cur), link);
23125
+ let st;
23126
+ try {
23127
+ st = await lstat3(next);
23128
+ } catch (le) {
23129
+ if (le.code === "ENOENT") return next;
23130
+ throw le;
23131
+ }
23132
+ if (st.isSymbolicLink()) {
23133
+ cur = next;
23134
+ continue;
23135
+ }
23136
+ return next;
23137
+ }
23138
+ throw new Error(`symlink chain too deep at ${path2}`);
23139
+ }
23140
+ }
23141
+ async function atomicWriteFollowingSymlink(targetPath, contents) {
23142
+ let st = null;
23143
+ try {
23144
+ st = await lstat3(targetPath);
23145
+ } catch (e) {
23146
+ if (e.code !== "ENOENT") throw e;
23147
+ }
23148
+ const realTarget = st?.isSymbolicLink() ? await resolveSymlinkTarget(targetPath) : targetPath;
23149
+ const tmpPath = `${realTarget}.${process.pid}.tmp`;
23150
+ try {
23151
+ await mkdir7(dirname8(realTarget), { recursive: true });
23152
+ await writeFile4(tmpPath, contents, "utf-8");
23153
+ await rename3(tmpPath, realTarget);
23154
+ } catch (err) {
23155
+ try {
23156
+ await unlink4(tmpPath);
23157
+ } catch {
23158
+ }
23159
+ throw err;
23160
+ }
23161
+ }
23162
+ var MAX_SYMLINK_DEPTH;
23163
+ var init_symlink_write = __esm({
23164
+ "src/core/symlink-write.ts"() {
23165
+ "use strict";
23166
+ init_esm_shims();
23167
+ MAX_SYMLINK_DEPTH = 40;
23168
+ }
23169
+ });
23170
+
23113
23171
  // src/core/hook-migration.ts
23114
23172
  var hook_migration_exports = {};
23115
23173
  __export(hook_migration_exports, {
@@ -23123,10 +23181,10 @@ __export(hook_migration_exports, {
23123
23181
  parseHookCommand: () => parseHookCommand,
23124
23182
  sweepLegacyHooks: () => sweepLegacyHooks
23125
23183
  });
23126
- import { mkdir as mkdir7, readFile as readFile10, rename as rename3, unlink as unlink4, writeFile as writeFile4 } from "fs/promises";
23184
+ import { readFile as readFile10 } from "fs/promises";
23127
23185
  import { existsSync as existsSync22 } from "fs";
23128
23186
  import { homedir as homedir4 } from "os";
23129
- import { basename as basename5, dirname as dirname8, join as join51 } from "path";
23187
+ import { basename as basename5, join as join51 } from "path";
23130
23188
  function defaultSettingsPath() {
23131
23189
  return join51(homedir4(), ".claude", "settings.json");
23132
23190
  }
@@ -23253,17 +23311,9 @@ async function migrateLegacyHookVariants(hookType, subcommand, newCommand, setti
23253
23311
  removedCount += before - g.hooks.length;
23254
23312
  }
23255
23313
  if (removedCount === 0) return 0;
23256
- const tmpPath = `${path2}.${process.pid}.tmp`;
23257
23314
  try {
23258
- const dir = dirname8(path2);
23259
- await mkdir7(dir, { recursive: true });
23260
- await writeFile4(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
23261
- await rename3(tmpPath, path2);
23315
+ await atomicWriteFollowingSymlink(path2, JSON.stringify(settings, null, 2) + "\n");
23262
23316
  } catch {
23263
- try {
23264
- await unlink4(tmpPath);
23265
- } catch {
23266
- }
23267
23317
  return 0;
23268
23318
  }
23269
23319
  return removedCount;
@@ -23341,6 +23391,7 @@ var init_hook_migration = __esm({
23341
23391
  "src/core/hook-migration.ts"() {
23342
23392
  "use strict";
23343
23393
  init_esm_shims();
23394
+ init_symlink_write();
23344
23395
  PRECOMPACT_SUBCOMMAND = "session compact-prepare";
23345
23396
  SESSIONSTART_SUBCOMMAND = "session resume-prompt";
23346
23397
  STOP_SUBCOMMAND = "hook-status";
@@ -23458,6 +23509,7 @@ __export(setup_skill_exports, {
23458
23509
  SESSIONSTART_SUBCOMMAND: () => SESSIONSTART_SUBCOMMAND,
23459
23510
  STOP_SUBCOMMAND: () => STOP_SUBCOMMAND,
23460
23511
  STORYBLOQ_LEGACY_BASENAMES: () => STORYBLOQ_LEGACY_BASENAMES,
23512
+ __copyDirRecursiveForTest: () => __copyDirRecursiveForTest,
23461
23513
  copyDirRecursive: () => copyDirRecursive,
23462
23514
  ensureCodexClientEnv: () => ensureCodexClientEnv,
23463
23515
  ensureCodexToolApprovals: () => ensureCodexToolApprovals,
@@ -23478,7 +23530,7 @@ __export(setup_skill_exports, {
23478
23530
  resolveStorybloqBin: () => resolveStorybloqBin,
23479
23531
  sweepLegacyHooks: () => sweepLegacyHooks
23480
23532
  });
23481
- import { mkdir as mkdir8, writeFile as writeFile5, readFile as readFile11, readdir as readdir7, copyFile, rm, rename as rename4, unlink as unlink5 } from "fs/promises";
23533
+ import { mkdir as mkdir8, writeFile as writeFile5, readFile as readFile11, readdir as readdir7, copyFile, rm, rename as rename4, lstat as lstat4 } from "fs/promises";
23482
23534
  import { existsSync as existsSync24, accessSync as accessSync4, readdirSync as readdirSync9, constants as fsConstants } from "fs";
23483
23535
  import { join as join53, dirname as dirname9, delimiter as pathDelimiter } from "path";
23484
23536
  import { homedir as homedir6 } from "os";
@@ -23500,10 +23552,38 @@ function resolveSkillSourceDir() {
23500
23552
  );
23501
23553
  }
23502
23554
  async function copyDirRecursive(srcDir, destDir) {
23503
- const tmpDir = destDir + ".tmp";
23504
- const bakDir = destDir + ".bak";
23505
- if (!existsSync24(destDir) && existsSync24(bakDir)) {
23506
- await rename4(bakDir, destDir);
23555
+ return runCopyDir(srcDir, destDir);
23556
+ }
23557
+ async function __copyDirRecursiveForTest(srcDir, destDir, testHooks) {
23558
+ return runCopyDir(srcDir, destDir, testHooks);
23559
+ }
23560
+ async function runCopyDir(srcDir, destDir, testHooks) {
23561
+ let st = null;
23562
+ try {
23563
+ st = await lstat4(destDir);
23564
+ } catch (e) {
23565
+ if (e.code !== "ENOENT") throw e;
23566
+ }
23567
+ let targetDir = destDir;
23568
+ if (st?.isSymbolicLink()) {
23569
+ targetDir = await resolveSymlinkTarget(destDir);
23570
+ let resolvedStat = null;
23571
+ try {
23572
+ resolvedStat = await lstat4(targetDir);
23573
+ } catch (e) {
23574
+ if (e.code !== "ENOENT") throw e;
23575
+ }
23576
+ if (resolvedStat && !resolvedStat.isDirectory()) {
23577
+ throw new Error(`refusing to replace non-directory symlink target: ${targetDir}`);
23578
+ }
23579
+ }
23580
+ return copyDirSwap(srcDir, targetDir, testHooks);
23581
+ }
23582
+ async function copyDirSwap(srcDir, targetDir, testHooks) {
23583
+ const tmpDir = targetDir + ".tmp";
23584
+ const bakDir = targetDir + ".bak";
23585
+ if (!existsSync24(targetDir) && existsSync24(bakDir)) {
23586
+ await rename4(bakDir, targetDir);
23507
23587
  }
23508
23588
  if (existsSync24(tmpDir)) await rm(tmpDir, { recursive: true, force: true });
23509
23589
  if (existsSync24(bakDir)) await rm(bakDir, { recursive: true, force: true });
@@ -23520,13 +23600,14 @@ async function copyDirRecursive(srcDir, destDir) {
23520
23600
  await copyFile(srcPath, destPath);
23521
23601
  written.push(relativePath);
23522
23602
  }
23523
- if (existsSync24(destDir)) {
23524
- await rename4(destDir, bakDir);
23603
+ if (existsSync24(targetDir)) {
23604
+ await rename4(targetDir, bakDir);
23525
23605
  }
23526
23606
  try {
23527
- await rename4(tmpDir, destDir);
23607
+ if (testHooks?.beforeSwapRename) await testHooks.beforeSwapRename();
23608
+ await rename4(tmpDir, targetDir);
23528
23609
  } catch (err) {
23529
- if (existsSync24(bakDir)) await rename4(bakDir, destDir).catch(() => {
23610
+ if (existsSync24(bakDir)) await rename4(bakDir, targetDir).catch(() => {
23530
23611
  });
23531
23612
  await rm(tmpDir, { recursive: true, force: true }).catch(() => {
23532
23613
  });
@@ -23687,17 +23768,9 @@ async function registerHook(hookType, hookEntry, settingsPath, matcher) {
23687
23768
  if (!appended) {
23688
23769
  hookArray.push({ matcher: targetMatcher, hooks: [hookEntry] });
23689
23770
  }
23690
- const tmpPath = `${path2}.${process.pid}.tmp`;
23691
23771
  try {
23692
- const dir = dirname9(path2);
23693
- await mkdir8(dir, { recursive: true });
23694
- await writeFile5(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
23695
- await rename4(tmpPath, path2);
23772
+ await atomicWriteFollowingSymlink(path2, JSON.stringify(settings, null, 2) + "\n");
23696
23773
  } catch (err) {
23697
- try {
23698
- await unlink5(tmpPath);
23699
- } catch {
23700
- }
23701
23774
  const message = err instanceof Error ? err.message : String(err);
23702
23775
  process.stderr.write(`Failed to write settings.json: ${message}
23703
23776
  `);
@@ -23751,17 +23824,9 @@ async function removeHook(hookType, command, settingsPath) {
23751
23824
  if (g.hooks.length < before) removed = true;
23752
23825
  }
23753
23826
  if (!removed) return "not_found";
23754
- const tmpPath = `${path2}.${process.pid}.tmp`;
23755
23827
  try {
23756
- const dir = dirname9(path2);
23757
- await mkdir8(dir, { recursive: true });
23758
- await writeFile5(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
23759
- await rename4(tmpPath, path2);
23828
+ await atomicWriteFollowingSymlink(path2, JSON.stringify(settings, null, 2) + "\n");
23760
23829
  } catch {
23761
- try {
23762
- await unlink5(tmpPath);
23763
- } catch {
23764
- }
23765
23830
  return "skipped";
23766
23831
  }
23767
23832
  return "removed";
@@ -24009,16 +24074,9 @@ approval_mode = "approve"
24009
24074
  if (next.length > 0 && !next.endsWith("\n\n")) next += "\n";
24010
24075
  next += additions.join("\n");
24011
24076
  }
24012
- const tmpPath = `${configPath}.${process.pid}.tmp`;
24013
24077
  try {
24014
- await mkdir8(dirname9(configPath), { recursive: true });
24015
- await writeFile5(tmpPath, next, "utf-8");
24016
- await rename4(tmpPath, configPath);
24078
+ await atomicWriteFollowingSymlink(configPath, next);
24017
24079
  } catch (err) {
24018
- try {
24019
- await unlink5(tmpPath);
24020
- } catch {
24021
- }
24022
24080
  const message = err instanceof Error ? err.message : String(err);
24023
24081
  process.stderr.write(`Failed to write Codex config.toml: ${message}
24024
24082
  `);
@@ -24098,16 +24156,9 @@ async function ensureCodexClientEnv(configPath = codexConfigPath()) {
24098
24156
  STORYBLOQ_CLIENT = "codex"
24099
24157
  `;
24100
24158
  }
24101
- const tmpPath = `${configPath}.${process.pid}.tmp`;
24102
24159
  try {
24103
- await mkdir8(dirname9(configPath), { recursive: true });
24104
- await writeFile5(tmpPath, next, "utf-8");
24105
- await rename4(tmpPath, configPath);
24160
+ await atomicWriteFollowingSymlink(configPath, next);
24106
24161
  } catch (err) {
24107
- try {
24108
- await unlink5(tmpPath);
24109
- } catch {
24110
- }
24111
24162
  const message = err instanceof Error ? err.message : String(err);
24112
24163
  process.stderr.write(`Failed to write Codex config.toml: ${message}
24113
24164
  `);
@@ -24154,16 +24205,9 @@ async function migrateCodexHookVariants(hookType, acceptedRests, newCommand, hoo
24154
24205
  removedCount += before - g.hooks.length;
24155
24206
  }
24156
24207
  if (removedCount === 0) return 0;
24157
- const tmpPath = `${hooksPath}.${process.pid}.tmp`;
24158
24208
  try {
24159
- await mkdir8(dirname9(hooksPath), { recursive: true });
24160
- await writeFile5(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
24161
- await rename4(tmpPath, hooksPath);
24209
+ await atomicWriteFollowingSymlink(hooksPath, JSON.stringify(settings, null, 2) + "\n");
24162
24210
  } catch {
24163
- try {
24164
- await unlink5(tmpPath);
24165
- } catch {
24166
- }
24167
24211
  return 0;
24168
24212
  }
24169
24213
  return removedCount;
@@ -24239,16 +24283,9 @@ async function registerCodexHook(hookType, hookEntry, hooksPath = codexHooksPath
24239
24283
  if (targetMatcher) group.matcher = targetMatcher;
24240
24284
  hookArray.push(group);
24241
24285
  }
24242
- const tmpPath = `${hooksPath}.${process.pid}.tmp`;
24243
24286
  try {
24244
- await mkdir8(dirname9(hooksPath), { recursive: true });
24245
- await writeFile5(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
24246
- await rename4(tmpPath, hooksPath);
24287
+ await atomicWriteFollowingSymlink(hooksPath, JSON.stringify(settings, null, 2) + "\n");
24247
24288
  } catch (err) {
24248
- try {
24249
- await unlink5(tmpPath);
24250
- } catch {
24251
- }
24252
24289
  const message = err instanceof Error ? err.message : String(err);
24253
24290
  process.stderr.write(`Failed to write Codex hooks.json: ${message}
24254
24291
  `);
@@ -24276,8 +24313,14 @@ async function handleSetupCodex(options = {}) {
24276
24313
  log(` ${writtenFiles.join(" + ")} written`);
24277
24314
  const compatSkillDir = join53(codexHome(), "skills", "story");
24278
24315
  if (existsSync24(join53(compatSkillDir, "SKILL.md"))) {
24279
- const compatFiles = await copyDirRecursive(srcSkillDir, compatSkillDir);
24280
- log(` Refreshed existing Codex skill copy at ${compatSkillDir}/ (${compatFiles.length} files)`);
24316
+ try {
24317
+ const compatFiles = await copyDirRecursive(srcSkillDir, compatSkillDir);
24318
+ log(` Refreshed existing Codex skill copy at ${compatSkillDir}/ (${compatFiles.length} files)`);
24319
+ } catch (err) {
24320
+ const msg = err instanceof Error ? err.message : String(err);
24321
+ process.stderr.write(`Warning: Codex skill copy refresh failed: ${msg}
24322
+ `);
24323
+ }
24281
24324
  }
24282
24325
  let cliInPath = false;
24283
24326
  try {
@@ -24400,6 +24443,7 @@ var init_setup_skill = __esm({
24400
24443
  "src/cli/commands/setup-skill.ts"() {
24401
24444
  "use strict";
24402
24445
  init_esm_shims();
24446
+ init_symlink_write();
24403
24447
  init_hook_migration();
24404
24448
  LEGACY_PRECOMPACT_HOOK_COMMAND = "storybloq snapshot --quiet";
24405
24449
  CODEX_READ_ONLY_APPROVAL_TOOLS = [
@@ -25347,7 +25391,7 @@ function renderRepairSummary(toSupersede, skippedPreLock, mutationSkipped, resul
25347
25391
  return lines.join("\n");
25348
25392
  }
25349
25393
  async function readOneLine(stream) {
25350
- return new Promise((resolve15) => {
25394
+ return new Promise((resolve16) => {
25351
25395
  let buf = "";
25352
25396
  let done = false;
25353
25397
  const onData = (chunk) => {
@@ -25358,7 +25402,7 @@ async function readOneLine(stream) {
25358
25402
  done = true;
25359
25403
  stream.removeListener("data", onData);
25360
25404
  stream.removeListener("end", onEnd);
25361
- resolve15(buf.slice(0, nl));
25405
+ resolve16(buf.slice(0, nl));
25362
25406
  }
25363
25407
  };
25364
25408
  const onEnd = () => {
@@ -25366,7 +25410,7 @@ async function readOneLine(stream) {
25366
25410
  done = true;
25367
25411
  stream.removeListener("data", onData);
25368
25412
  stream.removeListener("end", onEnd);
25369
- resolve15(buf);
25413
+ resolve16(buf);
25370
25414
  };
25371
25415
  stream.on("data", onData);
25372
25416
  stream.on("end", onEnd);
@@ -25572,6 +25616,220 @@ var init_session_watch = __esm({
25572
25616
  }
25573
25617
  });
25574
25618
 
25619
+ // src/feedback/github-client.ts
25620
+ async function fetchIssues(options) {
25621
+ const params = new URLSearchParams({
25622
+ state: "open",
25623
+ per_page: String(options.limit ?? 100)
25624
+ });
25625
+ if (options.category) {
25626
+ const label = CATEGORY_TO_LABEL[options.category] ?? options.category;
25627
+ params.set("labels", label);
25628
+ }
25629
+ const url = `${API_BASE}/issues?${params.toString()}`;
25630
+ let response;
25631
+ try {
25632
+ response = await fetch(url, {
25633
+ headers: {
25634
+ Accept: "application/vnd.github+json",
25635
+ "User-Agent": "storybloq-cli"
25636
+ }
25637
+ });
25638
+ } catch (err) {
25639
+ throw new FeedbackClientError(
25640
+ "network_error",
25641
+ `Failed to reach GitHub API: ${err instanceof Error ? err.message : String(err)}`
25642
+ );
25643
+ }
25644
+ if (!response.ok) {
25645
+ throw new FeedbackClientError(
25646
+ "api_error",
25647
+ `GitHub API returned ${response.status}`
25648
+ );
25649
+ }
25650
+ let data;
25651
+ try {
25652
+ data = await response.json();
25653
+ } catch {
25654
+ throw new FeedbackClientError("parse_error", "Failed to parse GitHub API response");
25655
+ }
25656
+ data = data.filter((issue) => !issue.pull_request);
25657
+ let rateLimitWarning = null;
25658
+ const remaining = response.headers.get("X-RateLimit-Remaining");
25659
+ if (remaining !== null) {
25660
+ const n = parseInt(remaining, 10);
25661
+ if (!isNaN(n) && n < 10) {
25662
+ rateLimitWarning = `GitHub API rate limit low: ${n} requests remaining`;
25663
+ }
25664
+ }
25665
+ return { issues: data, rateLimitWarning };
25666
+ }
25667
+ var REPO, API_BASE, CATEGORY_TO_LABEL, FeedbackClientError;
25668
+ var init_github_client = __esm({
25669
+ "src/feedback/github-client.ts"() {
25670
+ "use strict";
25671
+ init_esm_shims();
25672
+ REPO = "Storybloq/storybloq";
25673
+ API_BASE = `https://api.github.com/repos/${REPO}`;
25674
+ CATEGORY_TO_LABEL = {
25675
+ bug: "bug",
25676
+ feature: "enhancement",
25677
+ idea: "idea"
25678
+ };
25679
+ FeedbackClientError = class extends Error {
25680
+ code;
25681
+ constructor(code, message) {
25682
+ super(message);
25683
+ this.name = "FeedbackClientError";
25684
+ this.code = code;
25685
+ }
25686
+ };
25687
+ }
25688
+ });
25689
+
25690
+ // src/cli/commands/feedback.ts
25691
+ var feedback_exports = {};
25692
+ __export(feedback_exports, {
25693
+ buildCreateURL: () => buildCreateURL,
25694
+ handleFeedbackCreate: () => handleFeedbackCreate,
25695
+ handleFeedbackList: () => handleFeedbackList,
25696
+ handleFeedbackOpen: () => handleFeedbackOpen,
25697
+ handleFeedbackVote: () => handleFeedbackVote,
25698
+ openBrowser: () => openBrowser
25699
+ });
25700
+ import { spawn as spawn4 } from "child_process";
25701
+ function labelToCategory(labels) {
25702
+ for (const l of labels) {
25703
+ if (l.name === "bug") return "bug";
25704
+ if (l.name === "enhancement") return "feature";
25705
+ if (l.name === "idea") return "idea";
25706
+ }
25707
+ return "-";
25708
+ }
25709
+ function relativeDate(iso) {
25710
+ const ms = Date.now() - new Date(iso).getTime();
25711
+ const mins = Math.floor(ms / 6e4);
25712
+ if (mins < 60) return `${mins}m ago`;
25713
+ const hours = Math.floor(mins / 60);
25714
+ if (hours < 24) return `${hours}h ago`;
25715
+ const days = Math.floor(hours / 24);
25716
+ return `${days}d ago`;
25717
+ }
25718
+ function openBrowser(url) {
25719
+ const platform = process.platform;
25720
+ let cmd;
25721
+ let args;
25722
+ if (platform === "darwin") {
25723
+ cmd = "open";
25724
+ args = [url];
25725
+ } else if (platform === "win32") {
25726
+ cmd = "powershell.exe";
25727
+ args = ["-NoProfile", "-Command", "Start-Process $args[0]", "-args", url];
25728
+ } else {
25729
+ cmd = "xdg-open";
25730
+ args = [url];
25731
+ }
25732
+ const child = spawn4(cmd, args, { detached: true, stdio: "ignore" });
25733
+ child.unref();
25734
+ }
25735
+ async function handleFeedbackOpen() {
25736
+ openBrowser(`${REPO_URL}/issues`);
25737
+ return { output: `Opened ${REPO_URL}/issues`, exitCode: ExitCode.OK };
25738
+ }
25739
+ async function handleFeedbackList(options, format) {
25740
+ try {
25741
+ const result = await fetchIssues(options);
25742
+ if (format === "json") {
25743
+ return {
25744
+ output: JSON.stringify(successEnvelope({
25745
+ issues: result.issues.map((i) => ({
25746
+ number: i.number,
25747
+ title: i.title,
25748
+ category: labelToCategory(i.labels),
25749
+ votes: i.reactions["+1"],
25750
+ date: i.created_at,
25751
+ url: i.html_url
25752
+ })),
25753
+ rateLimitWarning: result.rateLimitWarning
25754
+ }), null, 2),
25755
+ exitCode: ExitCode.OK
25756
+ };
25757
+ }
25758
+ if (result.issues.length === 0) {
25759
+ let msg = "No feedback found.";
25760
+ if (result.rateLimitWarning) msg += `
25761
+
25762
+ ${result.rateLimitWarning}`;
25763
+ return { output: msg, exitCode: ExitCode.OK };
25764
+ }
25765
+ const rows = result.issues.map(
25766
+ (i) => `| ${i.number} | ${i.title} | ${labelToCategory(i.labels)} | ${i.reactions["+1"]} | ${relativeDate(i.created_at)} |`
25767
+ );
25768
+ let output = "# Community Feedback\n\n";
25769
+ output += "| # | Title | Category | Votes | Date |\n";
25770
+ output += "|---|-------|----------|-------|------|\n";
25771
+ output += rows.join("\n");
25772
+ if (result.rateLimitWarning) {
25773
+ output += `
25774
+
25775
+ > ${result.rateLimitWarning}`;
25776
+ }
25777
+ return { output, exitCode: ExitCode.OK };
25778
+ } catch (err) {
25779
+ if (err instanceof FeedbackClientError) {
25780
+ return { output: `Error: ${err.message}`, exitCode: ExitCode.USER_ERROR };
25781
+ }
25782
+ throw err;
25783
+ }
25784
+ }
25785
+ function buildCreateURL(title, category, body) {
25786
+ const params = new URLSearchParams();
25787
+ params.set("title", title);
25788
+ const version2 = process.env.npm_package_version ?? "unknown";
25789
+ const footer = `
25790
+
25791
+ ---
25792
+ *Submitted via \`storybloq feedback create\`*
25793
+ CLI version: ${version2}
25794
+ Platform: ${process.platform}
25795
+ Node: ${process.version}`;
25796
+ params.set("body", (body ?? "") + footer);
25797
+ if (category) {
25798
+ const label = CATEGORY_TO_LABEL[category] ?? category;
25799
+ params.set("labels", label);
25800
+ }
25801
+ return `${REPO_URL}/issues/new?${params.toString()}`;
25802
+ }
25803
+ async function handleFeedbackCreate(title, category, body) {
25804
+ const trimmed = title.trim();
25805
+ if (!trimmed) {
25806
+ return { output: "Error: Title is required", exitCode: ExitCode.USER_ERROR };
25807
+ }
25808
+ const url = buildCreateURL(trimmed, category, body);
25809
+ openBrowser(url);
25810
+ return { output: `Opening browser to create feedback...
25811
+ ${url}`, exitCode: ExitCode.OK };
25812
+ }
25813
+ async function handleFeedbackVote(issueNumber) {
25814
+ if (!issueNumber || issueNumber <= 0) {
25815
+ return { output: "Error: Issue number must be a positive integer", exitCode: ExitCode.USER_ERROR };
25816
+ }
25817
+ const url = `${REPO_URL}/issues/${issueNumber}`;
25818
+ openBrowser(url);
25819
+ return { output: `Opening issue #${issueNumber} to vote...
25820
+ ${url}`, exitCode: ExitCode.OK };
25821
+ }
25822
+ var REPO_URL;
25823
+ var init_feedback = __esm({
25824
+ "src/cli/commands/feedback.ts"() {
25825
+ "use strict";
25826
+ init_esm_shims();
25827
+ init_github_client();
25828
+ init_output_formatter();
25829
+ REPO_URL = "https://github.com/Storybloq/storybloq";
25830
+ }
25831
+ });
25832
+
25575
25833
  // src/cli/register.ts
25576
25834
  var register_exports = {};
25577
25835
  __export(register_exports, {
@@ -25580,6 +25838,7 @@ __export(register_exports, {
25580
25838
  registerConfigCommand: () => registerConfigCommand,
25581
25839
  registerDispatchCommand: () => registerDispatchCommand,
25582
25840
  registerExportCommand: () => registerExportCommand,
25841
+ registerFeedbackCommand: () => registerFeedbackCommand,
25583
25842
  registerHandoverCommand: () => registerHandoverCommand,
25584
25843
  registerHookStatusCommand: () => registerHookStatusCommand,
25585
25844
  registerInitCommand: () => registerInitCommand,
@@ -28503,6 +28762,82 @@ function registerSessionCommand(yargs) {
28503
28762
  }
28504
28763
  );
28505
28764
  }
28765
+ function registerFeedbackCommand(yargs) {
28766
+ return yargs.command(
28767
+ "feedback [subcommand]",
28768
+ "Community feedback via GitHub Issues",
28769
+ (y) => y.command(
28770
+ "list",
28771
+ "List community feedback",
28772
+ (sub) => sub.option("category", {
28773
+ type: "string",
28774
+ choices: ["bug", "feature", "idea"],
28775
+ describe: "Filter by category"
28776
+ }).option("format", {
28777
+ type: "string",
28778
+ default: "md",
28779
+ choices: ["md", "json"],
28780
+ describe: "Output format"
28781
+ }),
28782
+ async (argv) => {
28783
+ const { handleFeedbackList: handleFeedbackList2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
28784
+ const result = await handleFeedbackList2(
28785
+ { category: argv.category },
28786
+ argv.format
28787
+ );
28788
+ process.stdout.write(result.output + "\n");
28789
+ if (result.exitCode) process.exitCode = result.exitCode;
28790
+ }
28791
+ ).command(
28792
+ "create",
28793
+ "Create new feedback (opens browser)",
28794
+ (sub) => sub.option("title", {
28795
+ type: "string",
28796
+ demandOption: true,
28797
+ describe: "Feedback title"
28798
+ }).option("category", {
28799
+ type: "string",
28800
+ choices: ["bug", "feature", "idea"],
28801
+ describe: "Feedback category"
28802
+ }).option("body", {
28803
+ type: "string",
28804
+ describe: "Feedback body"
28805
+ }),
28806
+ async (argv) => {
28807
+ const { handleFeedbackCreate: handleFeedbackCreate2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
28808
+ const result = await handleFeedbackCreate2(
28809
+ argv.title,
28810
+ argv.category,
28811
+ argv.body
28812
+ );
28813
+ process.stdout.write(result.output + "\n");
28814
+ if (result.exitCode) process.exitCode = result.exitCode;
28815
+ }
28816
+ ).command(
28817
+ "vote <number>",
28818
+ "Vote on feedback (opens browser)",
28819
+ (sub) => sub.positional("number", {
28820
+ type: "number",
28821
+ demandOption: true,
28822
+ describe: "Issue number"
28823
+ }),
28824
+ async (argv) => {
28825
+ const { handleFeedbackVote: handleFeedbackVote2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
28826
+ const result = await handleFeedbackVote2(argv.number);
28827
+ process.stdout.write(result.output + "\n");
28828
+ if (result.exitCode) process.exitCode = result.exitCode;
28829
+ }
28830
+ ),
28831
+ async (argv) => {
28832
+ if (!argv.subcommand || argv.subcommand === "feedback") {
28833
+ const { handleFeedbackOpen: handleFeedbackOpen2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
28834
+ const result = await handleFeedbackOpen2();
28835
+ process.stdout.write(result.output + "\n");
28836
+ if (result.exitCode) process.exitCode = result.exitCode;
28837
+ }
28838
+ }
28839
+ );
28840
+ }
28506
28841
  var init_register = __esm({
28507
28842
  "src/cli/register.ts"() {
28508
28843
  "use strict";
@@ -28605,9 +28940,10 @@ async function runCli() {
28605
28940
  registerSessionCommand: registerSessionCommand2,
28606
28941
  registerRepairCommand: registerRepairCommand2,
28607
28942
  registerMigrateCommand: registerMigrateCommand2,
28608
- registerNodeCommand: registerNodeCommand2
28943
+ registerNodeCommand: registerNodeCommand2,
28944
+ registerFeedbackCommand: registerFeedbackCommand2
28609
28945
  } = await Promise.resolve().then(() => (init_register(), register_exports));
28610
- const version2 = "1.4.2";
28946
+ const version2 = "1.4.3";
28611
28947
  const { preCommandHousekeeping: preCommandHousekeeping2 } = await Promise.resolve().then(() => (init_housekeeping(), housekeeping_exports));
28612
28948
  await preCommandHousekeeping2(version2);
28613
28949
  class HandledError extends Error {
@@ -28657,6 +28993,7 @@ async function runCli() {
28657
28993
  cli = registerConfigCommand2(cli);
28658
28994
  cli = registerNodeCommand2(cli);
28659
28995
  cli = registerSessionCommand2(cli);
28996
+ cli = registerFeedbackCommand2(cli);
28660
28997
  function handleUnexpectedError(err) {
28661
28998
  if (err instanceof HandledError) return;
28662
28999
  const message = err instanceof Error ? err.message : String(err);
package/dist/index.d.ts CHANGED
@@ -1503,16 +1503,49 @@ declare const SnapshotV1Schema: z.ZodObject<{
1503
1503
  file: z.ZodString;
1504
1504
  message: z.ZodString;
1505
1505
  }, "strip", z.ZodTypeAny, {
1506
- message: string;
1507
1506
  type: string;
1507
+ message: string;
1508
1508
  file: string;
1509
1509
  }, {
1510
- message: string;
1511
1510
  type: string;
1511
+ message: string;
1512
1512
  file: string;
1513
1513
  }>, "many">>;
1514
1514
  gitHead: z.ZodOptional<z.ZodString>;
1515
1515
  }, "strip", z.ZodTypeAny, {
1516
+ version: 1;
1517
+ config: {
1518
+ version: number;
1519
+ type: string;
1520
+ language: string;
1521
+ project: string;
1522
+ features: {
1523
+ issues: boolean;
1524
+ tickets: boolean;
1525
+ handovers: boolean;
1526
+ roadmap: boolean;
1527
+ reviews: boolean;
1528
+ } & {
1529
+ [k: string]: unknown;
1530
+ };
1531
+ orchestrator?: string | undefined;
1532
+ nodes?: Record<string, unknown> | undefined;
1533
+ federation?: Record<string, unknown> | undefined;
1534
+ schemaVersion?: number | undefined;
1535
+ recipe?: string | undefined;
1536
+ recipeOverrides?: {
1537
+ maxTicketsPerSession?: number | undefined;
1538
+ compactThreshold?: string | undefined;
1539
+ reviewBackends?: string[] | undefined;
1540
+ codexReviewBackends?: string[] | undefined;
1541
+ handoverInterval?: number | undefined;
1542
+ stages?: Record<string, Record<string, unknown>> | undefined;
1543
+ branchStrategy?: "none" | "per-ticket" | undefined;
1544
+ maxParallelAgents?: number | undefined;
1545
+ } | undefined;
1546
+ } & {
1547
+ [k: string]: unknown;
1548
+ };
1516
1549
  issues: z.objectOutputType<{
1517
1550
  id: z.ZodString;
1518
1551
  title: z.ZodString;
@@ -1550,8 +1583,8 @@ declare const SnapshotV1Schema: z.ZodObject<{
1550
1583
  crossNodeBlockedBy: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1551
1584
  }, z.ZodTypeAny, "passthrough">[];
1552
1585
  roadmap: {
1553
- title: string;
1554
1586
  date: string;
1587
+ title: string;
1555
1588
  phases: z.objectOutputType<{
1556
1589
  id: z.ZodString;
1557
1590
  label: z.ZodString;
@@ -1569,7 +1602,6 @@ declare const SnapshotV1Schema: z.ZodObject<{
1569
1602
  } & {
1570
1603
  [k: string]: unknown;
1571
1604
  };
1572
- version: 1;
1573
1605
  project: string;
1574
1606
  notes: z.objectOutputType<{
1575
1607
  id: z.ZodString;
@@ -1594,11 +1626,21 @@ declare const SnapshotV1Schema: z.ZodObject<{
1594
1626
  supersedes: z.ZodNullable<z.ZodString>;
1595
1627
  status: z.ZodEnum<["active", "deprecated", "superseded"]>;
1596
1628
  }, z.ZodTypeAny, "passthrough">[];
1597
- config: {
1629
+ createdAt: string;
1630
+ handoverFilenames: string[];
1631
+ warnings?: {
1598
1632
  type: string;
1633
+ message: string;
1634
+ file: string;
1635
+ }[] | undefined;
1636
+ gitHead?: string | undefined;
1637
+ }, {
1638
+ version: 1;
1639
+ config: {
1599
1640
  version: number;
1600
- project: string;
1641
+ type: string;
1601
1642
  language: string;
1643
+ project: string;
1602
1644
  features: {
1603
1645
  issues: boolean;
1604
1646
  tickets: boolean;
@@ -1626,15 +1668,6 @@ declare const SnapshotV1Schema: z.ZodObject<{
1626
1668
  } & {
1627
1669
  [k: string]: unknown;
1628
1670
  };
1629
- createdAt: string;
1630
- handoverFilenames: string[];
1631
- warnings?: {
1632
- message: string;
1633
- type: string;
1634
- file: string;
1635
- }[] | undefined;
1636
- gitHead?: string | undefined;
1637
- }, {
1638
1671
  issues: z.objectInputType<{
1639
1672
  id: z.ZodString;
1640
1673
  title: z.ZodString;
@@ -1672,8 +1705,8 @@ declare const SnapshotV1Schema: z.ZodObject<{
1672
1705
  crossNodeBlockedBy: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1673
1706
  }, z.ZodTypeAny, "passthrough">[];
1674
1707
  roadmap: {
1675
- title: string;
1676
1708
  date: string;
1709
+ title: string;
1677
1710
  phases: z.objectInputType<{
1678
1711
  id: z.ZodString;
1679
1712
  label: z.ZodString;
@@ -1691,40 +1724,7 @@ declare const SnapshotV1Schema: z.ZodObject<{
1691
1724
  } & {
1692
1725
  [k: string]: unknown;
1693
1726
  };
1694
- version: 1;
1695
1727
  project: string;
1696
- config: {
1697
- type: string;
1698
- version: number;
1699
- project: string;
1700
- language: string;
1701
- features: {
1702
- issues: boolean;
1703
- tickets: boolean;
1704
- handovers: boolean;
1705
- roadmap: boolean;
1706
- reviews: boolean;
1707
- } & {
1708
- [k: string]: unknown;
1709
- };
1710
- orchestrator?: string | undefined;
1711
- nodes?: Record<string, unknown> | undefined;
1712
- federation?: Record<string, unknown> | undefined;
1713
- schemaVersion?: number | undefined;
1714
- recipe?: string | undefined;
1715
- recipeOverrides?: {
1716
- maxTicketsPerSession?: number | undefined;
1717
- compactThreshold?: string | undefined;
1718
- reviewBackends?: string[] | undefined;
1719
- codexReviewBackends?: string[] | undefined;
1720
- handoverInterval?: number | undefined;
1721
- stages?: Record<string, Record<string, unknown>> | undefined;
1722
- branchStrategy?: "none" | "per-ticket" | undefined;
1723
- maxParallelAgents?: number | undefined;
1724
- } | undefined;
1725
- } & {
1726
- [k: string]: unknown;
1727
- };
1728
1728
  createdAt: string;
1729
1729
  notes?: z.objectInputType<{
1730
1730
  id: z.ZodString;
@@ -1750,8 +1750,8 @@ declare const SnapshotV1Schema: z.ZodObject<{
1750
1750
  status: z.ZodEnum<["active", "deprecated", "superseded"]>;
1751
1751
  }, z.ZodTypeAny, "passthrough">[] | undefined;
1752
1752
  warnings?: {
1753
- message: string;
1754
1753
  type: string;
1754
+ message: string;
1755
1755
  file: string;
1756
1756
  }[] | undefined;
1757
1757
  handoverFilenames?: string[] | undefined;
package/dist/index.js CHANGED
@@ -2453,7 +2453,7 @@ async function initProject(root, options) {
2453
2453
  warnings
2454
2454
  };
2455
2455
  }
2456
- var STORY_GITIGNORE_ENTRIES = ["snapshots/", "status.json", "sessions/"];
2456
+ var STORY_GITIGNORE_ENTRIES = ["snapshots/", "status.json", "sessions/", "federation-cache.json"];
2457
2457
  async function ensureGitignoreEntries(gitignorePath, entries) {
2458
2458
  let existing = "";
2459
2459
  try {
package/dist/mcp.js CHANGED
@@ -6064,7 +6064,7 @@ async function initProject(root, options) {
6064
6064
  warnings
6065
6065
  };
6066
6066
  }
6067
- var STORY_GITIGNORE_ENTRIES = ["snapshots/", "status.json", "sessions/"];
6067
+ var STORY_GITIGNORE_ENTRIES = ["snapshots/", "status.json", "sessions/", "federation-cache.json"];
6068
6068
  async function ensureGitignoreEntries(gitignorePath, entries) {
6069
6069
  let existing = "";
6070
6070
  try {
@@ -16743,7 +16743,7 @@ function getInstalledVersion() {
16743
16743
  }
16744
16744
  }
16745
16745
  function getRunningVersion() {
16746
- return "1.4.2";
16746
+ return "1.4.3";
16747
16747
  }
16748
16748
 
16749
16749
  // src/autonomous/guide.ts
@@ -18753,7 +18753,7 @@ function registerAllTools(server, pinnedRoot) {
18753
18753
  const result = await runMcpReadTool(pinnedRoot, handleStatus);
18754
18754
  try {
18755
18755
  const { readUpdateCacheSync: readUpdateCacheSync2, refreshUpdateCacheInBackground: refreshUpdateCacheInBackground2 } = await Promise.resolve().then(() => (init_update_check(), update_check_exports));
18756
- const running = "1.4.2";
18756
+ const running = "1.4.3";
18757
18757
  const info = readUpdateCacheSync2(running);
18758
18758
  refreshUpdateCacheInBackground2();
18759
18759
  if (info?.updateAvailable && result.content[0]?.type === "text") {
@@ -20112,7 +20112,7 @@ async function trimFailedDirectory(inboxPath) {
20112
20112
  var ENV_VAR2 = "STORYBLOQ_PROJECT_ROOT";
20113
20113
  var LEGACY_ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
20114
20114
  var CONFIG_PATH2 = ".story/config.json";
20115
- var version = "1.4.2";
20115
+ var version = "1.4.3";
20116
20116
  function tryDiscoverRoot() {
20117
20117
  const envRoot = process.env[ENV_VAR2] ?? process.env[LEGACY_ENV_VAR2];
20118
20118
  const envName = process.env[ENV_VAR2] ? ENV_VAR2 : LEGACY_ENV_VAR2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybloq/storybloq",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "license": "PolyForm-Noncommercial-1.0.0",
5
5
  "description": "Project memory for Claude Code. Storybloq stores tickets, issues, handovers, and lessons in a .story/ folder inside your repo so every session starts where the last one left off. Pairs with the Storybloq Mac app on the App Store.",
6
6
  "homepage": "https://storybloq.com",