claude-code-session-manager 0.76.0 → 0.77.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.
Files changed (123) hide show
  1. package/dist/assets/{AgentLibrary-CBx9l4zN.js → AgentLibrary-B2ie8bbw.js} +2 -2
  2. package/dist/assets/{DataModel-Bf0EIE_t.js → DataModel-BIJPYw32.js} +1 -1
  3. package/dist/assets/{History-CpdtWhC8.js → History-CeY6dk9S.js} +2 -2
  4. package/dist/assets/{Hooks-DyUbMDmg.js → Hooks-BFH2ocKg.js} +2 -2
  5. package/dist/assets/{HostBilko-By-wIpry.js → HostBilko-36gj9wLz.js} +1 -1
  6. package/dist/assets/{Library-CQmo4QVC.js → Library-C-hBct39.js} +1 -1
  7. package/dist/assets/{ListDetail-BQMd6NOm.js → ListDetail-CNq64VWV.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-DEp43FXX.js → MarkdownEditor-Bh3qt5-1.js} +1 -1
  9. package/dist/assets/{McpServers-CLarzwqA.js → McpServers-DpGN0oyz.js} +1 -1
  10. package/dist/assets/{Memory-B0sCdIy1.js → Memory-D59hUjC4.js} +6 -6
  11. package/dist/assets/{Panel-BhWPVOCD.js → Panel-DCgbaoci.js} +1 -1
  12. package/dist/assets/{Permissions-Ddlq8T_O.js → Permissions-DAmQ0DYV.js} +2 -2
  13. package/dist/assets/{Plugins-D2oA_2Jl.js → Plugins-Dyfgn6Is.js} +2 -2
  14. package/dist/assets/{ProvenanceBadge-DgAgavUM.js → ProvenanceBadge-BiYhPO1U.js} +1 -1
  15. package/dist/assets/SaveBar-RV7B6sOh.js +1 -0
  16. package/dist/assets/Scheduler-BPaNqx1b.js +14 -0
  17. package/dist/assets/{ScopeSwitcher-C_zWEtIl.js → ScopeSwitcher-P4mdLGNU.js} +1 -1
  18. package/dist/assets/{Settings-2Vx3X5SI.js → Settings-BL4vf5aX.js} +1 -1
  19. package/dist/assets/{SkillReferenceGraph-BDEUjlTQ.js → SkillReferenceGraph-BRBDyi1_.js} +1 -1
  20. package/dist/assets/{Skills-Cmrz_LeN.js → Skills-BV08gDUH.js} +2 -2
  21. package/dist/assets/{SystemPrompt-DVA1eYDP.js → SystemPrompt-CLftSsDw.js} +1 -1
  22. package/dist/assets/TagLibrary-Bp8jGsd5.js +1 -0
  23. package/dist/assets/{TiptapBody-DmPc3amD.js → TiptapBody-jCpuB6E5.js} +1 -1
  24. package/dist/assets/{Toggle-zfd5LJkK.js → Toggle-D2paA1xf.js} +1 -1
  25. package/dist/assets/{index-B_4PNh9T.js → index-BDRSqBl3.js} +175 -175
  26. package/dist/assets/{index-DIjnPkRN.css → index-CYhdtisq.css} +1 -1
  27. package/dist/assets/{settingsSchema-B9es6fdA.js → settingsSchema-6IOLjZZN.js} +1 -1
  28. package/dist/index.html +2 -2
  29. package/package.json +8 -2
  30. package/plugins/session-manager-dev/skills/develop/standards.md +1 -1
  31. package/scripts/project-pages-logic/dist/logic.cjs +4709 -0
  32. package/scripts/render-project-pages/dist/renderer.cjs +18900 -0
  33. package/scripts/render-project-pages.cjs +70 -0
  34. package/scripts/scheduler-mcp-server.cjs +115 -1
  35. package/scripts/validate-project-pages-summary.cjs +62 -0
  36. package/src/main/__tests__/agentModelResolve.test.cjs +66 -0
  37. package/src/main/__tests__/health-delegation-chain.test.cjs +2 -1
  38. package/src/main/__tests__/prdAgentType.test.cjs +103 -0
  39. package/src/main/__tests__/prdCreate.test.cjs +138 -0
  40. package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +117 -0
  41. package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +108 -0
  42. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +485 -0
  43. package/src/main/__tests__/projectPages.test.cjs +73 -1
  44. package/src/main/__tests__/rcaReport.test.cjs +54 -0
  45. package/src/main/__tests__/runVerify.test.cjs +94 -0
  46. package/src/main/__tests__/scheduler-autofix-select.test.cjs +43 -0
  47. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +103 -0
  48. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +10 -0
  49. package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +78 -0
  50. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +242 -0
  51. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +31 -0
  52. package/src/main/__tests__/scheduler-launch-failure.test.cjs +201 -0
  53. package/src/main/__tests__/scheduler-leftover-fields.test.cjs +52 -0
  54. package/src/main/__tests__/scheduler-looks-done.test.cjs +241 -0
  55. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +135 -0
  56. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +222 -0
  57. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +147 -0
  58. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +212 -0
  59. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +194 -0
  60. package/src/main/__tests__/seedAgentPersonas.test.cjs +75 -14
  61. package/src/main/config.cjs +4 -1
  62. package/src/main/index.cjs +8 -1
  63. package/src/main/ipcSchemas.cjs +51 -0
  64. package/src/main/lib/__tests__/childWithLog.test.cjs +78 -0
  65. package/src/main/lib/__tests__/delegationReadiness.test.cjs +152 -2
  66. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +4 -2
  67. package/src/main/lib/__tests__/fixChainDepth.test.cjs +40 -0
  68. package/src/main/lib/__tests__/gitWorktree.test.cjs +277 -4
  69. package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +153 -0
  70. package/src/main/lib/__tests__/jobWorktree.test.cjs +5 -3
  71. package/src/main/lib/__tests__/landedSinceRun.test.cjs +73 -0
  72. package/src/main/lib/__tests__/launchFailure.test.cjs +220 -0
  73. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +1 -0
  74. package/src/main/lib/__tests__/opsOwnership.test.cjs +7 -0
  75. package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +82 -0
  76. package/src/main/lib/__tests__/queueHealth.test.cjs +58 -0
  77. package/src/main/lib/__tests__/quietMachineLease.test.cjs +39 -0
  78. package/src/main/lib/__tests__/reaperHelpers.test.cjs +22 -1
  79. package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +125 -0
  80. package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +109 -0
  81. package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +71 -0
  82. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +350 -0
  83. package/src/main/lib/agentModelResolve.cjs +58 -0
  84. package/src/main/lib/childWithLog.cjs +40 -5
  85. package/src/main/lib/claudeBin.cjs +54 -1
  86. package/src/main/lib/definitionOfDone.cjs +3 -2
  87. package/src/main/lib/delegationReadiness.cjs +115 -9
  88. package/src/main/lib/epicWorktreeMint.cjs +5 -2
  89. package/src/main/lib/fixChainDepth.cjs +45 -0
  90. package/src/main/lib/gitWorktree.cjs +464 -19
  91. package/src/main/lib/jobWorktree.cjs +1 -0
  92. package/src/main/lib/landedSinceRun.cjs +55 -0
  93. package/src/main/lib/launchFailure.cjs +357 -0
  94. package/src/main/lib/mcpToolCatalog.cjs +87 -2
  95. package/src/main/lib/opsOwnership.cjs +12 -0
  96. package/src/main/lib/prdAgentType.cjs +84 -0
  97. package/src/main/lib/prdCreate.cjs +57 -1
  98. package/src/main/lib/prdDeclaredPaths.cjs +70 -0
  99. package/src/main/lib/prdFrontmatter.cjs +17 -3
  100. package/src/main/lib/projectHomeAdminRoutes.cjs +402 -0
  101. package/src/main/lib/projectPageSummarySchema.cjs +181 -0
  102. package/src/main/lib/queueHealth.cjs +38 -0
  103. package/src/main/lib/queueStore.cjs +9 -2
  104. package/src/main/lib/quietMachineLease.cjs +48 -0
  105. package/src/main/lib/rcaReport.cjs +53 -3
  106. package/src/main/lib/reaperHelpers.cjs +18 -1
  107. package/src/main/lib/scheduleJobSchema.cjs +31 -0
  108. package/src/main/lib/scheduleJobTransitions.cjs +6 -2
  109. package/src/main/lib/schedulerBatch.cjs +133 -29
  110. package/src/main/lib/schedulerConfig.cjs +19 -0
  111. package/src/main/projectPages.cjs +160 -2
  112. package/src/main/runVerify.cjs +50 -9
  113. package/src/main/scheduler/prdParser.cjs +18 -1
  114. package/src/main/scheduler.cjs +1371 -97
  115. package/src/main/seedAgentPersonas.cjs +62 -21
  116. package/src/main/templates/project-pages-catalog.json +741 -0
  117. package/src/main/templates/project-pages-pipeline.md +417 -0
  118. package/src/preload/api.d.ts +118 -2
  119. package/src/preload/index.cjs +7 -0
  120. package/src/seed/agents/project-home-builder.md +59 -0
  121. package/dist/assets/SaveBar-Qvc4Ek-H.js +0 -1
  122. package/dist/assets/Scheduler-BmYJvNzK.js +0 -14
  123. package/dist/assets/TagLibrary-DYJGAKZu.js +0 -1
