claude-code-session-manager 0.75.3 → 0.76.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 (101) hide show
  1. package/dist/assets/{AgentLibrary-CzQqcObq.js → AgentLibrary-CBx9l4zN.js} +1 -1
  2. package/dist/assets/{DataModel-Bj_WlLz8.js → DataModel-Bf0EIE_t.js} +1 -1
  3. package/dist/assets/{History-DnSi_OHm.js → History-CpdtWhC8.js} +1 -1
  4. package/dist/assets/{Hooks-0BB0dp3S.js → Hooks-DyUbMDmg.js} +1 -1
  5. package/dist/assets/{HostBilko-DHpwwsLQ.js → HostBilko-By-wIpry.js} +1 -1
  6. package/dist/assets/{Library-CaJVqVvi.js → Library-CQmo4QVC.js} +1 -1
  7. package/dist/assets/{ListDetail-C1W2HmC2.js → ListDetail-BQMd6NOm.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-5Ob9FW3z.js → MarkdownEditor-DEp43FXX.js} +1 -1
  9. package/dist/assets/{McpServers-JxCSfm1S.js → McpServers-CLarzwqA.js} +1 -1
  10. package/dist/assets/{Memory-BDeqlqwH.js → Memory-B0sCdIy1.js} +1 -1
  11. package/dist/assets/{Panel-Dh9ZHuEj.js → Panel-BhWPVOCD.js} +1 -1
  12. package/dist/assets/{Permissions-DXy-CbEY.js → Permissions-Ddlq8T_O.js} +1 -1
  13. package/dist/assets/{Plugins-_n1Iuc8T.js → Plugins-D2oA_2Jl.js} +2 -2
  14. package/dist/assets/{ProvenanceBadge-BP_evfxE.js → ProvenanceBadge-DgAgavUM.js} +1 -1
  15. package/dist/assets/{SaveBar-D-gCUx4n.js → SaveBar-Qvc4Ek-H.js} +1 -1
  16. package/dist/assets/{Scheduler-Bpd4OGju.js → Scheduler-BmYJvNzK.js} +1 -1
  17. package/dist/assets/{ScopeSwitcher-CAWzM6RI.js → ScopeSwitcher-C_zWEtIl.js} +1 -1
  18. package/dist/assets/{Settings-DRRozLyT.js → Settings-2Vx3X5SI.js} +1 -1
  19. package/dist/assets/{SkillReferenceGraph-DGHDWlz4.js → SkillReferenceGraph-BDEUjlTQ.js} +1 -1
  20. package/dist/assets/{Skills-D8L66eiX.js → Skills-Cmrz_LeN.js} +1 -1
  21. package/dist/assets/{SystemPrompt-CYtUsonD.js → SystemPrompt-DVA1eYDP.js} +1 -1
  22. package/dist/assets/{TagLibrary-E5CLeuVk.js → TagLibrary-DYJGAKZu.js} +1 -1
  23. package/dist/assets/{TiptapBody-B2hRgbPE.js → TiptapBody-DmPc3amD.js} +1 -1
  24. package/dist/assets/{Toggle-BTwsbxam.js → Toggle-zfd5LJkK.js} +1 -1
  25. package/dist/assets/{index-DijufvkJ.js → index-B_4PNh9T.js} +676 -676
  26. package/dist/assets/{index-CMLnzdZC.css → index-DIjnPkRN.css} +1 -1
  27. package/dist/assets/{settingsSchema-D6wzxAi6.js → settingsSchema-B9es6fdA.js} +1 -1
  28. package/dist/index.html +2 -2
  29. package/package.json +1 -1
  30. package/scripts/lib/activeSessions.cjs +116 -6
  31. package/scripts/scheduler-mcp-server.cjs +154 -95
  32. package/src/main/__tests__/epicStatusMirror.test.cjs +110 -0
  33. package/src/main/__tests__/health-delegation-chain.test.cjs +105 -0
  34. package/src/main/__tests__/prdAdminRoutes.test.cjs +295 -0
  35. package/src/main/__tests__/prdCreate.test.cjs +109 -0
  36. package/src/main/__tests__/scheduler-autofix-select.test.cjs +15 -3
  37. package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +41 -0
  38. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +60 -1
  39. package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +185 -0
  40. package/src/main/__tests__/seedSchedulerMcp.test.cjs +66 -0
  41. package/src/main/__tests__/uniquePrdNumbers.test.cjs +14 -5
  42. package/src/main/bilkoHost.cjs +4 -3
  43. package/src/main/chatRunner.cjs +6 -1
  44. package/src/main/config.cjs +22 -33
  45. package/src/main/health.cjs +153 -2
  46. package/src/main/index.cjs +56 -4
  47. package/src/main/ipcSchemas.cjs +18 -1
  48. package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +179 -0
  49. package/src/main/lib/__tests__/childWithLog.test.cjs +63 -0
  50. package/src/main/lib/__tests__/delegationReadiness.test.cjs +241 -42
  51. package/src/main/lib/__tests__/ephemeralCwd.test.cjs +91 -0
  52. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +1 -1
  53. package/src/main/lib/__tests__/gitWorktree.test.cjs +14 -2
  54. package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +107 -0
  55. package/src/main/lib/__tests__/jobWorktree.test.cjs +2 -2
  56. package/src/main/lib/__tests__/loadGate.test.cjs +159 -0
  57. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +101 -0
  58. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +151 -0
  59. package/src/main/lib/__tests__/opsRootResolve.test.cjs +149 -0
  60. package/src/main/lib/__tests__/projectRootResolve.test.cjs +148 -0
  61. package/src/main/lib/__tests__/reaperHelpers.test.cjs +112 -0
  62. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +19 -9
  63. package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +213 -0
  64. package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +127 -0
  65. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +217 -0
  66. package/src/main/lib/activeIndexMerge.cjs +15 -0
  67. package/src/main/lib/activeIndexRebuild.cjs +133 -0
  68. package/src/main/lib/buildTarget.cjs +3 -2
  69. package/src/main/lib/childWithLog.cjs +33 -1
  70. package/src/main/lib/crossProjectFeedback.cjs +8 -1
  71. package/src/main/lib/delegationReadiness.cjs +408 -26
  72. package/src/main/lib/ephemeralCwd.cjs +78 -0
  73. package/src/main/lib/epicDelegationStats.cjs +2 -1
  74. package/src/main/lib/epicMint.cjs +17 -1
  75. package/src/main/lib/epicStatusMirror.cjs +95 -0
  76. package/src/main/lib/epicValidationHook.cjs +2 -1
  77. package/src/main/lib/gitWorktree.cjs +56 -2
  78. package/src/main/lib/jobWorktree.cjs +1 -0
  79. package/src/main/lib/loadGate.cjs +134 -0
  80. package/src/main/lib/mcpToolCatalog.cjs +285 -0
  81. package/src/main/lib/opsErrorLog.cjs +12 -1
  82. package/src/main/lib/opsOwnership.cjs +94 -0
  83. package/src/main/lib/prdAdminRoutes.cjs +43 -3
  84. package/src/main/lib/prdCreate.cjs +46 -14
  85. package/src/main/lib/prdLocations.cjs +13 -6
  86. package/src/main/lib/projectRootResolve.cjs +134 -0
  87. package/src/main/lib/promptSessionSchema.cjs +7 -0
  88. package/src/main/lib/queueStore.cjs +31 -5
  89. package/src/main/lib/rcaReport.cjs +1 -1
  90. package/src/main/lib/reaperHelpers.cjs +47 -1
  91. package/src/main/lib/schedulerBatch.cjs +171 -29
  92. package/src/main/lib/schedulerConfig.cjs +80 -0
  93. package/src/main/projectBrief.cjs +3 -2
  94. package/src/main/projectPages.cjs +2 -1
  95. package/src/main/promptSessionTranscript.cjs +0 -0
  96. package/src/main/pty.cjs +5 -0
  97. package/src/main/queueOps.cjs +15 -8
  98. package/src/main/scheduler.cjs +346 -49
  99. package/src/main/seedSchedulerMcp.cjs +58 -4
  100. package/src/preload/api.d.ts +69 -1
  101. package/src/preload/index.cjs +2 -0
