claude-code-session-manager 0.20.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 (32) hide show
  1. package/dist/assets/{TiptapBody-COZHDXvn.js → TiptapBody-Db7_uXrI.js} +1 -1
  2. package/dist/assets/{cssMode-BGlgF50F.js → cssMode-DFKJhhi6.js} +1 -1
  3. package/dist/assets/{freemarker2-CwlJczaA.js → freemarker2-DUat8x8o.js} +1 -1
  4. package/dist/assets/{handlebars-C7ChleGP.js → handlebars-B2C1qhAI.js} +1 -1
  5. package/dist/assets/{html-C0XyedAq.js → html-khtg0DVs.js} +1 -1
  6. package/dist/assets/{htmlMode-DTJsOfuO.js → htmlMode-Jmhs-vfl.js} +1 -1
  7. package/dist/assets/{index-6poesY86.css → index-BkkBX1z7.css} +1 -1
  8. package/dist/assets/{index-C4joLNKY.js → index-pqnuXM14.js} +588 -578
  9. package/dist/assets/{javascript-CPRB5GUm.js → javascript-i1CXbgg4.js} +1 -1
  10. package/dist/assets/{jsonMode-DKBN0s8-.js → jsonMode-DXZaj-kR.js} +1 -1
  11. package/dist/assets/{liquid-CJmNIgnK.js → liquid-Ds7jUF53.js} +1 -1
  12. package/dist/assets/{lspLanguageFeatures-CIIba3v8.js → lspLanguageFeatures-B_15vO6X.js} +1 -1
  13. package/dist/assets/{mdx-BOiNk1a1.js → mdx-DgrrLgTE.js} +1 -1
  14. package/dist/assets/{python-5AV3HPYJ.js → python-Cff3tPw3.js} +1 -1
  15. package/dist/assets/{razor-6iMJA6dH.js → razor-DlyG7FmM.js} +1 -1
  16. package/dist/assets/{tsMode-WJISqg3-.js → tsMode-DRmmmttS.js} +1 -1
  17. package/dist/assets/{typescript-CnA0yZf9.js → typescript-DQFL2T1p.js} +1 -1
  18. package/dist/assets/{xml-BLkNwYO2.js → xml-CwsJEzdU.js} +1 -1
  19. package/dist/assets/{yaml-D6anZ1nO.js → yaml-BDsDjf-y.js} +1 -1
  20. package/dist/index.html +2 -2
  21. package/package.json +3 -1
  22. package/src/main/historyAggregator.cjs +15 -9
  23. package/src/main/index.cjs +7 -2
  24. package/src/main/ipcSchemas.cjs +43 -0
  25. package/src/main/kg.cjs +27 -17
  26. package/src/main/lib/reaperHelpers.cjs +67 -0
  27. package/src/main/lib/schedulerBatch.cjs +212 -0
  28. package/src/main/scheduler.cjs +173 -125
  29. package/src/main/webRemote.cjs +916 -0
  30. package/src/preload/api.d.ts +50 -9
  31. package/src/preload/index.cjs +34 -5
  32. 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,6 +1058,20 @@ 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
1076
  /** Distilled knowledge graph + ingest status for ONE project (`cwd`).
1038
1077
  * Omit `cwd` for the most-active project. */
@@ -1096,11 +1135,13 @@ export interface KgState {
1096
1135
  };
1097
1136
  }
1098
1137
  export interface KgIngestProgress {
1099
- phase: 'start' | 'extract' | 'done' | 'error';
1138
+ phase: 'start' | 'extract' | 'batch' | 'done' | 'error';
1100
1139
  ingesting: boolean;
1101
1140
  batch?: number;
1102
1141
  totalBatches?: number;
1103
1142
  added?: number;
1143
+ /** Set on `batch`: the project cwd whose graph just committed. */
1144
+ cwd?: string;
1104
1145
  error?: string;
1105
1146
  }
1106
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,6 +276,40 @@ 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
314
  /** Knowledge Graph distilled from the prompt log (~/.claude/knowledge-log),
286
315
  * segregated per project. `cwd` selects which project's graph; omit for the
@@ -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
- };