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.
- package/dist/assets/{AgentLibrary-CzQqcObq.js → AgentLibrary-CBx9l4zN.js} +1 -1
- package/dist/assets/{DataModel-Bj_WlLz8.js → DataModel-Bf0EIE_t.js} +1 -1
- package/dist/assets/{History-DnSi_OHm.js → History-CpdtWhC8.js} +1 -1
- package/dist/assets/{Hooks-0BB0dp3S.js → Hooks-DyUbMDmg.js} +1 -1
- package/dist/assets/{HostBilko-DHpwwsLQ.js → HostBilko-By-wIpry.js} +1 -1
- package/dist/assets/{Library-CaJVqVvi.js → Library-CQmo4QVC.js} +1 -1
- package/dist/assets/{ListDetail-C1W2HmC2.js → ListDetail-BQMd6NOm.js} +1 -1
- package/dist/assets/{MarkdownEditor-5Ob9FW3z.js → MarkdownEditor-DEp43FXX.js} +1 -1
- package/dist/assets/{McpServers-JxCSfm1S.js → McpServers-CLarzwqA.js} +1 -1
- package/dist/assets/{Memory-BDeqlqwH.js → Memory-B0sCdIy1.js} +1 -1
- package/dist/assets/{Panel-Dh9ZHuEj.js → Panel-BhWPVOCD.js} +1 -1
- package/dist/assets/{Permissions-DXy-CbEY.js → Permissions-Ddlq8T_O.js} +1 -1
- package/dist/assets/{Plugins-_n1Iuc8T.js → Plugins-D2oA_2Jl.js} +2 -2
- package/dist/assets/{ProvenanceBadge-BP_evfxE.js → ProvenanceBadge-DgAgavUM.js} +1 -1
- package/dist/assets/{SaveBar-D-gCUx4n.js → SaveBar-Qvc4Ek-H.js} +1 -1
- package/dist/assets/{Scheduler-Bpd4OGju.js → Scheduler-BmYJvNzK.js} +1 -1
- package/dist/assets/{ScopeSwitcher-CAWzM6RI.js → ScopeSwitcher-C_zWEtIl.js} +1 -1
- package/dist/assets/{Settings-DRRozLyT.js → Settings-2Vx3X5SI.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-DGHDWlz4.js → SkillReferenceGraph-BDEUjlTQ.js} +1 -1
- package/dist/assets/{Skills-D8L66eiX.js → Skills-Cmrz_LeN.js} +1 -1
- package/dist/assets/{SystemPrompt-CYtUsonD.js → SystemPrompt-DVA1eYDP.js} +1 -1
- package/dist/assets/{TagLibrary-E5CLeuVk.js → TagLibrary-DYJGAKZu.js} +1 -1
- package/dist/assets/{TiptapBody-B2hRgbPE.js → TiptapBody-DmPc3amD.js} +1 -1
- package/dist/assets/{Toggle-BTwsbxam.js → Toggle-zfd5LJkK.js} +1 -1
- package/dist/assets/{index-DijufvkJ.js → index-B_4PNh9T.js} +676 -676
- package/dist/assets/{index-CMLnzdZC.css → index-DIjnPkRN.css} +1 -1
- package/dist/assets/{settingsSchema-D6wzxAi6.js → settingsSchema-B9es6fdA.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/scripts/lib/activeSessions.cjs +116 -6
- package/scripts/scheduler-mcp-server.cjs +154 -95
- package/src/main/__tests__/epicStatusMirror.test.cjs +110 -0
- package/src/main/__tests__/health-delegation-chain.test.cjs +105 -0
- package/src/main/__tests__/prdAdminRoutes.test.cjs +295 -0
- package/src/main/__tests__/prdCreate.test.cjs +109 -0
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +15 -3
- package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +41 -0
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +60 -1
- package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +185 -0
- package/src/main/__tests__/seedSchedulerMcp.test.cjs +66 -0
- package/src/main/__tests__/uniquePrdNumbers.test.cjs +14 -5
- package/src/main/bilkoHost.cjs +4 -3
- package/src/main/chatRunner.cjs +6 -1
- package/src/main/config.cjs +22 -33
- package/src/main/health.cjs +153 -2
- package/src/main/index.cjs +56 -4
- package/src/main/ipcSchemas.cjs +18 -1
- package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +179 -0
- package/src/main/lib/__tests__/childWithLog.test.cjs +63 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +241 -42
- package/src/main/lib/__tests__/ephemeralCwd.test.cjs +91 -0
- package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +1 -1
- package/src/main/lib/__tests__/gitWorktree.test.cjs +14 -2
- package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +107 -0
- package/src/main/lib/__tests__/jobWorktree.test.cjs +2 -2
- package/src/main/lib/__tests__/loadGate.test.cjs +159 -0
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +101 -0
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +151 -0
- package/src/main/lib/__tests__/opsRootResolve.test.cjs +149 -0
- package/src/main/lib/__tests__/projectRootResolve.test.cjs +148 -0
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +112 -0
- package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +19 -9
- package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +213 -0
- package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +127 -0
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +217 -0
- package/src/main/lib/activeIndexMerge.cjs +15 -0
- package/src/main/lib/activeIndexRebuild.cjs +133 -0
- package/src/main/lib/buildTarget.cjs +3 -2
- package/src/main/lib/childWithLog.cjs +33 -1
- package/src/main/lib/crossProjectFeedback.cjs +8 -1
- package/src/main/lib/delegationReadiness.cjs +408 -26
- package/src/main/lib/ephemeralCwd.cjs +78 -0
- package/src/main/lib/epicDelegationStats.cjs +2 -1
- package/src/main/lib/epicMint.cjs +17 -1
- package/src/main/lib/epicStatusMirror.cjs +95 -0
- package/src/main/lib/epicValidationHook.cjs +2 -1
- package/src/main/lib/gitWorktree.cjs +56 -2
- package/src/main/lib/jobWorktree.cjs +1 -0
- package/src/main/lib/loadGate.cjs +134 -0
- package/src/main/lib/mcpToolCatalog.cjs +285 -0
- package/src/main/lib/opsErrorLog.cjs +12 -1
- package/src/main/lib/opsOwnership.cjs +94 -0
- package/src/main/lib/prdAdminRoutes.cjs +43 -3
- package/src/main/lib/prdCreate.cjs +46 -14
- package/src/main/lib/prdLocations.cjs +13 -6
- package/src/main/lib/projectRootResolve.cjs +134 -0
- package/src/main/lib/promptSessionSchema.cjs +7 -0
- package/src/main/lib/queueStore.cjs +31 -5
- package/src/main/lib/rcaReport.cjs +1 -1
- package/src/main/lib/reaperHelpers.cjs +47 -1
- package/src/main/lib/schedulerBatch.cjs +171 -29
- package/src/main/lib/schedulerConfig.cjs +80 -0
- package/src/main/projectBrief.cjs +3 -2
- package/src/main/projectPages.cjs +2 -1
- package/src/main/promptSessionTranscript.cjs +0 -0
- package/src/main/pty.cjs +5 -0
- package/src/main/queueOps.cjs +15 -8
- package/src/main/scheduler.cjs +346 -49
- package/src/main/seedSchedulerMcp.cjs +58 -4
- package/src/preload/api.d.ts +69 -1
- 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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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
|
}
|
package/src/preload/api.d.ts
CHANGED
|
@@ -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:
|
|
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[]>;
|
package/src/preload/index.cjs
CHANGED
|
@@ -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'),
|