claude-code-session-manager 0.35.8 → 0.35.9
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/{TiptapBody-DI6Dl7gv.js → TiptapBody-Wc0rOkr4.js} +1 -1
- package/dist/assets/{index-CCqF0xvC.js → index-B4PkQh71.js} +175 -177
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +11 -1
- package/src/main/index.cjs +29 -0
- package/src/main/ipcSchemas.cjs +15 -0
- package/src/main/scheduler.cjs +7 -2
- package/src/preload/api.d.ts +9 -0
- package/src/preload/index.cjs +2 -0
package/dist/index.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;0,6..72,700;1,6..72,400&family=Geist:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
10
|
-
<script type="module" crossorigin src="./assets/index-
|
|
10
|
+
<script type="module" crossorigin src="./assets/index-B4PkQh71.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="./assets/monaco-editor-BW5C4Iv1.js">
|
|
12
12
|
<link rel="stylesheet" crossorigin href="./assets/monaco-editor-BTnBOi8r.css">
|
|
13
13
|
<link rel="stylesheet" crossorigin href="./assets/index-C7NyYuXu.css">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-session-manager",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.9",
|
|
4
4
|
"description": "Local cockpit for the Claude Code CLI — multi-tab terminal, full config surface, scheduler, voice dictation, and live observability.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main/index.cjs",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const { test } = require('node:test');
|
|
10
10
|
const assert = require('node:assert/strict');
|
|
11
|
-
const { selectAutoFixTargets, isUnresolvableNeedsReview } = require('../scheduler.cjs');
|
|
11
|
+
const { selectAutoFixTargets, isUnresolvableNeedsReview, isRescanCandidate } = require('../scheduler.cjs');
|
|
12
12
|
|
|
13
13
|
const noSiblingOnDisk = () => false;
|
|
14
14
|
const noRunDir = () => null;
|
|
@@ -140,4 +140,14 @@ test('defaults parallelGroup to 99 when absent', () => {
|
|
|
140
140
|
assert.strictEqual(seen[0], '99-fix-my-feature');
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
+
test('isRescanCandidate: needs_review + runId + no_verdict_sentinel → true (RESCANNABLE_VERDICTS includes it)', () => {
|
|
144
|
+
const job = makeJob({ verifierVerdict: 'no_verdict_sentinel' });
|
|
145
|
+
assert.strictEqual(isRescanCandidate(job), true);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('isRescanCandidate: needs_review + runId + uncommitted_changes → false (git commit-guard verdict stays excluded)', () => {
|
|
149
|
+
const job = makeJob({ verifierVerdict: 'uncommitted_changes' });
|
|
150
|
+
assert.strictEqual(isRescanCandidate(job), false);
|
|
151
|
+
});
|
|
152
|
+
|
|
143
153
|
console.log('scheduler-autofix-select tests: PASS');
|
package/src/main/index.cjs
CHANGED
|
@@ -434,6 +434,25 @@ ipcMain.handle('app:pick-directory', async () => {
|
|
|
434
434
|
|
|
435
435
|
ipcMain.on('app:reboot-app', () => rebootApp());
|
|
436
436
|
|
|
437
|
+
// Recorder export "Save to file…" (PRD 412) — native Save As dialog, written
|
|
438
|
+
// directly since the path is user-chosen, not renderer input.
|
|
439
|
+
ipcMain.handle('browser:save-recording', validated(schemas.browserSaveRecording, async ({ defaultName, text }) => {
|
|
440
|
+
try {
|
|
441
|
+
const result = await dialog.showSaveDialog(mainWindow, {
|
|
442
|
+
defaultPath: defaultName,
|
|
443
|
+
filters: [
|
|
444
|
+
{ name: 'Markdown', extensions: ['md'] },
|
|
445
|
+
{ name: 'All Files', extensions: ['*'] },
|
|
446
|
+
],
|
|
447
|
+
});
|
|
448
|
+
if (result.canceled || !result.filePath) return { ok: false, canceled: true };
|
|
449
|
+
await fsp.writeFile(result.filePath, text, 'utf8');
|
|
450
|
+
return { ok: true, path: result.filePath };
|
|
451
|
+
} catch (e) {
|
|
452
|
+
return { ok: false, error: e && e.message ? e.message : String(e) };
|
|
453
|
+
}
|
|
454
|
+
}));
|
|
455
|
+
|
|
437
456
|
// Image paste — Ctrl+V in the Terminal pane. Reads the OS clipboard via
|
|
438
457
|
// Electron's native API (renderer's navigator.clipboard.read() doesn't expose
|
|
439
458
|
// raw image MIME types under contextIsolation), saves the bitmap to a temp
|
|
@@ -469,6 +488,16 @@ ipcMain.handle('clipboard:paste-text', async () => {
|
|
|
469
488
|
}
|
|
470
489
|
});
|
|
471
490
|
|
|
491
|
+
// Recorder export "Copy to clipboard" (PRD 412) — write side.
|
|
492
|
+
ipcMain.handle('clipboard:write-text', validated(schemas.clipboardWriteText, ({ text }) => {
|
|
493
|
+
try {
|
|
494
|
+
clipboard.writeText(text);
|
|
495
|
+
return { ok: true };
|
|
496
|
+
} catch (e) {
|
|
497
|
+
return { ok: false, error: e && e.message ? e.message : String(e) };
|
|
498
|
+
}
|
|
499
|
+
}));
|
|
500
|
+
|
|
472
501
|
// PRD 407 Capture panel — write side of paste-image's read. Writes a
|
|
473
502
|
// screenshot capture to the OS clipboard as an image.
|
|
474
503
|
ipcMain.handle('browser:copy-image', validated(schemas.browserCopyImage, ({ dataUrl }) => {
|
package/src/main/ipcSchemas.cjs
CHANGED
|
@@ -96,6 +96,19 @@ const browserCopyImage = z.object({
|
|
|
96
96
|
dataUrl: z.string().min(1).max(50_000_000),
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
// Recorder export (PRD 412): write arbitrary recorded-flow text to the OS
|
|
100
|
+
// clipboard, separate from the image-only browserCopyImage above.
|
|
101
|
+
const clipboardWriteText = z.object({
|
|
102
|
+
text: z.string().max(1_000_000),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Recorder export (PRD 412): native "Save As" dialog write, bypassing the
|
|
106
|
+
// config.cjs write-boundary since the path is user-chosen via OS dialog.
|
|
107
|
+
const browserSaveRecording = z.object({
|
|
108
|
+
defaultName: z.string().min(1).max(255),
|
|
109
|
+
text: z.string().max(1_000_000),
|
|
110
|
+
});
|
|
111
|
+
|
|
99
112
|
// PRD 407: binary-safe atomic write (browser:save-binary) for screenshot
|
|
100
113
|
// captures — config:write-text is utf8-only.
|
|
101
114
|
const browserSaveBinary = z.object({
|
|
@@ -621,6 +634,8 @@ module.exports = {
|
|
|
621
634
|
browserCaptureSelection,
|
|
622
635
|
browserCopyImage,
|
|
623
636
|
browserSaveBinary,
|
|
637
|
+
clipboardWriteText,
|
|
638
|
+
browserSaveRecording,
|
|
624
639
|
browserReplay,
|
|
625
640
|
browserSetZoom,
|
|
626
641
|
browserFind,
|
package/src/main/scheduler.cjs
CHANGED
|
@@ -1924,8 +1924,13 @@ function selectHistoryJobs(jobs, limit) {
|
|
|
1924
1924
|
// Transcript-scan verdicts that re-running verifyRun can re-evaluate. NOT
|
|
1925
1925
|
// 'uncommitted_changes' — that comes from the git commit-guard, which verifyRun
|
|
1926
1926
|
// does not inspect, so re-scanning it would always return 'clean' and wrongly
|
|
1927
|
-
// heal a genuinely-unfinished job.
|
|
1928
|
-
|
|
1927
|
+
// heal a genuinely-unfinished job. 'no_verdict_sentinel' is included because
|
|
1928
|
+
// its raising condition (sentinel === null && !committedDuringRun) depends on
|
|
1929
|
+
// commit-detection, which committedInWindow() can fix retroactively (e.g. the
|
|
1930
|
+
// git-log --all scan added for missed non-HEAD commits) — rescanning lets a
|
|
1931
|
+
// job whose commit is now correctly detected clear on its own instead of
|
|
1932
|
+
// staying stuck in needs_review forever.
|
|
1933
|
+
const RESCANNABLE_VERDICTS = new Set(['transcript_errors', 'verify_unavailable', 'no_verdict_sentinel']);
|
|
1929
1934
|
|
|
1930
1935
|
/**
|
|
1931
1936
|
* Backfill a job's missing runId by scanning RUNS_DIR for a run directory
|
package/src/preload/api.d.ts
CHANGED
|
@@ -1066,6 +1066,13 @@ export interface SessionManagerAPI {
|
|
|
1066
1066
|
| { ok: false; error: string }
|
|
1067
1067
|
>;
|
|
1068
1068
|
saveBinary: (path: string, base64: string) => Promise<{ ok: boolean; error?: string }>;
|
|
1069
|
+
/** Opens a native "Save As" dialog and writes `text` to the chosen path directly
|
|
1070
|
+
* (bypasses config.cjs's write-boundary check — the path is user-chosen via OS dialog). */
|
|
1071
|
+
saveRecording: (payload: { defaultName: string; text: string }) => Promise<
|
|
1072
|
+
| { ok: true; path: string }
|
|
1073
|
+
| { ok: false; canceled: true }
|
|
1074
|
+
| { ok: false; error: string }
|
|
1075
|
+
>;
|
|
1069
1076
|
replay: (payload: {
|
|
1070
1077
|
viewId: string;
|
|
1071
1078
|
steps: RecordStep[];
|
|
@@ -1271,6 +1278,8 @@ export interface SessionManagerAPI {
|
|
|
1271
1278
|
>;
|
|
1272
1279
|
/** Write side — copies a Capture-panel screenshot data URL to the OS clipboard. */
|
|
1273
1280
|
copyImage: (dataUrl: string) => Promise<{ ok: boolean; error?: string }>;
|
|
1281
|
+
/** Write side — copies arbitrary text (e.g. a recorded flow export) to the OS clipboard. */
|
|
1282
|
+
writeText: (text: string) => Promise<{ ok: boolean; error?: string }>;
|
|
1274
1283
|
};
|
|
1275
1284
|
memory: {
|
|
1276
1285
|
/** List markdown memory entries for the given workspace (defaults to 'default'). */
|
package/src/preload/index.cjs
CHANGED
|
@@ -82,6 +82,7 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
82
82
|
captureDom: (payload) => ipcRenderer.invoke('browser:capture-dom', payload),
|
|
83
83
|
captureShot: (viewId) => ipcRenderer.invoke('browser:capture-shot', { viewId }),
|
|
84
84
|
saveBinary: (path, base64) => ipcRenderer.invoke('browser:save-binary', { path, base64 }),
|
|
85
|
+
saveRecording: (payload) => ipcRenderer.invoke('browser:save-recording', payload),
|
|
85
86
|
replay: (payload) => ipcRenderer.invoke('browser:replay', payload),
|
|
86
87
|
onReplayStep: (viewId, handler) => {
|
|
87
88
|
const channel = `browser:replay-step:${viewId}`;
|
|
@@ -289,6 +290,7 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
289
290
|
pasteImage: () => ipcRenderer.invoke('clipboard:paste-image'),
|
|
290
291
|
pasteText: () => ipcRenderer.invoke('clipboard:paste-text'),
|
|
291
292
|
copyImage: (dataUrl) => ipcRenderer.invoke('browser:copy-image', { dataUrl }),
|
|
293
|
+
writeText: (text) => ipcRenderer.invoke('clipboard:write-text', { text }),
|
|
292
294
|
},
|
|
293
295
|
memory: {
|
|
294
296
|
list: (workspace) => ipcRenderer.invoke('memory:list', workspace ? { workspace } : {}),
|