claude-code-session-manager 0.33.1 → 0.35.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/README.md +5 -1
- package/dist/assets/{TiptapBody-BqQFXHkk.js → TiptapBody-BqDK21Pr.js} +51 -51
- package/dist/assets/index-CPTin6qz.css +32 -0
- package/dist/assets/index-zepGuf8m.js +3536 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/plugins/session-manager-dev/skills/discover-features/SKILL.md +95 -0
- package/plugins/session-manager-dev/skills/optimize-kpi/SKILL.md +9 -9
- package/plugins/session-manager-dev/skills/process-feedback/SKILL.md +77 -62
- package/plugins/session-manager-dev/skills/project-status/SKILL.md +13 -0
- package/src/main/__tests__/chat-queue.test.cjs +65 -0
- package/src/main/__tests__/chat-stop-signal.test.cjs +52 -0
- package/src/main/__tests__/exchanges.test.cjs +177 -0
- package/src/main/__tests__/files-reject-credentials.test.cjs +40 -0
- package/src/main/__tests__/kg-augment.test.cjs +195 -0
- package/src/main/__tests__/memoryAggregate.test.cjs +70 -0
- package/src/main/agentMemory.cjs +0 -21
- package/src/main/chatRunner.cjs +398 -0
- package/src/main/exchanges.cjs +125 -0
- package/src/main/files.cjs +20 -8
- package/src/main/historyAggregator.cjs +0 -162
- package/src/main/index.cjs +76 -57
- package/src/main/ipcSchemas.cjs +70 -30
- package/src/main/lib/kgExchangePairing.cjs +75 -0
- package/src/main/lib/reaperHelpers.cjs +7 -1
- package/src/main/lib/summarize.cjs +114 -0
- package/src/main/lib/toolUseClassify.cjs +19 -0
- package/src/main/memoryAggregate.cjs +250 -0
- package/src/main/pluginInstall.cjs +4 -2
- package/src/main/scheduler.cjs +67 -21
- package/src/main/supervisor.cjs +16 -0
- package/src/main/transcripts.cjs +22 -2
- package/src/main/voiceHotkey.cjs +0 -2
- package/src/main/webRemote.cjs +11 -78
- package/src/preload/api.d.ts +140 -125
- package/src/preload/index.cjs +50 -29
- package/dist/assets/index-1PpZBVUr.js +0 -3535
- package/dist/assets/index-AKeGl-VM.css +0 -32
- package/src/main/kg.cjs +0 -792
- package/src/main/lib/kgLite.cjs +0 -195
- package/src/main/lib/kgPrune.cjs +0 -87
package/src/main/webRemote.cjs
CHANGED
|
@@ -28,6 +28,7 @@ const { writeTextAtomic, validatePath } = require('./config.cjs');
|
|
|
28
28
|
const logs = require('./logs.cjs');
|
|
29
29
|
const { sendIfAlive } = require('./lib/sendToRenderer.cjs');
|
|
30
30
|
const { schemas } = require('./ipcSchemas.cjs');
|
|
31
|
+
const { summarize: _sharedSummarize } = require('./lib/summarize.cjs');
|
|
31
32
|
const { makeState, confirmSas: confirmSasLogic } = require('./lib/e2eStateMachine.cjs');
|
|
32
33
|
|
|
33
34
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
@@ -740,70 +741,9 @@ function startSessionListPush() {
|
|
|
740
741
|
}
|
|
741
742
|
|
|
742
743
|
// ─── SM-V2-03: mobile summary via Claude Haiku 4.5 ───────────────────────────
|
|
744
|
+
// Summarization logic lives in lib/summarize.cjs (shared with exchanges.cjs).
|
|
743
745
|
|
|
744
|
-
const SUMMARY_MIN_CHARS = 280;
|
|
745
|
-
const SUMMARY_MODEL = 'claude-haiku-4-5';
|
|
746
|
-
const SUMMARY_MAX_INPUT_CHARS = 24_000; // cap the turn text sent to Haiku (~6k tokens)
|
|
747
|
-
const SUMMARY_SYSTEM =
|
|
748
|
-
'Summarize this Claude Code assistant turn for a phone screen in 2 sentences max, ' +
|
|
749
|
-
'followed by an optional list of up to 3 short action items. Plain text only — no ' +
|
|
750
|
-
'markdown headers, no code blocks. Lead with what was done or decided.';
|
|
751
|
-
|
|
752
|
-
let _anthropicKeyCache = null; // memoized found key only (string); null = re-resolve
|
|
753
|
-
|
|
754
|
-
/** Resolve the Anthropic API key: env → web-remote.json → null (degrade to raw).
|
|
755
|
-
* Only a FOUND key is cached — if absent we re-resolve each call (cheap, loadConfig
|
|
756
|
-
* is TTL-cached) so adding the key to web-remote.json later takes effect without a restart. */
|
|
757
|
-
async function resolveAnthropicKey() {
|
|
758
|
-
if (_anthropicKeyCache) return _anthropicKeyCache;
|
|
759
|
-
const fromEnv = process.env.ANTHROPIC_API_KEY;
|
|
760
|
-
if (fromEnv && fromEnv.trim()) { _anthropicKeyCache = fromEnv.trim(); return _anthropicKeyCache; }
|
|
761
|
-
try {
|
|
762
|
-
const cfg = await loadConfig();
|
|
763
|
-
const k = cfg.anthropicApiKey;
|
|
764
|
-
if (typeof k === 'string' && k.trim()) { _anthropicKeyCache = k.trim(); return _anthropicKeyCache; }
|
|
765
|
-
} catch { /* fall through to null → re-resolve next time */ }
|
|
766
|
-
return null;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
/** POST to the Anthropic Messages API. Returns the first text block, or throws. */
|
|
770
|
-
function anthropicSummarize(apiKey, text) {
|
|
771
|
-
const body = JSON.stringify({
|
|
772
|
-
model: SUMMARY_MODEL,
|
|
773
|
-
max_tokens: 320,
|
|
774
|
-
system: SUMMARY_SYSTEM,
|
|
775
|
-
messages: [{ role: 'user', content: text.slice(0, SUMMARY_MAX_INPUT_CHARS) }],
|
|
776
|
-
});
|
|
777
|
-
return new Promise((resolve, reject) => {
|
|
778
|
-
const req = https.request('https://api.anthropic.com/v1/messages', {
|
|
779
|
-
method: 'POST',
|
|
780
|
-
headers: {
|
|
781
|
-
'content-type': 'application/json',
|
|
782
|
-
'x-api-key': apiKey,
|
|
783
|
-
'anthropic-version': '2023-06-01',
|
|
784
|
-
'content-length': Buffer.byteLength(body),
|
|
785
|
-
},
|
|
786
|
-
timeout: 20_000,
|
|
787
|
-
}, (res) => {
|
|
788
|
-
let data = '';
|
|
789
|
-
res.on('data', (c) => { data += c; });
|
|
790
|
-
res.on('end', () => {
|
|
791
|
-
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
792
|
-
return reject(new Error(`anthropic HTTP ${res.statusCode}`));
|
|
793
|
-
}
|
|
794
|
-
try {
|
|
795
|
-
const json = JSON.parse(data);
|
|
796
|
-
const block = Array.isArray(json.content) ? json.content.find((b) => b.type === 'text') : null;
|
|
797
|
-
if (!block?.text) return reject(new Error('no text in response'));
|
|
798
|
-
resolve(block.text.trim());
|
|
799
|
-
} catch (e) { reject(e); }
|
|
800
|
-
});
|
|
801
|
-
});
|
|
802
|
-
req.on('error', reject);
|
|
803
|
-
req.on('timeout', () => req.destroy(new Error('anthropic request timed out')));
|
|
804
|
-
req.end(body);
|
|
805
|
-
});
|
|
806
|
-
}
|
|
746
|
+
const SUMMARY_MIN_CHARS = 280; // below this, push raw — not worth an API call
|
|
807
747
|
|
|
808
748
|
/**
|
|
809
749
|
* Produce a mobile summary of the watcher's last completed assistant turn and push it.
|
|
@@ -823,22 +763,15 @@ async function maybeSummarize(w) {
|
|
|
823
763
|
return;
|
|
824
764
|
}
|
|
825
765
|
|
|
826
|
-
const
|
|
827
|
-
if (
|
|
828
|
-
|
|
829
|
-
pushEvent('event:session:summary', {
|
|
830
|
-
tabId: w.tabId, summary: text.slice(0, 600), ofMessageId, model: 'raw', degraded: 'no_api_key', ts: Date.now(),
|
|
831
|
-
});
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
try {
|
|
836
|
-
const summary = await anthropicSummarize(apiKey, text);
|
|
837
|
-
pushEvent('event:session:summary', { tabId: w.tabId, summary, ofMessageId, model: SUMMARY_MODEL, ts: Date.now() });
|
|
838
|
-
} catch (e) {
|
|
839
|
-
logs.writeLine({ scope: 'webRemote', level: 'warn', message: 'summary failed; pushing raw', meta: { error: e?.message } });
|
|
840
|
-
pushEvent('event:session:summary', { tabId: w.tabId, summary: text.slice(0, 600), ofMessageId, model: 'raw', degraded: 'api_error', ts: Date.now() });
|
|
766
|
+
const { summary, model, degraded } = await _sharedSummarize(text);
|
|
767
|
+
if (degraded) {
|
|
768
|
+
logs.writeLine({ scope: 'webRemote', level: 'warn', message: `summary degraded: ${degraded}`, meta: {} });
|
|
841
769
|
}
|
|
770
|
+
pushEvent('event:session:summary', {
|
|
771
|
+
tabId: w.tabId, summary, ofMessageId, model,
|
|
772
|
+
...(degraded ? { degraded } : {}),
|
|
773
|
+
ts: Date.now(),
|
|
774
|
+
});
|
|
842
775
|
}
|
|
843
776
|
|
|
844
777
|
// ─── Message handling & command dispatch ─────────────────────────────────────
|
package/src/preload/api.d.ts
CHANGED
|
@@ -443,24 +443,6 @@ export interface HistoryAggregateResult {
|
|
|
443
443
|
scannedMs: number;
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
export interface ConversationSummary {
|
|
447
|
-
/** ISO 8601 timestamp of the first event in the conversation (or file mtime fallback). */
|
|
448
|
-
timestamp: string;
|
|
449
|
-
/** Decoded project cwd, e.g. /home/user/Projects/foo. */
|
|
450
|
-
projectFolder: string;
|
|
451
|
-
stats: {
|
|
452
|
-
/** Wall-clock duration in ms (first event ts → last event ts). Omitted when unknown. */
|
|
453
|
-
duration?: number;
|
|
454
|
-
/** Sum of input + output tokens across the file. 0 when no usage blocks present. */
|
|
455
|
-
estimatedTokens: number;
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export interface ListConversationsResult {
|
|
460
|
-
conversations: ConversationSummary[];
|
|
461
|
-
scannedMs: number;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
446
|
export interface SessionScanEntry {
|
|
465
447
|
sessionId: string;
|
|
466
448
|
projectEncoded: string;
|
|
@@ -490,7 +472,6 @@ export interface FilesWriteResult { ok: boolean; error: string | null }
|
|
|
490
472
|
export interface FilesCreateResult { ok: boolean; path?: string; error: string | null }
|
|
491
473
|
export interface FilesRenameResult { ok: boolean; newPath?: string; error: string | null }
|
|
492
474
|
export interface FilesDeleteResult { ok: boolean; error: string | null }
|
|
493
|
-
export interface FilesShellResult { ok: boolean; error?: string }
|
|
494
475
|
|
|
495
476
|
export interface SearchFileEntry {
|
|
496
477
|
name: string;
|
|
@@ -681,6 +662,29 @@ export interface MemoryMutationResult {
|
|
|
681
662
|
error: string | null;
|
|
682
663
|
}
|
|
683
664
|
|
|
665
|
+
export interface MemoryClusterLink {
|
|
666
|
+
from: string;
|
|
667
|
+
to: string;
|
|
668
|
+
label?: string;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
export interface MemoryCluster {
|
|
672
|
+
id: string;
|
|
673
|
+
name: string;
|
|
674
|
+
summary: string;
|
|
675
|
+
memberSlugs: string[];
|
|
676
|
+
links: MemoryClusterLink[];
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
export interface MemoryAggregateResult {
|
|
680
|
+
workspace: string;
|
|
681
|
+
generatedAt: number | null;
|
|
682
|
+
clusters: MemoryCluster[];
|
|
683
|
+
orphans: string[];
|
|
684
|
+
cached: boolean;
|
|
685
|
+
error?: string;
|
|
686
|
+
}
|
|
687
|
+
|
|
684
688
|
// ────────────────────────────────────────────── Per-subagent memory
|
|
685
689
|
// Stored at ~/.claude/session-manager/agent-memory/<agentId>.json. Keyed by
|
|
686
690
|
// agent name (the .md filename in ~/.claude/agents/), not by workspace cwd.
|
|
@@ -712,17 +716,6 @@ export interface AgentMemoryMutationResult {
|
|
|
712
716
|
error: string | null;
|
|
713
717
|
}
|
|
714
718
|
|
|
715
|
-
export interface AgentMemoryAgentSummary {
|
|
716
|
-
agentId: string;
|
|
717
|
-
bytes: number;
|
|
718
|
-
mtimeMs: number;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
export interface AgentMemoryListAgentsResult {
|
|
722
|
-
agents: AgentMemoryAgentSummary[];
|
|
723
|
-
error: string | null;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
719
|
// ────────────────────────────────────────────── Git status (richer than app:git-branch)
|
|
727
720
|
|
|
728
721
|
/** Mirrors the status returned by src/main/git.cjs mapStatus(). */
|
|
@@ -845,6 +838,67 @@ export interface WebRemoteAuditTailResult {
|
|
|
845
838
|
error?: string;
|
|
846
839
|
}
|
|
847
840
|
|
|
841
|
+
// ────────────────────────────────────────────── Chat runner (PRD 319)
|
|
842
|
+
|
|
843
|
+
export interface ChatRunPayload {
|
|
844
|
+
tabId: string;
|
|
845
|
+
/** UUID for the claude session — created by the caller; stays the same across
|
|
846
|
+
* resumes so transcript context carries forward. */
|
|
847
|
+
sessionId: string;
|
|
848
|
+
prompt: string;
|
|
849
|
+
cwd: string;
|
|
850
|
+
/** When true, use --resume <sessionId> instead of --session-id. */
|
|
851
|
+
resume?: boolean;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
export interface ChatRunQueuedEvent {
|
|
855
|
+
tabId: string;
|
|
856
|
+
sessionId: string;
|
|
857
|
+
/** 1-based position in the FIFO queue while waiting behind a busy lane. */
|
|
858
|
+
position: number;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
export interface ChatRunStartedEvent {
|
|
862
|
+
tabId: string;
|
|
863
|
+
sessionId: string;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
export interface ChatRunOutputEvent {
|
|
867
|
+
tabId: string;
|
|
868
|
+
/** Incremental text delta from one assistant content block. */
|
|
869
|
+
delta: string;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
export interface ChatRunToolUseEvent {
|
|
873
|
+
tabId: string;
|
|
874
|
+
/** tool_use content block id from the stream-json event. */
|
|
875
|
+
id: string;
|
|
876
|
+
kind: 'skill' | 'mcp' | 'tool';
|
|
877
|
+
label: string;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
export interface ChatRunNeedsInputEvent {
|
|
881
|
+
tabId: string;
|
|
882
|
+
sessionId: string;
|
|
883
|
+
/** Questions the agent is blocked on. */
|
|
884
|
+
questions: string[];
|
|
885
|
+
/** Full raw assistant text including the stop-signal sentinel. */
|
|
886
|
+
raw: string;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
export interface ChatRunCompleteEvent {
|
|
890
|
+
tabId: string;
|
|
891
|
+
sessionId: string;
|
|
892
|
+
/** The run's own final assistant message verbatim. */
|
|
893
|
+
finalMessage: string;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
export interface ChatRunErrorEvent {
|
|
897
|
+
tabId: string;
|
|
898
|
+
sessionId: string;
|
|
899
|
+
message: string;
|
|
900
|
+
}
|
|
901
|
+
|
|
848
902
|
export interface SessionManagerAPI {
|
|
849
903
|
app: {
|
|
850
904
|
version: () => Promise<string>;
|
|
@@ -867,16 +921,6 @@ export interface SessionManagerAPI {
|
|
|
867
921
|
homeSelfCheck: () => Promise<{ ok: boolean; error?: string; realCwd?: string }>;
|
|
868
922
|
onNewSession: (handler: () => void) => () => void;
|
|
869
923
|
onRebootSession: (handler: () => void) => () => void;
|
|
870
|
-
openInEditor: (cwd: string, editor?: string | null) => Promise<{ ok: boolean; opener?: string; error?: string }>;
|
|
871
|
-
/** Open an http/https URL in the OS default browser. file://, javascript:,
|
|
872
|
-
* and other schemes are rejected with `ok:false` to prevent abuse. */
|
|
873
|
-
openExternal: (url: string) => Promise<{ ok: boolean; error?: string }>;
|
|
874
|
-
/** Open a specific file at line:col in the user's editor. Editors with
|
|
875
|
-
* goto-line support (code/cursor/subl) get the `-g file:line:col` form;
|
|
876
|
-
* others open the file alone. Image files are routed to the OS default viewer. */
|
|
877
|
-
openFileInEditor: (filePath: string, line?: number, col?: number, editor?: string | null) => Promise<{ ok: boolean; opener?: string; error?: string }>;
|
|
878
|
-
openInFinder: (cwd: string) => Promise<{ ok: boolean; opener?: string; error?: string }>;
|
|
879
|
-
openInTerminal: (cwd: string) => Promise<{ ok: boolean; opener?: string; error?: string }>;
|
|
880
924
|
archiveProject: (encoded: string) => Promise<{ ok: boolean; error?: string }>;
|
|
881
925
|
};
|
|
882
926
|
pty: {
|
|
@@ -929,7 +973,6 @@ export interface SessionManagerAPI {
|
|
|
929
973
|
onHotkeyConfigChanged: (handler: (cfg: VoiceHotkeyConfig) => void) => () => void;
|
|
930
974
|
getHotkeyConfig: () => Promise<VoiceHotkeyConfig>;
|
|
931
975
|
setHotkeyConfig: (cfg: VoiceHotkeyConfig) => Promise<VoiceSetHotkeyResult>;
|
|
932
|
-
getHotkeyConfigPath: () => Promise<string>;
|
|
933
976
|
setRecording: (recording: boolean) => void;
|
|
934
977
|
/** F5: read persisted audio-input device preference. */
|
|
935
978
|
getDevicePref: () => Promise<VoiceDevicePref>;
|
|
@@ -965,8 +1008,21 @@ export interface SessionManagerAPI {
|
|
|
965
1008
|
create: (parentPath: string, name: string, kind: 'file' | 'folder') => Promise<FilesCreateResult>;
|
|
966
1009
|
rename: (path: string, newName: string) => Promise<FilesRenameResult>;
|
|
967
1010
|
delete: (path: string) => Promise<FilesDeleteResult>;
|
|
968
|
-
|
|
969
|
-
|
|
1011
|
+
};
|
|
1012
|
+
/** Consolidated shell open/reveal. One method, discriminated on `as`, replaces
|
|
1013
|
+
* the former app.openIn* / app.openExternal / files.openExternal / files.showInFinder.
|
|
1014
|
+
* Each variant's boundary guard (home-scope / http(s)-only) runs in the main handler. */
|
|
1015
|
+
shell: {
|
|
1016
|
+
open: (
|
|
1017
|
+
opts:
|
|
1018
|
+
| { as: 'editor'; cwd: string; editor?: string | null }
|
|
1019
|
+
| { as: 'fileInEditor'; path: string; line?: number; col?: number; editor?: string | null }
|
|
1020
|
+
| { as: 'finder'; cwd: string }
|
|
1021
|
+
| { as: 'terminal'; cwd: string }
|
|
1022
|
+
| { as: 'external'; url: string }
|
|
1023
|
+
| { as: 'openPath'; path: string }
|
|
1024
|
+
| { as: 'revealPath'; path: string }
|
|
1025
|
+
) => Promise<{ ok: boolean; opener?: string; error?: string }>;
|
|
970
1026
|
};
|
|
971
1027
|
search: {
|
|
972
1028
|
files: (cwd: string, query?: string, opts?: { limit?: number }) => Promise<SearchFilesResult>;
|
|
@@ -983,7 +1039,6 @@ export interface SessionManagerAPI {
|
|
|
983
1039
|
};
|
|
984
1040
|
history: {
|
|
985
1041
|
aggregate: (req?: HistoryAggregateRequest) => Promise<HistoryAggregateResult>;
|
|
986
|
-
listConversations: () => Promise<ListConversationsResult>;
|
|
987
1042
|
scanProjects: () => Promise<SessionScanResult>;
|
|
988
1043
|
};
|
|
989
1044
|
schedule: {
|
|
@@ -993,7 +1048,6 @@ export interface SessionManagerAPI {
|
|
|
993
1048
|
runNow: () => Promise<{ ok: boolean }>;
|
|
994
1049
|
forceTick: () => Promise<{ ok: boolean }>;
|
|
995
1050
|
resume: () => Promise<{ ok: boolean }>;
|
|
996
|
-
refreshReset: () => Promise<{ ok: boolean; nextReset: string | null }>;
|
|
997
1051
|
/** Re-scan prds/ and merge into queue.json; broadcasts updated state. */
|
|
998
1052
|
rescan: () => Promise<{ ok: boolean }>;
|
|
999
1053
|
/** Move all pending+failed PRDs to prds-archived/<ISO>/ and drop their
|
|
@@ -1057,6 +1111,8 @@ export interface SessionManagerAPI {
|
|
|
1057
1111
|
delete: (name: string, workspace?: string) => Promise<MemoryMutationResult>;
|
|
1058
1112
|
/** Create a new memory entry with starter frontmatter + body. */
|
|
1059
1113
|
create: (name: string, description?: string, workspace?: string) => Promise<MemoryMutationResult>;
|
|
1114
|
+
/** Aggregate workspace memories into semantic clusters. `refresh:true` fires a cost-gated `claude -p` pass; otherwise returns the cache only. */
|
|
1115
|
+
aggregate: (workspace: string, refresh?: boolean) => Promise<MemoryAggregateResult>;
|
|
1060
1116
|
};
|
|
1061
1117
|
agentMemory: {
|
|
1062
1118
|
/** List all memory entries for one subagent. Sorted newest first. */
|
|
@@ -1072,8 +1128,6 @@ export interface SessionManagerAPI {
|
|
|
1072
1128
|
) => Promise<AgentMemoryMutationResult>;
|
|
1073
1129
|
/** Delete one entry. Removes the file outright when last entry is removed. */
|
|
1074
1130
|
delete: (agentId: string, entryId: string) => Promise<AgentMemoryMutationResult>;
|
|
1075
|
-
/** List all agents that currently have a memory file on disk. */
|
|
1076
|
-
listAgents: () => Promise<AgentMemoryListAgentsResult>;
|
|
1077
1131
|
};
|
|
1078
1132
|
docEditor: {
|
|
1079
1133
|
pickFile: (payload?: { lastDir?: string }) => Promise<{ path: string | null; error?: string }>;
|
|
@@ -1121,88 +1175,49 @@ export interface SessionManagerAPI {
|
|
|
1121
1175
|
* E2E session as authenticated and unblocks MUTATE-tier commands. */
|
|
1122
1176
|
confirmSas: () => Promise<WebRemoteMutationResult>;
|
|
1123
1177
|
};
|
|
1124
|
-
|
|
1125
|
-
/**
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
/**
|
|
1139
|
-
|
|
1140
|
-
|
|
1178
|
+
chat: {
|
|
1179
|
+
/** Spawn a headless `claude -p` run for a tab. Results arrive via the on* listeners. */
|
|
1180
|
+
run: (payload: ChatRunPayload) => Promise<{ ok: boolean }>;
|
|
1181
|
+
/** Cancel the in-flight run for a tab (SIGTERM→SIGKILL). No-op when idle. */
|
|
1182
|
+
cancel: (tabId: string) => void;
|
|
1183
|
+
onQueued: (handler: (e: ChatRunQueuedEvent) => void) => () => void;
|
|
1184
|
+
onRunStarted: (handler: (e: ChatRunStartedEvent) => void) => () => void;
|
|
1185
|
+
onOutput: (handler: (e: ChatRunOutputEvent) => void) => () => void;
|
|
1186
|
+
onToolUse: (handler: (e: ChatRunToolUseEvent) => void) => () => void;
|
|
1187
|
+
onNeedsInput: (handler: (e: ChatRunNeedsInputEvent) => void) => () => void;
|
|
1188
|
+
onComplete: (handler: (e: ChatRunCompleteEvent) => void) => () => void;
|
|
1189
|
+
onError: (handler: (e: ChatRunErrorEvent) => void) => () => void;
|
|
1190
|
+
};
|
|
1191
|
+
exchanges: {
|
|
1192
|
+
/** Durable per-exchange log entries for a project, newest-first (max 100 by default). */
|
|
1193
|
+
list: (payload: {
|
|
1194
|
+
cwd: string;
|
|
1195
|
+
sessionId?: string;
|
|
1196
|
+
limit?: number;
|
|
1197
|
+
offset?: number;
|
|
1198
|
+
}) => Promise<Exchange[]>;
|
|
1141
1199
|
};
|
|
1142
1200
|
}
|
|
1143
1201
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
/** total - processed. */
|
|
1153
|
-
pending: number;
|
|
1154
|
-
nodes: number;
|
|
1155
|
-
edges: number;
|
|
1156
|
-
lastIngest: string | null;
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
export interface KgNode {
|
|
1160
|
-
id: string;
|
|
1161
|
-
key: string;
|
|
1162
|
-
name: string;
|
|
1163
|
-
type: string;
|
|
1164
|
-
description: string;
|
|
1165
|
-
count: number;
|
|
1166
|
-
firstTs: string | null;
|
|
1167
|
-
lastTs: string | null;
|
|
1168
|
-
}
|
|
1169
|
-
export interface KgEdge {
|
|
1170
|
-
src: string;
|
|
1171
|
-
dst: string;
|
|
1172
|
-
relation: string;
|
|
1173
|
-
weight: number;
|
|
1174
|
-
lastTs: string | null;
|
|
1175
|
-
}
|
|
1176
|
-
export interface KgState {
|
|
1177
|
-
/** The project this graph belongs to. */
|
|
1202
|
+
// ────────────────────────────────────────────── Exchanges (PRD 324 read path)
|
|
1203
|
+
|
|
1204
|
+
export interface Exchange {
|
|
1205
|
+
/** ISO 8601 timestamp when the exchange was recorded. */
|
|
1206
|
+
ts: string;
|
|
1207
|
+
/** Claude session UUID. */
|
|
1208
|
+
sessionId: string;
|
|
1209
|
+
/** Project cwd. */
|
|
1178
1210
|
cwd: string;
|
|
1179
|
-
/**
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
logPath: string;
|
|
1190
|
-
extractionEnabled: boolean;
|
|
1191
|
-
/** Active capture mode: 'llm' | 'lite' | 'off'. */
|
|
1192
|
-
captureMode: 'llm' | 'lite' | 'off';
|
|
1193
|
-
/** Node cap from kg-config.json; 0 = disabled; default 300. */
|
|
1194
|
-
maxGraphNodes: number;
|
|
1195
|
-
};
|
|
1196
|
-
}
|
|
1197
|
-
export interface KgIngestProgress {
|
|
1198
|
-
phase: 'start' | 'extract' | 'batch' | 'done' | 'error';
|
|
1199
|
-
ingesting: boolean;
|
|
1200
|
-
batch?: number;
|
|
1201
|
-
totalBatches?: number;
|
|
1202
|
-
added?: number;
|
|
1203
|
-
/** Set on `batch`: the project cwd whose graph just committed. */
|
|
1204
|
-
cwd?: string;
|
|
1205
|
-
error?: string;
|
|
1211
|
+
/** The user prompt that started the exchange. */
|
|
1212
|
+
prompt: string;
|
|
1213
|
+
/** The verbatim assistant result. */
|
|
1214
|
+
result: string;
|
|
1215
|
+
/** Haiku-generated one-sentence summary. */
|
|
1216
|
+
summary: string;
|
|
1217
|
+
/** Haiku model used for the summary (informational). */
|
|
1218
|
+
model?: string;
|
|
1219
|
+
/** Set when summarization failed — `result` is available but `summary` may be empty. */
|
|
1220
|
+
degraded?: boolean;
|
|
1206
1221
|
}
|
|
1207
1222
|
|
|
1208
1223
|
declare global {
|
package/src/preload/index.cjs
CHANGED
|
@@ -9,11 +9,6 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
9
9
|
pickDirectory: () => ipcRenderer.invoke('app:pick-directory'),
|
|
10
10
|
gitBranch: (cwd) => ipcRenderer.invoke('app:git-branch', { cwd }),
|
|
11
11
|
rebootApp: () => ipcRenderer.send('app:reboot-app'),
|
|
12
|
-
openInEditor: (cwd, editor) => ipcRenderer.invoke('app:open-in-editor', { cwd, editor }),
|
|
13
|
-
openExternal: (url) => ipcRenderer.invoke('app:open-external', { url }),
|
|
14
|
-
openFileInEditor: (filePath, line, col, editor) => ipcRenderer.invoke('app:open-file-in-editor', { path: filePath, line, col, editor }),
|
|
15
|
-
openInFinder: (cwd) => ipcRenderer.invoke('app:open-in-finder', { cwd }),
|
|
16
|
-
openInTerminal: (cwd) => ipcRenderer.invoke('app:open-in-terminal', { cwd }),
|
|
17
12
|
archiveProject: (encoded) => ipcRenderer.invoke('app:archive-project', { encoded }),
|
|
18
13
|
testFireHook: (args) => ipcRenderer.invoke('app:test-fire-hook', args),
|
|
19
14
|
// F7: lets the renderer suppress the wizard auto-trigger under SM_E2E=1.
|
|
@@ -121,7 +116,6 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
121
116
|
},
|
|
122
117
|
getHotkeyConfig: () => ipcRenderer.invoke('voice:get-hotkey-config'),
|
|
123
118
|
setHotkeyConfig: (cfg) => ipcRenderer.invoke('voice:set-hotkey', cfg),
|
|
124
|
-
getHotkeyConfigPath: () => ipcRenderer.invoke('voice:get-hotkey-config-path'),
|
|
125
119
|
setRecording: (recording) => ipcRenderer.send('voice:set-recording', !!recording),
|
|
126
120
|
// F5 device picker prefs (~/.config/session-manager/voice.json `device` key).
|
|
127
121
|
getDevicePref: () => ipcRenderer.invoke('voice:get-device-pref'),
|
|
@@ -158,7 +152,6 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
158
152
|
},
|
|
159
153
|
history: {
|
|
160
154
|
aggregate: (req) => ipcRenderer.invoke('history:aggregate', req),
|
|
161
|
-
listConversations: () => ipcRenderer.invoke('history:list-conversations'),
|
|
162
155
|
scanProjects: () => ipcRenderer.invoke('history:scan-projects'),
|
|
163
156
|
},
|
|
164
157
|
files: {
|
|
@@ -168,8 +161,11 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
168
161
|
create: (parentPath, name, kind) => ipcRenderer.invoke('files:create', { parentPath, name, kind }),
|
|
169
162
|
rename: (path, newName) => ipcRenderer.invoke('files:rename', { path, newName }),
|
|
170
163
|
delete: (path) => ipcRenderer.invoke('files:delete', { path }),
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
},
|
|
165
|
+
// Consolidated shell open/reveal — see shell:open in index.cjs.
|
|
166
|
+
// as: 'editor' | 'fileInEditor' | 'finder' | 'terminal' | 'external' | 'openPath' | 'revealPath'
|
|
167
|
+
shell: {
|
|
168
|
+
open: (opts) => ipcRenderer.invoke('shell:open', opts),
|
|
173
169
|
},
|
|
174
170
|
search: {
|
|
175
171
|
files: (cwd, query, opts) => ipcRenderer.invoke('search:files', { cwd, query, opts }),
|
|
@@ -191,7 +187,6 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
191
187
|
runNow: () => ipcRenderer.invoke('schedule:run-now'),
|
|
192
188
|
forceTick: () => ipcRenderer.invoke('schedule:force-tick'),
|
|
193
189
|
resume: () => ipcRenderer.invoke('schedule:resume'),
|
|
194
|
-
refreshReset: () => ipcRenderer.invoke('schedule:refresh-reset'),
|
|
195
190
|
rescan: () => ipcRenderer.invoke('schedule:rescan'),
|
|
196
191
|
clearQueue: () => ipcRenderer.invoke('schedule:clear-queue'),
|
|
197
192
|
openFolder: () => ipcRenderer.invoke('schedule:open-folder'),
|
|
@@ -244,6 +239,8 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
244
239
|
if (workspace) payload.workspace = workspace;
|
|
245
240
|
return ipcRenderer.invoke('memory:create', payload);
|
|
246
241
|
},
|
|
242
|
+
aggregate: (workspace, refresh) =>
|
|
243
|
+
ipcRenderer.invoke('memory:aggregate', refresh ? { workspace, refresh: true } : { workspace }),
|
|
247
244
|
},
|
|
248
245
|
agentMemory: {
|
|
249
246
|
list: (agentId) => ipcRenderer.invoke('agent-memory:list', { agentId }),
|
|
@@ -254,7 +251,6 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
254
251
|
return ipcRenderer.invoke('agent-memory:set', payload);
|
|
255
252
|
},
|
|
256
253
|
delete: (agentId, entryId) => ipcRenderer.invoke('agent-memory:delete', { agentId, entryId }),
|
|
257
|
-
listAgents: () => ipcRenderer.invoke('agent-memory:list-agents'),
|
|
258
254
|
},
|
|
259
255
|
docEditor: {
|
|
260
256
|
pickFile: (payload) => ipcRenderer.invoke('doc-editor:pick-file', payload),
|
|
@@ -320,25 +316,50 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
320
316
|
return () => ipcRenderer.removeListener('webRemote:revoked-all', listener);
|
|
321
317
|
},
|
|
322
318
|
},
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
319
|
+
chat: {
|
|
320
|
+
/** Spawn a headless claude -p job. Results arrive via the on* listeners. */
|
|
321
|
+
run: (payload) => ipcRenderer.invoke('chat:run', payload),
|
|
322
|
+
/** Cancel an in-flight run for the given tabId. No-op if none running. */
|
|
323
|
+
cancel: (tabId) => ipcRenderer.send('chat:cancel', { tabId }),
|
|
324
|
+
onQueued: (handler) => {
|
|
325
|
+
const listener = (_e, payload) => handler(payload);
|
|
326
|
+
ipcRenderer.on('chat:run:queued', listener);
|
|
327
|
+
return () => ipcRenderer.removeListener('chat:run:queued', listener);
|
|
328
|
+
},
|
|
329
|
+
onRunStarted: (handler) => {
|
|
330
|
+
const listener = (_e, payload) => handler(payload);
|
|
331
|
+
ipcRenderer.on('chat:run:started', listener);
|
|
332
|
+
return () => ipcRenderer.removeListener('chat:run:started', listener);
|
|
333
|
+
},
|
|
334
|
+
onOutput: (handler) => {
|
|
335
|
+
const listener = (_e, payload) => handler(payload);
|
|
336
|
+
ipcRenderer.on('chat:run:output', listener);
|
|
337
|
+
return () => ipcRenderer.removeListener('chat:run:output', listener);
|
|
338
|
+
},
|
|
339
|
+
onToolUse: (handler) => {
|
|
339
340
|
const listener = (_e, payload) => handler(payload);
|
|
340
|
-
ipcRenderer.on('
|
|
341
|
-
return () => ipcRenderer.removeListener('
|
|
341
|
+
ipcRenderer.on('chat:run:tool-use', listener);
|
|
342
|
+
return () => ipcRenderer.removeListener('chat:run:tool-use', listener);
|
|
342
343
|
},
|
|
344
|
+
onNeedsInput: (handler) => {
|
|
345
|
+
const listener = (_e, payload) => handler(payload);
|
|
346
|
+
ipcRenderer.on('chat:run:needs-input', listener);
|
|
347
|
+
return () => ipcRenderer.removeListener('chat:run:needs-input', listener);
|
|
348
|
+
},
|
|
349
|
+
onComplete: (handler) => {
|
|
350
|
+
const listener = (_e, payload) => handler(payload);
|
|
351
|
+
ipcRenderer.on('chat:run:complete', listener);
|
|
352
|
+
return () => ipcRenderer.removeListener('chat:run:complete', listener);
|
|
353
|
+
},
|
|
354
|
+
onError: (handler) => {
|
|
355
|
+
const listener = (_e, payload) => handler(payload);
|
|
356
|
+
ipcRenderer.on('chat:run:error', listener);
|
|
357
|
+
return () => ipcRenderer.removeListener('chat:run:error', listener);
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
exchanges: {
|
|
361
|
+
/** List exchanges for a project (durable chat-run log), newest-first.
|
|
362
|
+
* `sessionId` filters to one session; `limit`/`offset` for pagination. */
|
|
363
|
+
list: (payload) => ipcRenderer.invoke('exchanges:list', payload),
|
|
343
364
|
},
|
|
344
365
|
});
|