claude-code-session-manager 0.19.0 → 0.20.1
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-CO4q65kH.js → TiptapBody-Db7_uXrI.js} +1 -1
- package/dist/assets/{cssMode-0tbceX4i.js → cssMode-DFKJhhi6.js} +1 -1
- package/dist/assets/{freemarker2-Dv8wl_HH.js → freemarker2-DUat8x8o.js} +1 -1
- package/dist/assets/{handlebars-MzrjkW3b.js → handlebars-B2C1qhAI.js} +1 -1
- package/dist/assets/{html-C0YEYUHk.js → html-khtg0DVs.js} +1 -1
- package/dist/assets/{htmlMode-Bf9ccIo3.js → htmlMode-Jmhs-vfl.js} +1 -1
- package/dist/assets/{index-BsSklu93.css → index-BkkBX1z7.css} +1 -1
- package/dist/assets/{index-BXeFi7dA.js → index-pqnuXM14.js} +634 -624
- package/dist/assets/{javascript-BZhQgLYg.js → javascript-i1CXbgg4.js} +1 -1
- package/dist/assets/{jsonMode-XkKuSIs5.js → jsonMode-DXZaj-kR.js} +1 -1
- package/dist/assets/{liquid-B6fnroVU.js → liquid-Ds7jUF53.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-BAIq7N4N.js → lspLanguageFeatures-B_15vO6X.js} +1 -1
- package/dist/assets/{mdx-DzH38OXA.js → mdx-DgrrLgTE.js} +1 -1
- package/dist/assets/{python-ak0De5ar.js → python-Cff3tPw3.js} +1 -1
- package/dist/assets/{razor-DC-IpQpX.js → razor-DlyG7FmM.js} +1 -1
- package/dist/assets/{tsMode-DaZCqNuS.js → tsMode-DRmmmttS.js} +1 -1
- package/dist/assets/{typescript-D5YkmMgh.js → typescript-DQFL2T1p.js} +1 -1
- package/dist/assets/{whisperWorker-CcsPqZUS.js → whisperWorker-Dbia1OpC.js} +15 -15
- package/dist/assets/{xml-8idHpw2C.js → xml-CwsJEzdU.js} +1 -1
- package/dist/assets/{yaml-Dm8NKlcv.js → yaml-BDsDjf-y.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +5 -2
- package/src/main/health.cjs +216 -0
- package/src/main/historyAggregator.cjs +15 -9
- package/src/main/index.cjs +7 -2
- package/src/main/ipcSchemas.cjs +43 -0
- package/src/main/kg.cjs +0 -0
- package/src/main/lib/reaperHelpers.cjs +67 -0
- package/src/main/lib/schedulerBatch.cjs +212 -0
- package/src/main/lib/schedulerConfig.cjs +9 -1
- package/src/main/scheduler.cjs +274 -125
- package/src/main/webRemote.cjs +916 -0
- package/src/preload/api.d.ts +78 -15
- package/src/preload/index.cjs +41 -8
- package/src/main/projectSkills.cjs +0 -124
package/src/preload/api.d.ts
CHANGED
|
@@ -452,10 +452,6 @@ export interface ListConversationsResult {
|
|
|
452
452
|
scannedMs: number;
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
-
export interface ProjectSkillState {
|
|
456
|
-
skillId: string;
|
|
457
|
-
enabled: boolean;
|
|
458
|
-
}
|
|
459
455
|
|
|
460
456
|
export interface FileEntry {
|
|
461
457
|
name: string;
|
|
@@ -786,6 +782,39 @@ export interface SuperAgentStateChangedEvent {
|
|
|
786
782
|
state: SuperAgentRunState | null;
|
|
787
783
|
}
|
|
788
784
|
|
|
785
|
+
// ────────────────────────────────────────────── Web Remote (PRD 08)
|
|
786
|
+
|
|
787
|
+
export interface WebRemoteDevice {
|
|
788
|
+
deviceId: string;
|
|
789
|
+
deviceName: string;
|
|
790
|
+
issuedAt: string;
|
|
791
|
+
lastConnectedAt: string | null;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
export interface WebRemoteStatus {
|
|
795
|
+
enabled: boolean;
|
|
796
|
+
connected: boolean;
|
|
797
|
+
e2eActive: boolean;
|
|
798
|
+
devices: WebRemoteDevice[];
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
export interface WebRemotePairResult {
|
|
802
|
+
ok: boolean;
|
|
803
|
+
deviceId?: string;
|
|
804
|
+
error?: string;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
export interface WebRemoteMutationResult {
|
|
808
|
+
ok: boolean;
|
|
809
|
+
error?: string;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
export interface WebRemoteAuditTailResult {
|
|
813
|
+
ok: boolean;
|
|
814
|
+
lines?: string[];
|
|
815
|
+
error?: string;
|
|
816
|
+
}
|
|
817
|
+
|
|
789
818
|
export interface SessionManagerAPI {
|
|
790
819
|
app: {
|
|
791
820
|
version: () => Promise<string>;
|
|
@@ -894,10 +923,6 @@ export interface SessionManagerAPI {
|
|
|
894
923
|
status: () => Promise<OtelStatus>;
|
|
895
924
|
configPath: () => Promise<string>;
|
|
896
925
|
};
|
|
897
|
-
projectSkills: {
|
|
898
|
-
get: (cwd: string) => Promise<ProjectSkillState[]>;
|
|
899
|
-
set: (cwd: string, skillId: string, enabled: boolean) => Promise<{ ok: boolean }>;
|
|
900
|
-
};
|
|
901
926
|
files: {
|
|
902
927
|
list: (path: string, showHidden?: boolean) => Promise<FilesListResult>;
|
|
903
928
|
read: (path: string) => Promise<FilesReadResult>;
|
|
@@ -1033,17 +1058,49 @@ export interface SessionManagerAPI {
|
|
|
1033
1058
|
stop: (tabId: string) => Promise<{ ok: boolean }>;
|
|
1034
1059
|
onStateChanged: (handler: (ev: SuperAgentStateChangedEvent) => void) => () => void;
|
|
1035
1060
|
};
|
|
1061
|
+
webRemote: {
|
|
1062
|
+
getStatus: () => Promise<WebRemoteStatus>;
|
|
1063
|
+
enable: () => Promise<WebRemoteMutationResult>;
|
|
1064
|
+
disable: () => Promise<WebRemoteMutationResult>;
|
|
1065
|
+
pair: (otp: string) => Promise<WebRemotePairResult>;
|
|
1066
|
+
revokeDevice: (deviceId: string) => Promise<WebRemoteMutationResult>;
|
|
1067
|
+
auditTail: (lines?: number) => Promise<WebRemoteAuditTailResult>;
|
|
1068
|
+
onStatus: (handler: (status: WebRemoteStatus) => void) => () => void;
|
|
1069
|
+
onTokenRevoked: (handler: (ev: { deviceId: string }) => void) => () => void;
|
|
1070
|
+
/** Revoke ALL paired devices and tear down every session immediately (panic). */
|
|
1071
|
+
revokeAll: () => Promise<WebRemoteMutationResult>;
|
|
1072
|
+
/** Subscribe to the completion event broadcast after revokeAll. */
|
|
1073
|
+
onRevokedAll: (handler: (ev: { revokedCount: number }) => void) => () => void;
|
|
1074
|
+
};
|
|
1036
1075
|
kg: {
|
|
1037
|
-
/** Distilled knowledge graph + ingest status
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1076
|
+
/** Distilled knowledge graph + ingest status for ONE project (`cwd`).
|
|
1077
|
+
* Omit `cwd` for the most-active project. */
|
|
1078
|
+
get: (cwd?: string) => Promise<KgState>;
|
|
1079
|
+
/** Projects seen in the prompt log, with per-project graph stats. */
|
|
1080
|
+
projects: () => Promise<KgProject[]>;
|
|
1081
|
+
/** Process new prompt-log lines into per-project graphs (incremental, global). */
|
|
1082
|
+
ingest: () => Promise<{ ok: boolean; added?: number; projects?: number; stopped?: boolean; error?: string; note?: string }>;
|
|
1083
|
+
/** Ask a question answered from ONE project's graph + prompts via claude -p. */
|
|
1084
|
+
ask: (question: string, cwd?: string) => Promise<{ ok: boolean; answer?: string; cited?: { ts: string; prompt: string }[]; error?: string }>;
|
|
1043
1085
|
onIngestProgress: (handler: (ev: KgIngestProgress) => void) => () => void;
|
|
1044
1086
|
};
|
|
1045
1087
|
}
|
|
1046
1088
|
|
|
1089
|
+
export interface KgProject {
|
|
1090
|
+
cwd: string;
|
|
1091
|
+
/** Last path segment of `cwd`, for display. */
|
|
1092
|
+
label: string;
|
|
1093
|
+
/** Prompts logged for this project (real prompts only). */
|
|
1094
|
+
total: number;
|
|
1095
|
+
/** Prompts already distilled into this project's graph. */
|
|
1096
|
+
processed: number;
|
|
1097
|
+
/** total - processed. */
|
|
1098
|
+
pending: number;
|
|
1099
|
+
nodes: number;
|
|
1100
|
+
edges: number;
|
|
1101
|
+
lastIngest: string | null;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1047
1104
|
export interface KgNode {
|
|
1048
1105
|
id: string;
|
|
1049
1106
|
key: string;
|
|
@@ -1062,6 +1119,10 @@ export interface KgEdge {
|
|
|
1062
1119
|
lastTs: string | null;
|
|
1063
1120
|
}
|
|
1064
1121
|
export interface KgState {
|
|
1122
|
+
/** The project this graph belongs to. */
|
|
1123
|
+
cwd: string;
|
|
1124
|
+
/** Last path segment of `cwd`, for display. */
|
|
1125
|
+
label: string;
|
|
1065
1126
|
nodes: KgNode[];
|
|
1066
1127
|
edges: KgEdge[];
|
|
1067
1128
|
status: {
|
|
@@ -1074,11 +1135,13 @@ export interface KgState {
|
|
|
1074
1135
|
};
|
|
1075
1136
|
}
|
|
1076
1137
|
export interface KgIngestProgress {
|
|
1077
|
-
phase: 'start' | 'extract' | 'done' | 'error';
|
|
1138
|
+
phase: 'start' | 'extract' | 'batch' | 'done' | 'error';
|
|
1078
1139
|
ingesting: boolean;
|
|
1079
1140
|
batch?: number;
|
|
1080
1141
|
totalBatches?: number;
|
|
1081
1142
|
added?: number;
|
|
1143
|
+
/** Set on `batch`: the project cwd whose graph just committed. */
|
|
1144
|
+
cwd?: string;
|
|
1082
1145
|
error?: string;
|
|
1083
1146
|
}
|
|
1084
1147
|
|
package/src/preload/index.cjs
CHANGED
|
@@ -156,11 +156,6 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
156
156
|
aggregate: (req) => ipcRenderer.invoke('history:aggregate', req),
|
|
157
157
|
listConversations: () => ipcRenderer.invoke('history:list-conversations'),
|
|
158
158
|
},
|
|
159
|
-
projectSkills: {
|
|
160
|
-
get: (cwd) => ipcRenderer.invoke('project-skills:get', { cwd }),
|
|
161
|
-
set: (cwd, skillId, enabled) =>
|
|
162
|
-
ipcRenderer.invoke('project-skills:set', { cwd, skillId, enabled }),
|
|
163
|
-
},
|
|
164
159
|
files: {
|
|
165
160
|
list: (path, showHidden) => ipcRenderer.invoke('files:list', { path, showHidden }),
|
|
166
161
|
read: (path) => ipcRenderer.invoke('files:read', { path }),
|
|
@@ -281,11 +276,49 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
281
276
|
return () => ipcRenderer.removeListener('superagent:state-changed', listener);
|
|
282
277
|
},
|
|
283
278
|
},
|
|
279
|
+
webRemote: {
|
|
280
|
+
/** Current connection state (no token values). */
|
|
281
|
+
getStatus: () => ipcRenderer.invoke('webRemote:get-status'),
|
|
282
|
+
/** Turn remote control on. Initiates relay connection if a device is paired. */
|
|
283
|
+
enable: () => ipcRenderer.invoke('webRemote:enable'),
|
|
284
|
+
/** Turn remote control off. Immediately drops relay connection. */
|
|
285
|
+
disable: () => ipcRenderer.invoke('webRemote:disable'),
|
|
286
|
+
/** Pair a new device using the 8-character OTP shown in the web UI. */
|
|
287
|
+
pair: (otp) => ipcRenderer.invoke('webRemote:pair', { otp }),
|
|
288
|
+
/** Revoke a paired device by its deviceId. */
|
|
289
|
+
revokeDevice: (deviceId) => ipcRenderer.invoke('webRemote:revoke-device', { deviceId }),
|
|
290
|
+
/** Read the last N lines of today's audit log (default 50). */
|
|
291
|
+
auditTail: (lines) => ipcRenderer.invoke('webRemote:audit-tail', lines ? { lines } : {}),
|
|
292
|
+
/** Push event from main when connection status changes. */
|
|
293
|
+
onStatus: (handler) => {
|
|
294
|
+
const listener = (_e, payload) => handler(payload);
|
|
295
|
+
ipcRenderer.on('webRemote:status', listener);
|
|
296
|
+
return () => ipcRenderer.removeListener('webRemote:status', listener);
|
|
297
|
+
},
|
|
298
|
+
/** Push event when the relay revokes this device's token. */
|
|
299
|
+
onTokenRevoked: (handler) => {
|
|
300
|
+
const listener = (_e, payload) => handler(payload);
|
|
301
|
+
ipcRenderer.on('webRemote:token-revoked', listener);
|
|
302
|
+
return () => ipcRenderer.removeListener('webRemote:token-revoked', listener);
|
|
303
|
+
},
|
|
304
|
+
/** Revoke ALL paired devices and tear down every session immediately. */
|
|
305
|
+
revokeAll: () => ipcRenderer.invoke('webRemote:revoke-all'),
|
|
306
|
+
/** Push event when revokeAll completes (main broadcasts webRemote:revoked-all). */
|
|
307
|
+
onRevokedAll: (handler) => {
|
|
308
|
+
const listener = (_e, payload) => handler(payload);
|
|
309
|
+
ipcRenderer.on('webRemote:revoked-all', listener);
|
|
310
|
+
return () => ipcRenderer.removeListener('webRemote:revoked-all', listener);
|
|
311
|
+
},
|
|
312
|
+
},
|
|
284
313
|
kg: {
|
|
285
|
-
/** Knowledge Graph distilled from the prompt log (~/.claude/knowledge-log)
|
|
286
|
-
|
|
314
|
+
/** Knowledge Graph distilled from the prompt log (~/.claude/knowledge-log),
|
|
315
|
+
* segregated per project. `cwd` selects which project's graph; omit for the
|
|
316
|
+
* most-active project. */
|
|
317
|
+
get: (cwd) => ipcRenderer.invoke('kg:get', { cwd }),
|
|
318
|
+
/** Projects seen in the log, with per-project graph stats (for the selector). */
|
|
319
|
+
projects: () => ipcRenderer.invoke('kg:projects'),
|
|
287
320
|
ingest: () => ipcRenderer.invoke('kg:ingest'),
|
|
288
|
-
ask: (question) => ipcRenderer.invoke('kg:ask', { question }),
|
|
321
|
+
ask: (question, cwd) => ipcRenderer.invoke('kg:ask', { question, cwd }),
|
|
289
322
|
onIngestProgress: (handler) => {
|
|
290
323
|
const listener = (_e, payload) => handler(payload);
|
|
291
324
|
ipcRenderer.on('kg:ingest-progress', listener);
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ProjectSkills — per-project skill enable/disable state.
|
|
3
|
-
*
|
|
4
|
-
* Storage: <cwd>/.claude/project-skills.json
|
|
5
|
-
* Format: { skills: Array<{ skillId: string; enabled: boolean }>, schemaVersion: 1 }
|
|
6
|
-
*
|
|
7
|
-
* Reads enumerate all skills under <cwd>/.claude/skills/ and <home>/.claude/skills/
|
|
8
|
-
* and merge their enable state from the project-local config. Skills not listed in
|
|
9
|
-
* the JSON default to `enabled: true` (i.e., opt-out per project).
|
|
10
|
-
*
|
|
11
|
-
* IPC:
|
|
12
|
-
* - project-skills:get(cwd) -> SkillState[]
|
|
13
|
-
* - project-skills:set(cwd, skillId, enabled) -> { ok: boolean }
|
|
14
|
-
*
|
|
15
|
-
* Atomic writes go through config.cjs::writeJson. cwd is validated via
|
|
16
|
-
* validatePath which constrains it to allowedRoots (home + registered project
|
|
17
|
-
* dirs).
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
const { ipcMain } = require('electron');
|
|
21
|
-
const path = require('node:path');
|
|
22
|
-
const { z } = require('zod');
|
|
23
|
-
const { readJson, writeJson, addAllowedRoot } = require('./config.cjs');
|
|
24
|
-
|
|
25
|
-
const SCHEMA_VERSION = 1;
|
|
26
|
-
|
|
27
|
-
function projectSkillsPath(cwd) {
|
|
28
|
-
return path.join(cwd, '.claude', 'project-skills.json');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Load the project-skills.json record for a cwd. Missing file => empty record.
|
|
33
|
-
* Returns { skills: Array<{skillId, enabled}>, schemaVersion }.
|
|
34
|
-
*/
|
|
35
|
-
async function loadRecord(cwd) {
|
|
36
|
-
const filePath = projectSkillsPath(cwd);
|
|
37
|
-
const r = await readJson(filePath);
|
|
38
|
-
if (!r.exists || !r.data || typeof r.data !== 'object') {
|
|
39
|
-
return { skills: [], schemaVersion: SCHEMA_VERSION };
|
|
40
|
-
}
|
|
41
|
-
const data = r.data;
|
|
42
|
-
const skills = Array.isArray(data.skills) ? data.skills : [];
|
|
43
|
-
// Filter for well-formed entries; tolerate corruption silently.
|
|
44
|
-
const clean = [];
|
|
45
|
-
const seen = new Set();
|
|
46
|
-
for (const s of skills) {
|
|
47
|
-
if (!s || typeof s.skillId !== 'string' || typeof s.enabled !== 'boolean') continue;
|
|
48
|
-
if (seen.has(s.skillId)) continue;
|
|
49
|
-
seen.add(s.skillId);
|
|
50
|
-
clean.push({ skillId: s.skillId, enabled: s.enabled });
|
|
51
|
-
}
|
|
52
|
-
return { skills: clean, schemaVersion: SCHEMA_VERSION };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function saveRecord(cwd, record) {
|
|
56
|
-
const filePath = projectSkillsPath(cwd);
|
|
57
|
-
const payload = {
|
|
58
|
-
schemaVersion: SCHEMA_VERSION,
|
|
59
|
-
skills: record.skills,
|
|
60
|
-
savedAt: Date.now(),
|
|
61
|
-
};
|
|
62
|
-
return writeJson(filePath, payload);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Return the array of skill enable-states for a project cwd. */
|
|
66
|
-
async function getProjectSkills(cwd) {
|
|
67
|
-
// Register cwd so writeJson is permitted under <cwd>/.claude.
|
|
68
|
-
addAllowedRoot(cwd);
|
|
69
|
-
const record = await loadRecord(cwd);
|
|
70
|
-
return record.skills;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Upsert a single skillId's enabled flag. */
|
|
74
|
-
async function setProjectSkill(cwd, skillId, enabled) {
|
|
75
|
-
addAllowedRoot(cwd);
|
|
76
|
-
const record = await loadRecord(cwd);
|
|
77
|
-
const idx = record.skills.findIndex((s) => s.skillId === skillId);
|
|
78
|
-
if (idx >= 0) {
|
|
79
|
-
record.skills[idx] = { skillId, enabled };
|
|
80
|
-
} else {
|
|
81
|
-
record.skills.push({ skillId, enabled });
|
|
82
|
-
}
|
|
83
|
-
await saveRecord(cwd, record);
|
|
84
|
-
return { ok: true };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ──────────────────────────────────────────── IPC schemas
|
|
88
|
-
const projectSkillsCwd = z.object({
|
|
89
|
-
cwd: z.string().min(1).max(4096),
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const projectSkillsSet = z.object({
|
|
93
|
-
cwd: z.string().min(1).max(4096),
|
|
94
|
-
skillId: z.string().min(1).max(256),
|
|
95
|
-
enabled: z.boolean(),
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
function validated(schema, handler) {
|
|
99
|
-
return (_event, payload) => {
|
|
100
|
-
const parsed = schema.parse(payload);
|
|
101
|
-
return handler(parsed);
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function registerProjectSkillsHandlers() {
|
|
106
|
-
ipcMain.handle(
|
|
107
|
-
'project-skills:get',
|
|
108
|
-
validated(projectSkillsCwd, ({ cwd }) => getProjectSkills(cwd)),
|
|
109
|
-
);
|
|
110
|
-
ipcMain.handle(
|
|
111
|
-
'project-skills:set',
|
|
112
|
-
validated(projectSkillsSet, ({ cwd, skillId, enabled }) =>
|
|
113
|
-
setProjectSkill(cwd, skillId, enabled),
|
|
114
|
-
),
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
module.exports = {
|
|
119
|
-
registerProjectSkillsHandlers,
|
|
120
|
-
// Exported for tests / direct use.
|
|
121
|
-
getProjectSkills,
|
|
122
|
-
setProjectSkill,
|
|
123
|
-
projectSkillsPath,
|
|
124
|
-
};
|