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.
Files changed (35) hide show
  1. package/dist/assets/{TiptapBody-CO4q65kH.js → TiptapBody-Db7_uXrI.js} +1 -1
  2. package/dist/assets/{cssMode-0tbceX4i.js → cssMode-DFKJhhi6.js} +1 -1
  3. package/dist/assets/{freemarker2-Dv8wl_HH.js → freemarker2-DUat8x8o.js} +1 -1
  4. package/dist/assets/{handlebars-MzrjkW3b.js → handlebars-B2C1qhAI.js} +1 -1
  5. package/dist/assets/{html-C0YEYUHk.js → html-khtg0DVs.js} +1 -1
  6. package/dist/assets/{htmlMode-Bf9ccIo3.js → htmlMode-Jmhs-vfl.js} +1 -1
  7. package/dist/assets/{index-BsSklu93.css → index-BkkBX1z7.css} +1 -1
  8. package/dist/assets/{index-BXeFi7dA.js → index-pqnuXM14.js} +634 -624
  9. package/dist/assets/{javascript-BZhQgLYg.js → javascript-i1CXbgg4.js} +1 -1
  10. package/dist/assets/{jsonMode-XkKuSIs5.js → jsonMode-DXZaj-kR.js} +1 -1
  11. package/dist/assets/{liquid-B6fnroVU.js → liquid-Ds7jUF53.js} +1 -1
  12. package/dist/assets/{lspLanguageFeatures-BAIq7N4N.js → lspLanguageFeatures-B_15vO6X.js} +1 -1
  13. package/dist/assets/{mdx-DzH38OXA.js → mdx-DgrrLgTE.js} +1 -1
  14. package/dist/assets/{python-ak0De5ar.js → python-Cff3tPw3.js} +1 -1
  15. package/dist/assets/{razor-DC-IpQpX.js → razor-DlyG7FmM.js} +1 -1
  16. package/dist/assets/{tsMode-DaZCqNuS.js → tsMode-DRmmmttS.js} +1 -1
  17. package/dist/assets/{typescript-D5YkmMgh.js → typescript-DQFL2T1p.js} +1 -1
  18. package/dist/assets/{whisperWorker-CcsPqZUS.js → whisperWorker-Dbia1OpC.js} +15 -15
  19. package/dist/assets/{xml-8idHpw2C.js → xml-CwsJEzdU.js} +1 -1
  20. package/dist/assets/{yaml-Dm8NKlcv.js → yaml-BDsDjf-y.js} +1 -1
  21. package/dist/index.html +2 -2
  22. package/package.json +5 -2
  23. package/src/main/health.cjs +216 -0
  24. package/src/main/historyAggregator.cjs +15 -9
  25. package/src/main/index.cjs +7 -2
  26. package/src/main/ipcSchemas.cjs +43 -0
  27. package/src/main/kg.cjs +0 -0
  28. package/src/main/lib/reaperHelpers.cjs +67 -0
  29. package/src/main/lib/schedulerBatch.cjs +212 -0
  30. package/src/main/lib/schedulerConfig.cjs +9 -1
  31. package/src/main/scheduler.cjs +274 -125
  32. package/src/main/webRemote.cjs +916 -0
  33. package/src/preload/api.d.ts +78 -15
  34. package/src/preload/index.cjs +41 -8
  35. package/src/main/projectSkills.cjs +0 -124
@@ -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 over the prompt log. */
1038
- get: () => Promise<KgState>;
1039
- /** Process new prompt-log lines into the graph (incremental). */
1040
- ingest: () => Promise<{ ok: boolean; added?: number; nodes?: number; edges?: number; error?: string; note?: string }>;
1041
- /** Ask a question answered from the graph + your real prompts via claude -p. */
1042
- ask: (question: string) => Promise<{ ok: boolean; answer?: string; cited?: { ts: string; prompt: string }[]; error?: string }>;
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
 
@@ -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
- get: () => ipcRenderer.invoke('kg:get'),
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
- };