claude-code-session-manager 0.92.1 → 0.94.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/DataModel-B0LDnnSL.js +1 -0
- package/dist/assets/{History-BOR_fJNr.js → History-C685Kytt.js} +2 -2
- package/dist/assets/{Hooks-BtD436iL.js → Hooks-CwLnp0Z_.js} +3 -3
- package/dist/assets/HostBilko-CwEHEKYk.js +1 -0
- package/dist/assets/{Library-DeKdY-tD.js → Library-BU9np05E.js} +25 -25
- package/dist/assets/{MarkdownEditor-CbzC-Oqf.js → MarkdownEditor-B74ogK2f.js} +1 -1
- package/dist/assets/McpServers-BLM3ftzP.js +2 -0
- package/dist/assets/{Memory-B68AJjg2.js → Memory-DAP1t8bA.js} +6 -6
- package/dist/assets/{Permissions-Cr0RRvNy.js → Permissions-3pGLJmxQ.js} +3 -3
- package/dist/assets/Plugins-Q1KoLEzn.js +2 -0
- package/dist/assets/ProvenanceBadge-BnjBQiV9.js +1 -0
- package/dist/assets/{SaveBar-87ZJfscX.js → SaveBar-Zq2NfcPf.js} +1 -1
- package/dist/assets/Scheduler-D488ebKm.js +16 -0
- package/dist/assets/{ScopeSwitcher-CKzpqjJ_.js → ScopeSwitcher-Cnojv22D.js} +1 -1
- package/dist/assets/Settings-D5Lhj7ga.js +3 -0
- package/dist/assets/{SkillReferenceGraph-D_-wg4r9.js → SkillReferenceGraph-BRDiE6Hv.js} +2 -2
- package/dist/assets/Skills-BQDqp-EN.js +3 -0
- package/dist/assets/SystemPrompt-tFr19Od6.js +1 -0
- package/dist/assets/TagLibrary-BjyrnaRE.js +1 -0
- package/dist/assets/{TiptapBody-DYXIp8aG.js → TiptapBody-DGzSg3BO.js} +1 -1
- package/dist/assets/{Toggle-CDXR5l3m.js → Toggle-DzoROibf.js} +1 -1
- package/dist/assets/index-CCl4tz-u.js +3079 -0
- package/dist/assets/{index-D3P_jldk.css → index-CKH5Uxik.css} +1 -1
- package/dist/assets/settingsSchema-BYKVe1WM.js +1 -0
- package/dist/index.html +2 -2
- package/package.json +6 -3
- package/scripts/README.md +3 -0
- package/src/main/__tests__/agentEffortResolve.test.cjs +117 -0
- package/src/main/__tests__/agentLibrary.test.cjs +21 -0
- package/src/main/__tests__/agentModelResolve.test.cjs +16 -0
- package/src/main/__tests__/agentOverlayWrite.test.cjs +95 -0
- package/src/main/__tests__/chat-cancel-terminal.test.cjs +5 -2
- package/src/main/__tests__/chat-exit-close-race.test.cjs +8 -2
- package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +5 -2
- package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +44 -0
- package/src/main/__tests__/intradayRefresh.test.cjs +39 -0
- package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +25 -0
- package/src/main/__tests__/opsErrorLog.test.cjs +22 -0
- package/src/main/__tests__/personaMerge.test.cjs +169 -0
- package/src/main/__tests__/prdCreatePlanId.test.cjs +132 -0
- package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +13 -0
- package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +21 -0
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +14 -0
- package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +26 -0
- package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +11 -1
- package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +11 -1
- package/src/main/__tests__/runVerify.test.cjs +12 -1
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +47 -2
- package/src/main/__tests__/transcriptsUsageFor.test.cjs +112 -1
- package/src/main/agentLibrary.cjs +86 -40
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +50 -10
- package/src/main/git.cjs +9 -2
- package/src/main/historyAggregator.cjs +2 -19
- package/src/main/index.cjs +17 -8
- package/src/main/ipcSchemas.cjs +25 -3
- package/src/main/lib/__tests__/childWithLog.test.cjs +180 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +19 -0
- package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +10 -5
- package/src/main/lib/__tests__/gitCacheBound.test.cjs +69 -0
- package/src/main/lib/__tests__/modelCatalog.test.cjs +202 -0
- package/src/main/lib/agentEffortResolve.cjs +74 -0
- package/src/main/lib/agentModelResolve.cjs +52 -59
- package/src/main/lib/agentPersonaSchema.cjs +5 -0
- package/src/main/lib/childWithLog.cjs +92 -51
- package/src/main/lib/delegationReadiness.cjs +3 -1
- package/src/main/lib/effectiveModelInfo.cjs +38 -20
- package/src/main/lib/epicMint.cjs +5 -2
- package/src/main/lib/epicSpawnPlan.cjs +27 -8
- package/src/main/lib/epicTranscriptPath.cjs +5 -1
- package/src/main/lib/epicWorktreeMerge.cjs +7 -6
- package/src/main/lib/headTailBuffer.cjs +43 -0
- package/src/main/lib/intradayRefresh.cjs +33 -0
- package/src/main/lib/lruCache.cjs +39 -0
- package/src/main/lib/modelCatalog.cjs +243 -0
- package/src/main/lib/openExternalApp.cjs +27 -9
- package/src/main/lib/opsErrorLog.cjs +22 -0
- package/src/main/lib/personaMerge.cjs +166 -0
- package/src/main/lib/prdCreate.cjs +23 -5
- package/src/main/lib/prdDisposition.cjs +46 -0
- package/src/main/lib/prdFrontmatter.cjs +6 -2
- package/src/main/lib/promptSessionSchema.cjs +5 -0
- package/src/main/lib/promptSessionsCreateEpic.cjs +5 -3
- package/src/main/lib/rendererRecovery.cjs +141 -0
- package/src/main/lib/scheduleJobSchema.cjs +3 -0
- package/src/main/runVerify.cjs +3 -1
- package/src/main/scheduler/prdParser.cjs +2 -0
- package/src/main/scheduler.cjs +381 -262
- package/src/main/templates/PRD_AUTHORING.md +4 -0
- package/src/main/transcripts.cjs +54 -11
- package/src/preload/api.d.ts +56 -3
- package/src/preload/index.cjs +4 -0
- package/dist/assets/AgentLibrary-Ci6u03bq.js +0 -3
- package/dist/assets/DataModel-BIqcjsv2.js +0 -1
- package/dist/assets/HostBilko-CMe5cH3H.js +0 -1
- package/dist/assets/ListDetail-CtVjrHKB.js +0 -1
- package/dist/assets/McpServers-DKN75Shn.js +0 -2
- package/dist/assets/Panel-C2YTW-qP.js +0 -1
- package/dist/assets/Plugins-DbZkJs5l.js +0 -2
- package/dist/assets/ProvenanceBadge-kJ__BOQv.js +0 -1
- package/dist/assets/Scheduler-DdEaxku8.js +0 -16
- package/dist/assets/Settings-CjywVsNB.js +0 -3
- package/dist/assets/Skills-Cd_yPO_l.js +0 -3
- package/dist/assets/SystemPrompt-2z6eGPSF.js +0 -1
- package/dist/assets/TagLibrary-DcaWQSp4.js +0 -1
- package/dist/assets/index-D5H_H5wC.js +0 -3074
- package/dist/assets/settingsSchema-JRDfjgHb.js +0 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/**
|
|
2
3
|
* Canonical runtime schema for a PromptSession (Epic) record, mirroring the
|
|
3
4
|
* TS `PromptSession` interface at src/renderer/state/promptSessions.ts:29-76
|
|
@@ -72,6 +73,9 @@ const PromptSessionSchema = z.object({
|
|
|
72
73
|
openingPrompt: z.string().nullable().optional(),
|
|
73
74
|
source: EpicSourceSchema.optional(),
|
|
74
75
|
agentType: z.string().optional(),
|
|
76
|
+
// Per-Epic runtime overrides chosen on the New Session card; absent = the persona's own value.
|
|
77
|
+
model: z.string().optional(),
|
|
78
|
+
effort: z.string().optional(),
|
|
75
79
|
// Absent on Epics minted before this field existed — those fall back to
|
|
76
80
|
// rendering the flat `openingPrompt` as a single block (see
|
|
77
81
|
// ChatTranscriptTurn.tsx's EpicIntakeCard).
|
|
@@ -93,6 +97,7 @@ const PromptSessionSchema = z.object({
|
|
|
93
97
|
* doesn't match PromptSessionSchema. Callers that want fail-closed
|
|
94
98
|
* enforcement before persisting a session object call this immediately
|
|
95
99
|
* before their write.
|
|
100
|
+
* @param {unknown} session
|
|
96
101
|
*/
|
|
97
102
|
function assertValidPromptSession(session) {
|
|
98
103
|
const result = PromptSessionSchema.safeParse(session);
|
|
@@ -41,12 +41,14 @@ const { validatePath } = require('../config.cjs');
|
|
|
41
41
|
* IPC (config:read-json/write-json, lib/activeIndexMerge.cjs's own merge) is
|
|
42
42
|
* already required to pass through.
|
|
43
43
|
*/
|
|
44
|
-
async function createEpicViaIpc(cwd, { goalText, tag, agentType, source, openingPrompt, sections } = {}) {
|
|
44
|
+
async function createEpicViaIpc(cwd, { goalText, tag, agentType, model, effort, source, openingPrompt, sections } = {}) {
|
|
45
45
|
validatePath(cwd);
|
|
46
46
|
const { epicId } = await ensureEpic(cwd, {
|
|
47
47
|
goalText,
|
|
48
48
|
tag,
|
|
49
49
|
agentType,
|
|
50
|
+
model,
|
|
51
|
+
effort,
|
|
50
52
|
source,
|
|
51
53
|
openingPrompt,
|
|
52
54
|
sections,
|
|
@@ -62,8 +64,8 @@ function registerPromptSessionsCreateEpicHandlers() {
|
|
|
62
64
|
const { schemas: s, validated: v } = require('../ipcSchemas.cjs');
|
|
63
65
|
ipcMain.handle(
|
|
64
66
|
'promptSessions:create-epic',
|
|
65
|
-
v(s.promptSessionsCreateEpic, ({ cwd, goalText, tag, agentType, source, openingPrompt, sections }) =>
|
|
66
|
-
createEpicViaIpc(cwd, { goalText, tag, agentType, source, openingPrompt, sections })),
|
|
67
|
+
v(s.promptSessionsCreateEpic, ({ cwd, goalText, tag, agentType, model, effort, source, openingPrompt, sections }) =>
|
|
68
|
+
createEpicViaIpc(cwd, { goalText, tag, agentType, model, effort, source, openingPrompt, sections })),
|
|
67
69
|
);
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Bounded automatic recovery for a dead / hung / failed-to-load renderer.
|
|
4
|
+
// Without it an OOM-killed renderer leaves a permanently white window while
|
|
5
|
+
// scheduler jobs keep running headless with no UI to pause them.
|
|
6
|
+
//
|
|
7
|
+
// `createReloadPolicy` is the pure cap/timing unit (injected clock);
|
|
8
|
+
// `attachRendererRecovery` wires it to one webContents (= one window).
|
|
9
|
+
|
|
10
|
+
const MAX_RELOADS = 3;
|
|
11
|
+
const WINDOW_MS = 10 * 60 * 1000;
|
|
12
|
+
const UNRESPONSIVE_GRACE_MS = 30 * 1000;
|
|
13
|
+
const LOAD_RETRY_DELAY_MS = 2000;
|
|
14
|
+
const ERR_ABORTED = -3;
|
|
15
|
+
|
|
16
|
+
/** Sliding-window cap: at most `max` reloads per `windowMs`. O(max) per call. */
|
|
17
|
+
function createReloadPolicy({ now = Date.now, max = MAX_RELOADS, windowMs = WINDOW_MS } = {}) {
|
|
18
|
+
let stamps = [];
|
|
19
|
+
return {
|
|
20
|
+
/** Record a reload if the cap allows it. Returns true when allowed. */
|
|
21
|
+
tryReload() {
|
|
22
|
+
const t = now();
|
|
23
|
+
stamps = stamps.filter((s) => t - s < windowMs);
|
|
24
|
+
if (stamps.length >= max) return false;
|
|
25
|
+
stamps.push(t);
|
|
26
|
+
return true;
|
|
27
|
+
},
|
|
28
|
+
/** Would tryReload() succeed right now? Pure — consumes no slot. */
|
|
29
|
+
canReload() {
|
|
30
|
+
const t = now();
|
|
31
|
+
return stamps.filter((s) => t - s < windowMs).length < max;
|
|
32
|
+
},
|
|
33
|
+
/** Should a render-process-gone reason trigger recovery? */
|
|
34
|
+
shouldRecoverFromGone(reason) {
|
|
35
|
+
return reason !== 'clean-exit';
|
|
36
|
+
},
|
|
37
|
+
/** Should a did-fail-load trigger a retry? Main frame only, not ERR_ABORTED. */
|
|
38
|
+
shouldRetryLoad(errorCode, isMainFrame) {
|
|
39
|
+
return isMainFrame !== false && errorCode !== ERR_ABORTED;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function attachRendererRecovery(wc, {
|
|
45
|
+
logs,
|
|
46
|
+
policy = createReloadPolicy(),
|
|
47
|
+
setTimer = setTimeout,
|
|
48
|
+
clearTimer = clearTimeout,
|
|
49
|
+
} = {}) {
|
|
50
|
+
let unresponsiveTimer = null;
|
|
51
|
+
let loadRetryTimer = null;
|
|
52
|
+
let capLogged = false;
|
|
53
|
+
|
|
54
|
+
const log = (level, message, meta) => {
|
|
55
|
+
try { logs?.writeLine({ scope: 'crash-diag', level, message, meta }); } catch { /* logging must never break recovery */ }
|
|
56
|
+
};
|
|
57
|
+
const alive = () => !wc.isDestroyed();
|
|
58
|
+
|
|
59
|
+
function logCapReached(reason) {
|
|
60
|
+
if (capLogged) return;
|
|
61
|
+
capLogged = true;
|
|
62
|
+
log('error', 'renderer auto-reload cap reached — giving up', { reason, max: MAX_RELOADS, windowMs: WINDOW_MS });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function reload(reason) {
|
|
66
|
+
if (!alive()) return;
|
|
67
|
+
if (!policy.tryReload()) {
|
|
68
|
+
logCapReached(reason);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
capLogged = false;
|
|
72
|
+
log('warn', 'renderer auto-reload', { reason });
|
|
73
|
+
try { wc.reload(); } catch (e) { log('error', 'renderer reload threw', { reason, error: e?.message }); }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// A hung main thread cannot commit a same-process reload, so kill the renderer
|
|
77
|
+
// and let the render-process-gone handler do the single cap-counted reload
|
|
78
|
+
// (in a new process). No slot is consumed here.
|
|
79
|
+
function recoverFromHang() {
|
|
80
|
+
if (!alive()) return;
|
|
81
|
+
if (!policy.canReload()) {
|
|
82
|
+
// A hung-but-visible window beats a dead white one.
|
|
83
|
+
logCapReached('unresponsive');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
if (typeof wc.forcefullyCrashRenderer !== 'function') throw new Error('forcefullyCrashRenderer unavailable');
|
|
88
|
+
log('warn', 'renderer unresponsive — forcefully crashing for recovery');
|
|
89
|
+
wc.forcefullyCrashRenderer();
|
|
90
|
+
} catch (e) {
|
|
91
|
+
log('warn', 'forcefullyCrashRenderer failed — falling back to reload', { error: e?.message });
|
|
92
|
+
reload('unresponsive');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
wc.on('render-process-gone', (_e, details) => {
|
|
97
|
+
const reason = details?.reason;
|
|
98
|
+
if (!policy.shouldRecoverFromGone(reason)) return;
|
|
99
|
+
reload(`render-process-gone:${reason}`);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
wc.on('unresponsive', () => {
|
|
103
|
+
log('warn', 'renderer unresponsive');
|
|
104
|
+
if (unresponsiveTimer) return;
|
|
105
|
+
unresponsiveTimer = setTimer(() => {
|
|
106
|
+
unresponsiveTimer = null;
|
|
107
|
+
recoverFromHang();
|
|
108
|
+
}, UNRESPONSIVE_GRACE_MS);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
wc.on('responsive', () => {
|
|
112
|
+
if (unresponsiveTimer) { clearTimer(unresponsiveTimer); unresponsiveTimer = null; }
|
|
113
|
+
log('info', 'renderer responsive again');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
wc.on('did-fail-load', (_e, errorCode, errorDescription, _url, isMainFrame) => {
|
|
117
|
+
if (!policy.shouldRetryLoad(errorCode, isMainFrame)) return;
|
|
118
|
+
log('warn', 'main-frame did-fail-load', { errorCode, errorDescription });
|
|
119
|
+
if (loadRetryTimer) return;
|
|
120
|
+
loadRetryTimer = setTimer(() => {
|
|
121
|
+
loadRetryTimer = null;
|
|
122
|
+
reload(`did-fail-load:${errorCode}`);
|
|
123
|
+
}, LOAD_RETRY_DELAY_MS);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
wc.once('destroyed', () => {
|
|
127
|
+
if (unresponsiveTimer) clearTimer(unresponsiveTimer);
|
|
128
|
+
if (loadRetryTimer) clearTimer(loadRetryTimer);
|
|
129
|
+
unresponsiveTimer = loadRetryTimer = null;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
createReloadPolicy,
|
|
135
|
+
attachRendererRecovery,
|
|
136
|
+
MAX_RELOADS,
|
|
137
|
+
WINDOW_MS,
|
|
138
|
+
UNRESPONSIVE_GRACE_MS,
|
|
139
|
+
LOAD_RETRY_DELAY_MS,
|
|
140
|
+
ERR_ABORTED,
|
|
141
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/**
|
|
2
3
|
* Canonical runtime schema for a ScheduleJob record, mirroring the TS
|
|
3
4
|
* `ScheduleJob` interface (`ScheduleJob` in src/preload/api.d.ts) field-for-field.
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
|
|
25
26
|
const { z } = require('zod');
|
|
26
27
|
|
|
28
|
+
/** @type {[string, ...string[]]} */
|
|
27
29
|
const JOB_STATUSES = ['pending', 'running', 'investigating', 'completed', 'skipped', 'failed', 'needs_review', 'quarantined'];
|
|
28
30
|
|
|
29
31
|
const ScheduleJobStatusSchema = z.enum(JOB_STATUSES);
|
|
@@ -138,6 +140,7 @@ const ScheduleJobSchema = z
|
|
|
138
140
|
/**
|
|
139
141
|
* Throws a clear, descriptive error (not a raw ZodError dump) when `job`
|
|
140
142
|
* doesn't match ScheduleJobSchema. Mirrors assertValidPromptSession's shape.
|
|
143
|
+
* @param {unknown} job
|
|
141
144
|
*/
|
|
142
145
|
function assertValidScheduleJob(job) {
|
|
143
146
|
const result = ScheduleJobSchema.safeParse(job);
|
package/src/main/runVerify.cjs
CHANGED
|
@@ -898,7 +898,9 @@ async function verifyRun({
|
|
|
898
898
|
scannedAt: new Date().toISOString(),
|
|
899
899
|
...(extras ?? {}),
|
|
900
900
|
};
|
|
901
|
-
|
|
901
|
+
// Atomic (tmp+rename) — scheduler.cjs reads this sidecar to decide completed-equivalence,
|
|
902
|
+
// so a torn write must never be observable. Lazy require keeps this module electron-free at load.
|
|
903
|
+
try { require('./config.cjs').writeJsonSync(verdictsPath, record); } catch { /* best-effort */ }
|
|
902
904
|
return { verdict, reason, downgradeTo, ...(extras ?? {}) };
|
|
903
905
|
}
|
|
904
906
|
|
|
@@ -126,6 +126,8 @@ async function parsePrdRaw(filePath) {
|
|
|
126
126
|
// the decision (first-ever PRD in its Epic, or one with its own explicit
|
|
127
127
|
// dependsOn).
|
|
128
128
|
disposition: (fm.disposition === 'append' || fm.disposition === 'new-head') ? fm.disposition : null,
|
|
129
|
+
// Durable wave identity (createPrd-stamped); malformed values read as absent.
|
|
130
|
+
planId: (typeof fm.planId === 'string' && /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(fm.planId)) ? fm.planId : null,
|
|
129
131
|
// Opt-in exclusive-lease flag (PRD 1107, quietMachineLease.cjs +
|
|
130
132
|
// schedulerBatch.cjs's pickNextBatch). Only a literal `true` opts in —
|
|
131
133
|
// matches prdFrontmatter.cjs's applyKey semantics for this field.
|