@@ -28,6 +28,8 @@ const DEV_PLUGIN_ENABLED_KEY = 'session-manager-dev@session-manager';
28
28
  const SCHEDULER_MCP_SERVER_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'scheduler-mcp-server.cjs');
29
29
  const PRD_WRITE_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'hooks', 'guard-prd-writes.cjs');
30
30
  const PRD_WRITE_GUARD_MATCHER = 'Write|Edit|NotebookEdit';
31
+ const DESTRUCTIVE_GIT_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'hooks', 'guard-destructive-git.cjs');
32
+ const DESTRUCTIVE_GIT_GUARD_MATCHER = 'Bash';
31
33
  const LIVE_PROBE_TIMEOUT_MS = 10_000;
32
34
  const LIVE_PROBE_TTL_MS = 60_000;
33
35
  const REQUIRED_LIVE_TOOLS = ['scheduler_create_prd', 'session_manager_help'];
@@ -341,13 +343,15 @@ function checkAgentPersonas({ cwd, homeDir }) {
341
343
  }
342
344
 
343
345
  /**
344
- * Pull the guard script's path out of a hook `command` string.
346
+ * Pull a guard script's path out of a hook `command` string.
345
347
  *
346
- * Commands are `node <script>` (optionally quoted). We only care about the
347
- * token naming guard-prd-writes — anything else is not this hook.
348
+ * Commands are `node <script>` (optionally quoted). `scriptBasename` names
349
+ * the exact guard file we're looking for — anything else is not that hook.
348
350
  */