@@ -81,6 +81,27 @@ function alreadyRegistered() {
81
81
  }
82
82
  }
83
83
 
84
+ /**
85
+ * true only when the user-scope entry EXISTS but its script arg no longer
86
+ * resolves on disk (repo moved, worktree deleted). An entry that is entirely
87
+ * ABSENT is a deliberate `claude mcp remove` and must stay removed — that
88
+ * case returns false here, same as any other "not registered" read.
89
+ */
90
+ function scriptPathMissing() {
91
+ try {
92
+ const raw = fs.readFileSync(path.join(os.homedir(), '.claude.json'), 'utf8');
93
+ const servers = JSON.parse(raw)?.mcpServers;
94
+ const entry = servers && servers[SERVER_NAME];
95
+ if (!entry) return false;
96
+ const args = Array.isArray(entry.args) ? entry.args : [];
97
+ const scriptArg = args[args.length - 1];
98
+ if (typeof scriptArg !== 'string' || !scriptArg) return false;
99
+ return !fs.existsSync(scriptArg);
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
104
+
84
105
  /** Run `claude mcp add session-manager-scheduler --scope user -- node <serverPath>`.
85
106
  * No shell:true — argv array passed directly to spawn. */
86
107
  function runClaudeMcpAdd(serverPath) {
@@ -106,14 +127,47 @@ function runClaudeMcpAdd(serverPath) {
106
127
  });
107
128
  }
108
129
 
109
- async function seedSchedulerMcp({ logger = console, addFn = runClaudeMcpAdd, writeLog = () => {} } = {}) {
130
+ /** Run `claude mcp remove session-manager-scheduler --scope user`, best-effort. */
131
+ function runClaudeMcpRemove() {
132
+ return new Promise((resolve) => {
133
+ const claudeBin = resolveClaudeBin();
134
+ let proc;
135
+ try {
136
+ proc = spawn(
137
+ claudeBin,
138
+ ['mcp', 'remove', SERVER_NAME, '--scope', 'user'],
139
+ { cwd: os.homedir(), env: cleanChildEnv({ PATH: pathWithUserBins() }), stdio: 'ignore' }
140
+ );
141
+ } catch (err) {
142
+ resolve({ ok: false, error: err?.message ?? String(err) });
143
+ return;
144
+ }
145
+ proc.on('error', (err) => resolve({ ok: false, error: err?.message ?? String(err) }));
146
+ proc.on('close', (code) => resolve({ ok: code === 0, exitCode: code }));
147
+ });
148
+ }
149
+
150
+ async function seedSchedulerMcp({ logger = console, addFn = runClaudeMcpAdd, removeFn = runClaudeMcpRemove, writeLog = () => {} } = {}) {
110
151
  if (process.env.SM_SEED_SCHEDULER_MCP_DISABLE === '1') return;
111
152
  const marker = readMarker();
112
- if (marker.done) return; // succeeded before — leave it alone.
113
- if (marker.attempts >= MAX_ATTEMPTS) return; // gave up — manual install only.
153
+
154
+ // `claude mcp add` refuses when a server of this name already exists, so a
155
+ // repair must remove the stale entry first — but ONLY when the marker says
156
+ // `done` AND the registered script has actually gone missing. An entry
157
+ // that's simply absent (marker done, no ~/.claude.json entry at all) is a
158
+ // deliberate `claude mcp remove` and must stay removed exactly as today.
159
+ let repairing = false;
160
+ if (marker.done) {
161
+ if (!scriptPathMissing()) return;
162
+ repairing = true;
163
+ logger.warn?.('[seedSchedulerMcp] user-scope registration points at a missing script — repairing…');
164
+ await removeFn();
165
+ } else if (marker.attempts >= MAX_ATTEMPTS) {
166
+ return; // gave up — manual install only.
167
+ }
114
168
 
115
169
  try {
116
- if (alreadyRegistered()) {
170
+ if (!repairing && alreadyRegistered()) {
117
171
  writeMarker({ done: true, attempts: marker.attempts });
118
172
  return;
119
173
  }
@@ -199,6 +199,31 @@ export interface McpStatusResult {
199
199
  checkedAt: number;
200
200
  }
201
201
 
202
+ /** One session-manager-scheduler MCP tool's catalog entry (src/main/lib/mcpToolCatalog.cjs) —
203
+ * the same data GET /admin/mcp/catalog serves, read in-process for Project Home's
204
+ * PhAgentTools block. */
205
+ export interface McpToolCatalogEntry {
206
+ name: string;
207
+ group: 'scheduler' | 'chat' | 'feedback' | 'help';
208
+ purpose: string;
209
+ whenToUse: string;
210
+ whenNotToUse: string;
211
+ exampleArgs: Record<string, unknown>;
212
+ notes: string | null;
213
+ }
214
+
215
+ export interface McpRecipe {
216
+ id: string;
217
+ title: string;
218
+ steps: string[];
219
+ }
220
+
221
+ export interface McpCatalogResult {
222
+ ok: boolean;
223
+ tools: McpToolCatalogEntry[];
224
+ recipes: McpRecipe[];
225
+ }
226
+
202
227
  /** Mirrors WorkType (src/main/lib/workTypeLibrary.cjs) / EpicTag (tagLibrary.ts) — the
203
228
  * same Epic-mission taxonomy, reused here since an Agent persona's `tags` field is that
204
229
  * same concept, not a free-form string list. */
@@ -323,11 +348,31 @@ export interface TestFireHookResult {
323
348
  }
324
349
 
325
350
  export interface DelegationReadinessCheck {
326
- id: 'scheduler-mcp' | 'dev-plugin' | 'agent-personas' | 'prd-write-guard';
351
+ id:
352
+ | 'scheduler-mcp'
353
+ | 'scheduler-mcp-live'
354
+ | 'scheduler-mcp-project-duplicate'
355
+ | 'dev-plugin'
356
+ | 'agent-personas'
357
+ | 'prd-write-guard';
327
358
  label: string;
328
359
  ok: boolean;
329
360
  detail: string;
330
361
  fix: string | null;
362
+ /** Non-null when Session Manager can install this fix itself, one press. */
363
+ fixAction: 'install-prd-write-guard' | null;
364
+ /** True when ok:true is a WARNING (still passing, but worth a human's attention) — today only scheduler-mcp-project-duplicate. */
365
+ warn?: boolean;
366
+ /** True when this check didn't run because a precondition (another check) already failed — reported ok:true, not a failure. */
367
+ skipped?: boolean;
368
+ }
369
+
370
+ export interface InstallPrdWriteGuardResult {
371
+ ok: boolean;
372
+ action: 'installed' | 'repaired' | 'already-installed' | 'error';
373
+ settingsPath?: string;
374
+ command?: string;
375
+ error?: string;
331
376
  }
332
377
 
333
378
  export interface DelegationReadiness {
@@ -602,10 +647,31 @@ export interface ScheduleStateSnapshot {
602
647
  pollHealth?: SchedulePollHealth;
603
648
  /** Effective concurrency cap and whether it's env-pinned or config-driven. */
604
649
  effectiveConcurrency: ScheduleEffectiveConcurrency;
650
+ /**
651
+ * CPU-load launch gate (PRD 1085): why nothing is launching when the box
652
+ * is saturated. Null before the first tick that evaluated it.
653
+ */
654
+ loadGate?: ScheduleLoadGate | null;
605
655
  /** Returned only by the initial state() call, not the broadcast event. */
606
656
  paths?: SchedulePaths;
607
657
  }
608
658
 
659
+ export interface ScheduleLoadGate {
660
+ /** True when this tick's launches were withheld because of load. */
661
+ gated: boolean;
662
+ /** True when load would have gated but an explicit Run now bypassed it. */
663
+ bypassed: boolean;
664
+ /** 1-minute load average divided by core count. */
665
+ ratio: number;
666
+ /** LOAD_GATE_PER_CORE (or SM_LOAD_GATE_PER_CORE); 0 means disabled. */
667
+ threshold: number;
668
+ loadavg1: number | null;
669
+ cores: number;
670
+ /** How long the current gated stretch has lasted, 0 when not gated. */
671
+ gatedSinceMs: number;
672
+ at: string;
673
+ }
674
+
609
675
  export interface HistoryAggregateRequest {
610
676
  fromDate?: string;
611
677
  toDate?: string;
@@ -1298,6 +1364,7 @@ export interface SessionManagerAPI {
1298
1364
  /** "Can this project actually delegate?" — the 4 preconditions for
1299
1365
  * scheduler_create_prd being in an agent's tool list at all. */
1300
1366
  delegationReadiness: (cwd: string) => Promise<DelegationReadiness>;
1367
+ installPrdWriteGuard: (cwd: string) => Promise<InstallPrdWriteGuardResult>;
1301
1368
  onNewSession: (handler: () => void) => () => void;
1302
1369
  onRebootSession: (handler: () => void) => () => void;
1303
1370
  archiveProject: (encoded: string) => Promise<{ ok: boolean; error?: string }>;
@@ -1350,6 +1417,7 @@ export interface SessionManagerAPI {
1350
1417
  };
1351
1418
  mcp: {
1352
1419
  status: () => Promise<McpStatusResult>;
1420
+ catalog: () => Promise<McpCatalogResult>;
1353
1421
  };
1354
1422
  agents: {
1355
1423
  listPersonas: () => Promise<AgentPersona[]>;
@@ -23,6 +23,7 @@ contextBridge.exposeInMainWorld('api', {
23
23
  homeSelfCheck: () => ipcRenderer.invoke('app:home-self-check'),
24
24
  seedStatus: () => ipcRenderer.invoke('app:seed-status'),
25
25
  delegationReadiness: (cwd) => ipcRenderer.invoke('app:delegation-readiness', { cwd }),
26
+ installPrdWriteGuard: (cwd) => ipcRenderer.invoke('app:install-prd-write-guard', { cwd }),
26
27
  onNewSession: (handler) => {
27
28
  const listener = () => handler();
28
29
  ipcRenderer.on('app:new-session', listener);
@@ -94,6 +95,7 @@ contextBridge.exposeInMainWorld('api', {
94
95
  },
95
96
  mcp: {
96
97
  status: () => ipcRenderer.invoke('mcp:status'),
98
+ catalog: () => ipcRenderer.invoke('mcp:catalog'),
97
99
  },
98
100
  agents: {
99
101
  listPersonas: () => ipcRenderer.invoke('agents:list-personas'),