349
- function extractGuardScriptPath(command) {
350
- const match = String(command).match(/(?:"([^"]*guard-prd-writes\.cjs)"|'([^']*guard-prd-writes\.cjs)'|(\S*guard-prd-writes\.cjs))/);
351
+ function extractGuardScriptPath(command, scriptBasename) {
352
+ const esc = scriptBasename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
353
+ const re = new RegExp(`(?:"([^"]*${esc})"|'([^']*${esc})'|(\\S*${esc}))`);
354
+ const match = String(command).match(re);
351
355
  if (!match) return null;
352
356
  return match[1] || match[2] || match[3] || null;
353
357
  }
@@ -375,7 +379,7 @@ function checkPrdWriteGuard({ cwd }) {
375
379
  for (const h of matcher.hooks) {
376
380
  if (typeof h?.command !== 'string' || !h.command.includes('guard-prd-writes')) continue;
377
381
  mentioned = true;
378
- const raw = extractGuardScriptPath(h.command);
382
+ const raw = extractGuardScriptPath(h.command, 'guard-prd-writes.cjs');
379
383
  if (!raw) continue;
380
384
  const abs = path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
381
385
  if (fs.existsSync(abs)) { resolvedScript = abs; break; }
@@ -483,7 +487,105 @@ async function installPrdWriteGuard({ cwd }) {
483
487
  }
484
488
 
485
489
  /**
486
- * Runs all six delegation-readiness checks for `cwd`. Every filesystem read
490
+ * `ok` must mean "a hook that will actually run", not "the settings file
491
+ * mentions guard-destructive-git somewhere" — same rationale as
492
+ * checkPrdWriteGuard above (a PreToolUse command pointing at a script that
493
+ * doesn't exist in this project exits non-zero WITHOUT code 2, a
494
+ * non-blocking error that silently guards nothing).
495
+ */
496
+ function checkDestructiveGitGuard({ cwd }) {
497
+ const settings = readJsonSafe(path.join(cwd, '.claude', 'settings.json'), null);
498
+ const preToolUse = Array.isArray(settings?.hooks?.PreToolUse) ? settings.hooks.PreToolUse : [];
499
+
500
+ let mentioned = false;
501
+ let resolvedScript = null;
502
+ for (const matcher of preToolUse) {
503
+ if (!Array.isArray(matcher?.hooks)) continue;
504
+ for (const h of matcher.hooks) {
505
+ if (typeof h?.command !== 'string' || !h.command.includes('guard-destructive-git')) continue;
506
+ mentioned = true;
507
+ const raw = extractGuardScriptPath(h.command, 'guard-destructive-git.cjs');
508
+ if (!raw) continue;
509
+ const abs = path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
510
+ if (fs.existsSync(abs)) { resolvedScript = abs; break; }
511
+ }
512
+ if (resolvedScript) break;
513
+ }
514
+
515
+ const ok = !!resolvedScript;
516
+ let detail;
517
+ if (ok) detail = `guard-destructive-git PreToolUse hook found in ${cwd}/.claude/settings.json, resolving to ${resolvedScript}`;
518
+ else if (mentioned) detail = `guard-destructive-git PreToolUse hook in ${cwd}/.claude/settings.json names a script that does not exist — it would silently guard nothing`;
519
+ else detail = `no guard-destructive-git PreToolUse hook in ${cwd}/.claude/settings.json`;
520
+
521
+ return {
522
+ id: 'destructive-git-guard',
523
+ label: 'Destructive-git guard hook installed',
524
+ ok,
525
+ detail,
526
+ fix: ok
527
+ ? null
528
+ : `Add a PreToolUse hook to ${cwd}/.claude/settings.json matching Bash that runs node ${DESTRUCTIVE_GIT_GUARD_SCRIPT}`,
529
+ fixAction: ok ? null : 'install-destructive-git-guard',
530
+ };
531
+ }
532
+
533
+ /**
534
+ * Install the destructive-git guard into `<cwd>/.claude/settings.json`.
535
+ * Same reference-not-vendor rationale, and the same merge-into-existing-
536
+ * hooks-block / repair-in-place / idempotent behaviour as installPrdWriteGuard
537
+ * above — see that function's header. The one difference is the matcher
538
+ * (`Bash`, not `Write|Edit|NotebookEdit`), so this lands as its own
539
+ * `PreToolUse` entry rather than sharing installPrdWriteGuard's.
540
+ */
541
+ async function installDestructiveGitGuard({ cwd }) {
542
+ const settingsPath = path.join(cwd, '.claude', 'settings.json');
543
+ addAllowedRoot(cwd);
544
+
545
+ const existing = fs.existsSync(settingsPath) ? readJsonSafe(settingsPath, undefined) : {};
546
+ if (existing === undefined) {
547
+ return { ok: false, action: 'error', error: `${settingsPath} is not valid JSON — fix it by hand before installing the guard` };
548
+ }
549
+ const settings = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
550
+
551
+ const command = `node ${DESTRUCTIVE_GIT_GUARD_SCRIPT}`;
552
+ const hooks = (settings.hooks && typeof settings.hooks === 'object') ? settings.hooks : {};
553
+ const preToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse.slice() : [];
554
+
555
+ if (checkDestructiveGitGuard({ cwd }).ok) {
556
+ return { ok: true, action: 'already-installed', settingsPath, command };
557
+ }
558
+
559
+ let repaired = false;
560
+ for (const matcher of preToolUse) {
561
+ if (!Array.isArray(matcher?.hooks)) continue;
562
+ for (const h of matcher.hooks) {
563
+ if (typeof h?.command === 'string' && h.command.includes('guard-destructive-git')) {
564
+ h.command = command;
565
+ h.type = 'command';
566
+ repaired = true;
567
+ }
568
+ }
569
+ }
570
+
571
+ if (!repaired) {
572
+ const target = preToolUse.find((m) => m?.matcher === DESTRUCTIVE_GIT_GUARD_MATCHER);
573
+ if (target) {
574
+ target.hooks = Array.isArray(target.hooks) ? target.hooks : [];
575
+ target.hooks.push({ type: 'command', command });
576
+ } else {
577
+ preToolUse.push({ matcher: DESTRUCTIVE_GIT_GUARD_MATCHER, hooks: [{ type: 'command', command }] });
578
+ }
579
+ }
580
+
581
+ const next = { ...settings, hooks: { ...hooks, PreToolUse: preToolUse } };
582
+ await writeJson(settingsPath, next);
583
+
584
+ return { ok: true, action: repaired ? 'repaired' : 'installed', settingsPath, command };
585
+ }
586
+
587
+ /**
588
+ * Runs all seven delegation-readiness checks for `cwd`. Every filesystem read
487
589
  * is wrapped (readJsonSafe / try-catch) so a missing or unparseable file
488
590
  * yields ok:false with a detail, never a thrown exception. Async because
489
591
  * scheduler-mcp-live genuinely spawns a process and waits on it (bounded by
@@ -496,8 +598,8 @@ async function checkDelegationReadiness({ cwd, homeDir = os.homedir() }) {
496
598
  const schedulerMcpLiveCheck = await checkSchedulerMcpLive({ cwd, homeDir, schedulerMcpCheck });
497
599
 
498
600
  // `fixAction: null` / `warn: false` are the defaults — only a check with a
499
- // sanctioned one-press installer overrides fixAction (today: prd-write-guard),
500
- // and only scheduler-mcp-project-duplicate ever sets warn.
601
+ // sanctioned one-press installer overrides fixAction (today: prd-write-guard,
602
+ // destructive-git-guard), and only scheduler-mcp-project-duplicate ever sets warn.
501
603
  const checks = [
502
604
  schedulerMcpCheck,
503
605
  schedulerMcpLiveCheck,
@@ -505,6 +607,7 @@ async function checkDelegationReadiness({ cwd, homeDir = os.homedir() }) {
505
607
  checkDevPlugin({ homeDir }),
506
608
  checkAgentPersonas({ cwd, homeDir }),
507
609
  checkPrdWriteGuard({ cwd }),
610
+ checkDestructiveGitGuard({ cwd }),
508
611
  ].map((c) => ({ fixAction: null, warn: false, ...c }));
509
612
 
510
613
  return {
@@ -516,8 +619,11 @@ async function checkDelegationReadiness({ cwd, homeDir = os.homedir() }) {
516
619
  module.exports = {
517
620
  checkDelegationReadiness,
518
621
  installPrdWriteGuard,
622
+ installDestructiveGitGuard,
519
623
  probeSchedulerMcpLive,
520
624
  clearLiveProbeCache,
521
625
  PRD_WRITE_GUARD_SCRIPT,
522
626
  PRD_WRITE_GUARD_MATCHER,
627
+ DESTRUCTIVE_GIT_GUARD_SCRIPT,
628
+ DESTRUCTIVE_GIT_GUARD_MATCHER,
523
629
  };
@@ -13,8 +13,11 @@
13
13
  * that can only run main-process side, so approveProposed fires this IPC
14
14
  * call fire-and-forget and patches `worktree` onto the session once it
15
15
  * resolves — the transition itself is never blocked or delayed by it, and a
16
- * failure (not a repo / dirty base tree / disabled / cap reached) simply
17
- * leaves `worktree` unset, exactly as if this call had never been made.
16
+ * failure (not a repo / disabled / cap reached / carry-over of a dirty base
17
+ * tree's WIP failed) simply leaves `worktree` unset, exactly as if this call
18
+ * had never been made. A dirty base tree itself no longer disables
19
+ * isolation — its outstanding diff is carried into the fresh worktree
20
+ * instead (gitWorktree.cjs's createWorktree).
18
21
  *
19
22
  * Mirrors promptSessionsCreateEpic.cjs's shape: `validatePath(cwd)` closes
20
23
  * the same "arbitrary renderer-supplied cwd" gap that handler documents,
@@ -0,0 +1,45 @@
1
+ /**
2
+ * fixChainDepth.cjs — pure slug-inspection helpers for the fix-chain depth
3
+ * guard (PRD 1113). Generalizes scheduler.cjs's `isFixPlanSlug` (`^\d+-fix-`)
4
+ * into a counter: how many CONSECUTIVE '-fix-' segments immediately follow
5
+ * the leading `NN-` prefix. Only a run starting right at the prefix counts —
6
+ * a later segment that happens to read 'fix' (e.g.
7
+ * '13-fix-loop-extraction-and-round-trip', where 'loop' breaks the run right
8
+ * after the first 'fix') does not extend the count, and a segment that only
9
+ * contains 'fix' as a substring (e.g. '113-prefix-foo') never matches at all
10
+ * since segments are compared for exact equality after splitting on '-'.
11
+ *
12
+ * No filesystem access, no scheduler.cjs dependency — safe to require from
13
+ * lib/prdCreate.cjs without pulling in the scheduler module graph.
14
+ */
15
+ 'use strict';
16
+
17
+ function fixChainDepthOf(slug) {
18
+ const rest = String(slug).replace(/^\d+-/, '');
19
+ const segments = rest.split('-');
20
+ let depth = 0;
21
+ for (const seg of segments) {
22
+ if (seg !== 'fix') break;
23
+ depth += 1;
24
+ }
25
+ return depth;
26
+ }
27
+
28
+ /**
29
+ * Strips the leading consecutive '-fix-' chain a slug carries, returning the
30
+ * base slug the chain descends from — e.g. '113-fix-fix-foo' -> '113-foo'.
31
+ * Used only for error messages (naming what actually failed to close).
32
+ */
33
+ function baseSlugOf(slug) {
34
+ const str = String(slug);
35
+ const prefixMatch = str.match(/^(\d+)-/);
36
+ const prefix = prefixMatch ? prefixMatch[1] : '';
37
+ const rest = str.replace(/^\d+-/, '');
38
+ const segments = rest.split('-');
39
+ let i = 0;
40
+ while (i < segments.length && segments[i] === 'fix') i += 1;
41
+ const remainder = segments.slice(i).join('-');
42
+ return prefix ? `${prefix}-${remainder}` : remainder;
43
+ }
44
+
45
+ module.exports = { fixChainDepthOf, baseSlugOf };