claude-code-session-manager 0.10.2 → 0.11.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/dist/assets/TiptapBody-CAJSNRPs.js +189 -0
- package/dist/assets/{cssMode-DyodRfD-.js → cssMode-o7rZCrm4.js} +1 -1
- package/dist/assets/{freemarker2-D1H1ixRK.js → freemarker2-CgmCS5Wh.js} +1 -1
- package/dist/assets/{handlebars-wnlxpTlt.js → handlebars-BcPLqhPv.js} +1 -1
- package/dist/assets/{html-Dv_oA_OQ.js → html-CC9xWnC3.js} +1 -1
- package/dist/assets/{htmlMode-DGXsu2-V.js → htmlMode-DEgCqH7k.js} +1 -1
- package/dist/assets/{index-oiSqLrkZ.js → index-C7ljEoqc.js} +1223 -1192
- package/dist/assets/{index-CcRP2nIC.css → index-CH3K1pkS.css} +1 -1
- package/dist/assets/{javascript-CxejmYhM.js → javascript-CjwqkQrn.js} +1 -1
- package/dist/assets/{jsonMode-ztPfF7kI.js → jsonMode-BYTLu76d.js} +4 -4
- package/dist/assets/{liquid-DvtfrYeo.js → liquid-wbQUuJwT.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-mIBTKOZq.js → lspLanguageFeatures-BJGMI7Xu.js} +1 -1
- package/dist/assets/{mdx-DTebMWEJ.js → mdx-DcDstgPF.js} +1 -1
- package/dist/assets/{python-zea5QgfT.js → python-B96yyM_5.js} +1 -1
- package/dist/assets/{razor-DODk3om_.js → razor-C7aRIxIE.js} +1 -1
- package/dist/assets/{tsMode-BQGo_Gc8.js → tsMode-B3UYlGaL.js} +1 -1
- package/dist/assets/{typescript-Cfo1NBg6.js → typescript-CV587TvC.js} +1 -1
- package/dist/assets/{xml-D1RKIHcE.js → xml-PWUJecBf.js} +1 -1
- package/dist/assets/{yaml-B8MoJlND.js → yaml-D8bBNHE4.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +5 -1
- package/src/main/agentMemory.cjs +267 -0
- package/src/main/docEditor.cjs +92 -0
- package/src/main/files.cjs +346 -0
- package/src/main/git.cjs +333 -0
- package/src/main/historyAggregator.cjs +70 -0
- package/src/main/index.cjs +66 -0
- package/src/main/ipcSchemas.cjs +75 -0
- package/src/main/projectSkills.cjs +124 -0
- package/src/main/scheduler.cjs +155 -11
- package/src/main/superagent.cjs +202 -0
- package/src/main/transcripts.cjs +8 -1
- package/src/preload/api.d.ts +215 -0
- package/src/preload/index.cjs +54 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SuperAgent — "boss" runner that dispatches specialist subagents.
|
|
3
|
+
*
|
|
4
|
+
* Ported (in MVP form) from ClaudeCodeUnleashed's SuperAgent feature.
|
|
5
|
+
* Differs significantly from upstream:
|
|
6
|
+
* - We don't call Groq/OpenAI. The boss IS Claude — we send a structured
|
|
7
|
+
* prompt to the active PTY tab asking Claude to act as the boss, pick
|
|
8
|
+
* specialists, and report progress in a parseable format.
|
|
9
|
+
* - No autonomous output-parsing / fast-path / WAIT logic. State machine
|
|
10
|
+
* is renderer-driven via transcript events (see live.ts pattern).
|
|
11
|
+
* - Per-tab run state lives here so the renderer can poll status across
|
|
12
|
+
* navigation, and so a future supervisor probe can act on stuck runs.
|
|
13
|
+
*
|
|
14
|
+
* Channels:
|
|
15
|
+
* superagent:start({ tabId, prompt, specialistCount, depth })
|
|
16
|
+
* → { ok, error? } and broadcasts the boss prompt to the tab's PTY.
|
|
17
|
+
* superagent:status(tabId) → SuperAgentRunState | null
|
|
18
|
+
* superagent:stop(tabId) → { ok }
|
|
19
|
+
*
|
|
20
|
+
* Broadcasts:
|
|
21
|
+
* superagent:state-changed → { tabId, state } whenever a run starts/stops.
|
|
22
|
+
*
|
|
23
|
+
* The PTY write is intentionally done via the existing ptyManager.write
|
|
24
|
+
* indirection, NOT a fresh spawn — SuperAgent runs inside the user's current
|
|
25
|
+
* Claude session.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const { ipcMain } = require('electron');
|
|
29
|
+
const { schemas } = require('./ipcSchemas.cjs');
|
|
30
|
+
const { manager: ptyManager } = require('./pty.cjs');
|
|
31
|
+
const logs = require('./logs.cjs');
|
|
32
|
+
|
|
33
|
+
// Per-tab run state. Single live run per tab — starting a new run on a tab
|
|
34
|
+
// that's already running stops the existing one first.
|
|
35
|
+
//
|
|
36
|
+
// Shape (also exposed on the renderer via api.d.ts SuperAgentRunState):
|
|
37
|
+
// { status: 'idle' | 'running' | 'done' | 'error',
|
|
38
|
+
// prompt, specialistCount, depth,
|
|
39
|
+
// startedAt: number | null, finishedAt: number | null,
|
|
40
|
+
// error?: string }
|
|
41
|
+
const runs = new Map();
|
|
42
|
+
|
|
43
|
+
let mainWindow = null;
|
|
44
|
+
|
|
45
|
+
function attachWindow(win) {
|
|
46
|
+
mainWindow = win;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function broadcast(tabId) {
|
|
50
|
+
if (!mainWindow || mainWindow.isDestroyed()) return;
|
|
51
|
+
const state = runs.get(tabId) ?? null;
|
|
52
|
+
try {
|
|
53
|
+
mainWindow.webContents.send('superagent:state-changed', { tabId, state });
|
|
54
|
+
} catch { /* renderer gone */ }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build the prompt we send to Claude to act as the boss. Structured so the
|
|
59
|
+
* renderer can (in a follow-up) pattern-match progress markers off the
|
|
60
|
+
* transcript without us having to parse PTY output ourselves.
|
|
61
|
+
*
|
|
62
|
+
* O(1) string concat — the prompt is bounded by the zod max(8KiB).
|
|
63
|
+
*/
|
|
64
|
+
function buildBossPrompt({ prompt, specialistCount, depth }) {
|
|
65
|
+
const depthLine = depth === 'quick'
|
|
66
|
+
? 'Quick pass — surface-level analysis, single-shot specialist work.'
|
|
67
|
+
: depth === 'deep'
|
|
68
|
+
? 'Deep pass — multi-step plans per specialist, recurse on findings.'
|
|
69
|
+
: 'Standard pass — moderate detail, one or two iterations per specialist.';
|
|
70
|
+
|
|
71
|
+
return [
|
|
72
|
+
'## SuperAgent boss mode',
|
|
73
|
+
'',
|
|
74
|
+
`You are coordinating ${specialistCount} specialist subagent(s) for the user's task.`,
|
|
75
|
+
depthLine,
|
|
76
|
+
'',
|
|
77
|
+
'Workflow:',
|
|
78
|
+
` 1. Pick ${specialistCount} specialist subagent type(s) that best match the task.`,
|
|
79
|
+
' Report them as: [SUPERAGENT] specialists: <type1>, <type2>, ...',
|
|
80
|
+
' 2. Dispatch them via the Task tool, one at a time or in parallel as appropriate.',
|
|
81
|
+
' 3. After each specialist returns, report: [SUPERAGENT] progress: <specialist> done',
|
|
82
|
+
' 4. When the task is complete, summarize results and report: [SUPERAGENT] complete',
|
|
83
|
+
'',
|
|
84
|
+
'User task:',
|
|
85
|
+
prompt,
|
|
86
|
+
].join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function startRun(payload) {
|
|
90
|
+
const { tabId, prompt, specialistCount, depth } = payload;
|
|
91
|
+
|
|
92
|
+
// Stop any in-flight run on this tab — single run-per-tab invariant.
|
|
93
|
+
const existing = runs.get(tabId);
|
|
94
|
+
if (existing && existing.status === 'running') {
|
|
95
|
+
runs.set(tabId, {
|
|
96
|
+
...existing,
|
|
97
|
+
status: 'done',
|
|
98
|
+
finishedAt: Date.now(),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const fullPrompt = buildBossPrompt({ prompt, specialistCount, depth });
|
|
103
|
+
|
|
104
|
+
// PTY write — exactly the pattern docstring'd at the top of the task brief.
|
|
105
|
+
// The trailing carriage-return submits the prompt in Claude's TUI.
|
|
106
|
+
let writeErr = null;
|
|
107
|
+
try {
|
|
108
|
+
ptyManager.write({ tabId, data: fullPrompt + '\r' });
|
|
109
|
+
} catch (e) {
|
|
110
|
+
writeErr = e?.message ?? String(e);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (writeErr) {
|
|
114
|
+
const errState = {
|
|
115
|
+
status: 'error',
|
|
116
|
+
prompt,
|
|
117
|
+
specialistCount,
|
|
118
|
+
depth,
|
|
119
|
+
startedAt: Date.now(),
|
|
120
|
+
finishedAt: Date.now(),
|
|
121
|
+
error: writeErr,
|
|
122
|
+
};
|
|
123
|
+
runs.set(tabId, errState);
|
|
124
|
+
broadcast(tabId);
|
|
125
|
+
logs.writeLine({
|
|
126
|
+
scope: 'superagent',
|
|
127
|
+
level: 'error',
|
|
128
|
+
message: 'start failed',
|
|
129
|
+
meta: { tabId, error: writeErr },
|
|
130
|
+
});
|
|
131
|
+
return { ok: false, error: writeErr };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const state = {
|
|
135
|
+
status: 'running',
|
|
136
|
+
prompt,
|
|
137
|
+
specialistCount,
|
|
138
|
+
depth,
|
|
139
|
+
startedAt: Date.now(),
|
|
140
|
+
finishedAt: null,
|
|
141
|
+
};
|
|
142
|
+
runs.set(tabId, state);
|
|
143
|
+
broadcast(tabId);
|
|
144
|
+
|
|
145
|
+
logs.writeLine({
|
|
146
|
+
scope: 'superagent',
|
|
147
|
+
level: 'info',
|
|
148
|
+
message: 'start',
|
|
149
|
+
meta: { tabId, specialistCount, depth, promptBytes: prompt.length },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return { ok: true };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function stopRun(tabId) {
|
|
156
|
+
const existing = runs.get(tabId);
|
|
157
|
+
if (!existing || existing.status !== 'running') {
|
|
158
|
+
return { ok: true };
|
|
159
|
+
}
|
|
160
|
+
runs.set(tabId, {
|
|
161
|
+
...existing,
|
|
162
|
+
status: 'done',
|
|
163
|
+
finishedAt: Date.now(),
|
|
164
|
+
});
|
|
165
|
+
broadcast(tabId);
|
|
166
|
+
logs.writeLine({
|
|
167
|
+
scope: 'superagent',
|
|
168
|
+
level: 'info',
|
|
169
|
+
message: 'stop',
|
|
170
|
+
meta: { tabId },
|
|
171
|
+
});
|
|
172
|
+
return { ok: true };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getStatus(tabId) {
|
|
176
|
+
return runs.get(tabId) ?? null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function registerSuperAgentHandlers() {
|
|
180
|
+
ipcMain.handle('superagent:start', (_e, payload) => {
|
|
181
|
+
const parsed = schemas.superagentStart.parse(payload);
|
|
182
|
+
return startRun(parsed);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
ipcMain.handle('superagent:status', (_e, payload) => {
|
|
186
|
+
const { tabId } = schemas.superagentTabId.parse(payload);
|
|
187
|
+
return getStatus(tabId);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
ipcMain.handle('superagent:stop', (_e, payload) => {
|
|
191
|
+
const { tabId } = schemas.superagentTabId.parse(payload);
|
|
192
|
+
return stopRun(tabId);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
module.exports = {
|
|
197
|
+
attachWindow,
|
|
198
|
+
registerSuperAgentHandlers,
|
|
199
|
+
// Exposed for tests.
|
|
200
|
+
buildBossPrompt,
|
|
201
|
+
_runs: runs,
|
|
202
|
+
};
|
package/src/main/transcripts.cjs
CHANGED
|
@@ -69,7 +69,9 @@ function classifyLine(obj) {
|
|
|
69
69
|
return { kind: 'plan', data: block.input, raw: obj };
|
|
70
70
|
}
|
|
71
71
|
if (block.name === 'Agent' || block.name === 'Task') {
|
|
72
|
-
|
|
72
|
+
// Include block.id as toolUseId so the live store can match the
|
|
73
|
+
// corresponding tool_result and update per-agent lastActivityAt.
|
|
74
|
+
return { kind: 'agent_spawn', data: { ...block.input, toolUseId: block.id }, raw: obj };
|
|
73
75
|
}
|
|
74
76
|
return {
|
|
75
77
|
kind: 'tool_use',
|
|
@@ -77,6 +79,11 @@ function classifyLine(obj) {
|
|
|
77
79
|
raw: obj,
|
|
78
80
|
};
|
|
79
81
|
}
|
|
82
|
+
// tool_result carries the tool_use_id of the completed Task/Agent call.
|
|
83
|
+
// The live store uses this to update the agent's lastActivityAt bookend.
|
|
84
|
+
if (block?.type === 'tool_result' && block.tool_use_id) {
|
|
85
|
+
return { kind: 'tool_result', data: { toolUseId: block.tool_use_id }, raw: obj };
|
|
86
|
+
}
|
|
80
87
|
}
|
|
81
88
|
}
|
|
82
89
|
|
package/src/preload/api.d.ts
CHANGED
|
@@ -377,6 +377,46 @@ export interface HistoryAggregateResult {
|
|
|
377
377
|
scannedMs: number;
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
export interface ConversationSummary {
|
|
381
|
+
/** ISO 8601 timestamp of the first event in the conversation (or file mtime fallback). */
|
|
382
|
+
timestamp: string;
|
|
383
|
+
/** Decoded project cwd, e.g. /home/user/Projects/foo. */
|
|
384
|
+
projectFolder: string;
|
|
385
|
+
stats: {
|
|
386
|
+
/** Wall-clock duration in ms (first event ts → last event ts). Omitted when unknown. */
|
|
387
|
+
duration?: number;
|
|
388
|
+
/** Sum of input + output tokens across the file. 0 when no usage blocks present. */
|
|
389
|
+
estimatedTokens: number;
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface ListConversationsResult {
|
|
394
|
+
conversations: ConversationSummary[];
|
|
395
|
+
scannedMs: number;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export interface ProjectSkillState {
|
|
399
|
+
skillId: string;
|
|
400
|
+
enabled: boolean;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export interface FileEntry {
|
|
404
|
+
name: string;
|
|
405
|
+
path: string;
|
|
406
|
+
isDirectory: boolean;
|
|
407
|
+
isFile: boolean;
|
|
408
|
+
size: number;
|
|
409
|
+
mtimeMs: number;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export interface FilesListResult { ok: boolean; entries: FileEntry[]; error: string | null }
|
|
413
|
+
export interface FilesReadResult { ok: boolean; text: string; error: string | null; size: number }
|
|
414
|
+
export interface FilesWriteResult { ok: boolean; error: string | null }
|
|
415
|
+
export interface FilesCreateResult { ok: boolean; path?: string; error: string | null }
|
|
416
|
+
export interface FilesRenameResult { ok: boolean; newPath?: string; error: string | null }
|
|
417
|
+
export interface FilesDeleteResult { ok: boolean; error: string | null }
|
|
418
|
+
export interface FilesShellResult { ok: boolean; error?: string }
|
|
419
|
+
|
|
380
420
|
export interface WatcherInfo {
|
|
381
421
|
watcherId: string;
|
|
382
422
|
tabId: string;
|
|
@@ -506,6 +546,83 @@ export interface MemoryMutationResult {
|
|
|
506
546
|
error: string | null;
|
|
507
547
|
}
|
|
508
548
|
|
|
549
|
+
// ────────────────────────────────────────────── Per-subagent memory
|
|
550
|
+
// Stored at ~/.claude/session-manager/agent-memory/<agentId>.json. Keyed by
|
|
551
|
+
// agent name (the .md filename in ~/.claude/agents/), not by workspace cwd.
|
|
552
|
+
|
|
553
|
+
export type AgentMemoryCategory = 'command' | 'preference' | 'pattern' | 'failure' | 'workflow';
|
|
554
|
+
|
|
555
|
+
export interface AgentMemoryEntry {
|
|
556
|
+
id: string;
|
|
557
|
+
body: string;
|
|
558
|
+
category: AgentMemoryCategory | null;
|
|
559
|
+
createdAt: number;
|
|
560
|
+
updatedAt: number;
|
|
561
|
+
bytes: number;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export interface AgentMemoryListResult {
|
|
565
|
+
entries: AgentMemoryEntry[];
|
|
566
|
+
agentId: string;
|
|
567
|
+
error: string | null;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export interface AgentMemoryGetResult {
|
|
571
|
+
entry: AgentMemoryEntry | null;
|
|
572
|
+
error: string | null;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export interface AgentMemoryMutationResult {
|
|
576
|
+
ok: boolean;
|
|
577
|
+
error: string | null;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
export interface AgentMemoryAgentSummary {
|
|
581
|
+
agentId: string;
|
|
582
|
+
bytes: number;
|
|
583
|
+
mtimeMs: number;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
export interface AgentMemoryListAgentsResult {
|
|
587
|
+
agents: AgentMemoryAgentSummary[];
|
|
588
|
+
error: string | null;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// ────────────────────────────────────────────── Git status (richer than app:git-branch)
|
|
592
|
+
|
|
593
|
+
/** Mirrors the status returned by src/main/git.cjs mapStatus(). */
|
|
594
|
+
export type GitFileStatusType =
|
|
595
|
+
| 'modified'
|
|
596
|
+
| 'added'
|
|
597
|
+
| 'deleted'
|
|
598
|
+
| 'renamed'
|
|
599
|
+
| 'untracked'
|
|
600
|
+
| 'staged'
|
|
601
|
+
| 'conflict';
|
|
602
|
+
|
|
603
|
+
export interface GitFileStatus {
|
|
604
|
+
/** Absolute path. Always inside cwd (we resolve relative paths against it). */
|
|
605
|
+
path: string;
|
|
606
|
+
/** Path as git reported it, relative to the repo root. */
|
|
607
|
+
relativePath: string;
|
|
608
|
+
status: GitFileStatusType;
|
|
609
|
+
/** Raw porcelain X (index) character. ' ', 'M', 'A', 'D', 'R', 'C', 'U', '?'. */
|
|
610
|
+
indexStatus: string;
|
|
611
|
+
/** Raw porcelain Y (worktree) character. ' ', 'M', 'D', 'U', '?'. */
|
|
612
|
+
workTreeStatus: string;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
export interface GitStatusResult {
|
|
616
|
+
branch: string;
|
|
617
|
+
ahead: number;
|
|
618
|
+
behind: number;
|
|
619
|
+
uncommittedCount: number;
|
|
620
|
+
files: GitFileStatus[];
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/** Map keyed by absolute path. Same enum as GitFileStatus.status. */
|
|
624
|
+
export type GitFileStatusMap = Record<string, GitFileStatusType>;
|
|
625
|
+
|
|
509
626
|
// ────────────────────────────────────────────── Bundle F — plugins install
|
|
510
627
|
|
|
511
628
|
export interface PluginInstallResult {
|
|
@@ -519,6 +636,40 @@ export interface PluginInstallProgressEvent {
|
|
|
519
636
|
line: string;
|
|
520
637
|
}
|
|
521
638
|
|
|
639
|
+
// ────────────────────────────────────────────── SuperAgent
|
|
640
|
+
// "Boss" run that dispatches specialist subagents on the active tab's claude
|
|
641
|
+
// session. Renderer-driven progress — main only owns lifecycle + prompt write.
|
|
642
|
+
|
|
643
|
+
export type SuperAgentDepth = 'quick' | 'standard' | 'deep';
|
|
644
|
+
export type SuperAgentStatus = 'idle' | 'running' | 'done' | 'error';
|
|
645
|
+
|
|
646
|
+
export interface SuperAgentRunState {
|
|
647
|
+
status: SuperAgentStatus;
|
|
648
|
+
prompt: string;
|
|
649
|
+
specialistCount: number;
|
|
650
|
+
depth: SuperAgentDepth;
|
|
651
|
+
startedAt: number | null;
|
|
652
|
+
finishedAt: number | null;
|
|
653
|
+
error?: string;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
export interface SuperAgentStartArgs {
|
|
657
|
+
tabId: string;
|
|
658
|
+
prompt: string;
|
|
659
|
+
specialistCount: number;
|
|
660
|
+
depth: SuperAgentDepth;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export interface SuperAgentStartResult {
|
|
664
|
+
ok: boolean;
|
|
665
|
+
error?: string;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
export interface SuperAgentStateChangedEvent {
|
|
669
|
+
tabId: string;
|
|
670
|
+
state: SuperAgentRunState | null;
|
|
671
|
+
}
|
|
672
|
+
|
|
522
673
|
export interface SessionManagerAPI {
|
|
523
674
|
app: {
|
|
524
675
|
version: () => Promise<string>;
|
|
@@ -540,6 +691,13 @@ export interface SessionManagerAPI {
|
|
|
540
691
|
onNewSession: (handler: () => void) => () => void;
|
|
541
692
|
onRebootSession: (handler: () => void) => () => void;
|
|
542
693
|
openInEditor: (cwd: string, editor?: string | null) => Promise<{ ok: boolean; editor?: string; error?: string }>;
|
|
694
|
+
/** Open an http/https URL in the OS default browser. file://, javascript:,
|
|
695
|
+
* and other schemes are rejected with `ok:false` to prevent abuse. */
|
|
696
|
+
openExternal: (url: string) => Promise<{ ok: boolean; error?: string }>;
|
|
697
|
+
/** Open a specific file at line:col in the user's editor. Editors with
|
|
698
|
+
* goto-line support (code/cursor/subl) get the `-g file:line:col` form;
|
|
699
|
+
* others open the file alone. */
|
|
700
|
+
openFileInEditor: (filePath: string, line?: number, col?: number, editor?: string | null) => Promise<{ ok: boolean; editor?: string; error?: string }>;
|
|
543
701
|
openInFinder: (cwd: string) => Promise<{ ok: boolean; error?: string }>;
|
|
544
702
|
openInTerminal: (cwd: string) => Promise<{ ok: boolean; terminal?: string; error?: string }>;
|
|
545
703
|
archiveProject: (encoded: string) => Promise<{ ok: boolean; error?: string }>;
|
|
@@ -616,8 +774,23 @@ export interface SessionManagerAPI {
|
|
|
616
774
|
status: () => Promise<OtelStatus>;
|
|
617
775
|
configPath: () => Promise<string>;
|
|
618
776
|
};
|
|
777
|
+
projectSkills: {
|
|
778
|
+
get: (cwd: string) => Promise<ProjectSkillState[]>;
|
|
779
|
+
set: (cwd: string, skillId: string, enabled: boolean) => Promise<{ ok: boolean }>;
|
|
780
|
+
};
|
|
781
|
+
files: {
|
|
782
|
+
list: (path: string, showHidden?: boolean) => Promise<FilesListResult>;
|
|
783
|
+
read: (path: string) => Promise<FilesReadResult>;
|
|
784
|
+
write: (path: string, content: string) => Promise<FilesWriteResult>;
|
|
785
|
+
create: (parentPath: string, name: string, kind: 'file' | 'folder') => Promise<FilesCreateResult>;
|
|
786
|
+
rename: (path: string, newName: string) => Promise<FilesRenameResult>;
|
|
787
|
+
delete: (path: string) => Promise<FilesDeleteResult>;
|
|
788
|
+
openExternal: (path: string) => Promise<FilesShellResult>;
|
|
789
|
+
showInFinder: (path: string) => Promise<FilesShellResult>;
|
|
790
|
+
};
|
|
619
791
|
history: {
|
|
620
792
|
aggregate: (req?: HistoryAggregateRequest) => Promise<HistoryAggregateResult>;
|
|
793
|
+
listConversations: () => Promise<ListConversationsResult>;
|
|
621
794
|
};
|
|
622
795
|
schedule: {
|
|
623
796
|
state: () => Promise<ScheduleStateSnapshot>;
|
|
@@ -683,6 +856,48 @@ export interface SessionManagerAPI {
|
|
|
683
856
|
/** Create a new memory entry with starter frontmatter + body. */
|
|
684
857
|
create: (name: string, description?: string, workspace?: string) => Promise<MemoryMutationResult>;
|
|
685
858
|
};
|
|
859
|
+
agentMemory: {
|
|
860
|
+
/** List all memory entries for one subagent. Sorted newest first. */
|
|
861
|
+
list: (agentId: string) => Promise<AgentMemoryListResult>;
|
|
862
|
+
/** Get one entry's full body. Returns `{entry:null}` if missing. */
|
|
863
|
+
get: (agentId: string, entryId: string) => Promise<AgentMemoryGetResult>;
|
|
864
|
+
/** Upsert one entry. Atomic write through config.cjs; max body 1 MiB. */
|
|
865
|
+
set: (
|
|
866
|
+
agentId: string,
|
|
867
|
+
entryId: string,
|
|
868
|
+
body: string,
|
|
869
|
+
category?: AgentMemoryCategory,
|
|
870
|
+
) => Promise<AgentMemoryMutationResult>;
|
|
871
|
+
/** Delete one entry. Removes the file outright when last entry is removed. */
|
|
872
|
+
delete: (agentId: string, entryId: string) => Promise<AgentMemoryMutationResult>;
|
|
873
|
+
/** List all agents that currently have a memory file on disk. */
|
|
874
|
+
listAgents: () => Promise<AgentMemoryListAgentsResult>;
|
|
875
|
+
};
|
|
876
|
+
docEditor: {
|
|
877
|
+
pickFile: (payload?: { lastDir?: string }) => Promise<{ path: string | null; error?: string }>;
|
|
878
|
+
readFile: (path: string) => Promise<{ ok: boolean; text?: string; mtimeMs?: number; error?: string }>;
|
|
879
|
+
writeFile: (path: string, text: string) => Promise<{ ok: boolean; mtimeMs?: number; error?: string }>;
|
|
880
|
+
};
|
|
881
|
+
git: {
|
|
882
|
+
/** Full git status for `cwd`. Returns null when not a git repo, git is
|
|
883
|
+
* missing, or the call times out (5s ceiling). Cached per-cwd for 5s. */
|
|
884
|
+
status: (cwd: string) => Promise<GitStatusResult | null>;
|
|
885
|
+
/** `{ absPath: status }` map. Returns `{}` for non-git / errored cwds.
|
|
886
|
+
* Same 5s cache as status(). Designed for a file-tree sidebar where the
|
|
887
|
+
* renderer needs per-row badges without a separate git call per file. */
|
|
888
|
+
fileStatus: (cwd: string) => Promise<GitFileStatusMap>;
|
|
889
|
+
};
|
|
890
|
+
superagent: {
|
|
891
|
+
/** Start a SuperAgent boss run — writes a structured prompt to the tab's
|
|
892
|
+
* PTY asking Claude to pick + dispatch specialists. Single run per tab. */
|
|
893
|
+
start: (args: SuperAgentStartArgs) => Promise<SuperAgentStartResult>;
|
|
894
|
+
/** Current run state for tab, or null if no run has been started. */
|
|
895
|
+
status: (tabId: string) => Promise<SuperAgentRunState | null>;
|
|
896
|
+
/** Mark the run as done. Does not interrupt Claude — the user can stop
|
|
897
|
+
* the in-PTY work via Ctrl-C; this only flips the renderer indicator. */
|
|
898
|
+
stop: (tabId: string) => Promise<{ ok: boolean }>;
|
|
899
|
+
onStateChanged: (handler: (ev: SuperAgentStateChangedEvent) => void) => () => void;
|
|
900
|
+
};
|
|
686
901
|
}
|
|
687
902
|
|
|
688
903
|
declare global {
|
package/src/preload/index.cjs
CHANGED
|
@@ -10,6 +10,8 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
10
10
|
gitBranch: (cwd) => ipcRenderer.invoke('app:git-branch', { cwd }),
|
|
11
11
|
rebootApp: () => ipcRenderer.send('app:reboot-app'),
|
|
12
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 }),
|
|
13
15
|
openInFinder: (cwd) => ipcRenderer.invoke('app:open-in-finder', { cwd }),
|
|
14
16
|
openInTerminal: (cwd) => ipcRenderer.invoke('app:open-in-terminal', { cwd }),
|
|
15
17
|
archiveProject: (encoded) => ipcRenderer.invoke('app:archive-project', { encoded }),
|
|
@@ -144,6 +146,22 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
144
146
|
},
|
|
145
147
|
history: {
|
|
146
148
|
aggregate: (req) => ipcRenderer.invoke('history:aggregate', req),
|
|
149
|
+
listConversations: () => ipcRenderer.invoke('history:list-conversations'),
|
|
150
|
+
},
|
|
151
|
+
projectSkills: {
|
|
152
|
+
get: (cwd) => ipcRenderer.invoke('project-skills:get', { cwd }),
|
|
153
|
+
set: (cwd, skillId, enabled) =>
|
|
154
|
+
ipcRenderer.invoke('project-skills:set', { cwd, skillId, enabled }),
|
|
155
|
+
},
|
|
156
|
+
files: {
|
|
157
|
+
list: (path, showHidden) => ipcRenderer.invoke('files:list', { path, showHidden }),
|
|
158
|
+
read: (path) => ipcRenderer.invoke('files:read', { path }),
|
|
159
|
+
write: (path, content) => ipcRenderer.invoke('files:write', { path, content }),
|
|
160
|
+
create: (parentPath, name, kind) => ipcRenderer.invoke('files:create', { parentPath, name, kind }),
|
|
161
|
+
rename: (path, newName) => ipcRenderer.invoke('files:rename', { path, newName }),
|
|
162
|
+
delete: (path) => ipcRenderer.invoke('files:delete', { path }),
|
|
163
|
+
openExternal: (path) => ipcRenderer.invoke('files:open-external', { path }),
|
|
164
|
+
showInFinder: (path) => ipcRenderer.invoke('files:show-in-finder', { path }),
|
|
147
165
|
},
|
|
148
166
|
schedule: {
|
|
149
167
|
state: () => ipcRenderer.invoke('schedule:state'),
|
|
@@ -203,4 +221,40 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
203
221
|
return ipcRenderer.invoke('memory:create', payload);
|
|
204
222
|
},
|
|
205
223
|
},
|
|
224
|
+
agentMemory: {
|
|
225
|
+
list: (agentId) => ipcRenderer.invoke('agent-memory:list', { agentId }),
|
|
226
|
+
get: (agentId, entryId) => ipcRenderer.invoke('agent-memory:get', { agentId, entryId }),
|
|
227
|
+
set: (agentId, entryId, body, category) => {
|
|
228
|
+
const payload = { agentId, entryId, body };
|
|
229
|
+
if (category) payload.category = category;
|
|
230
|
+
return ipcRenderer.invoke('agent-memory:set', payload);
|
|
231
|
+
},
|
|
232
|
+
delete: (agentId, entryId) => ipcRenderer.invoke('agent-memory:delete', { agentId, entryId }),
|
|
233
|
+
listAgents: () => ipcRenderer.invoke('agent-memory:list-agents'),
|
|
234
|
+
},
|
|
235
|
+
docEditor: {
|
|
236
|
+
pickFile: (payload) => ipcRenderer.invoke('doc-editor:pick-file', payload),
|
|
237
|
+
readFile: (p) => ipcRenderer.invoke('doc-editor:read-file', { path: p }),
|
|
238
|
+
writeFile: (p, text) => ipcRenderer.invoke('doc-editor:write-file', { path: p, text }),
|
|
239
|
+
},
|
|
240
|
+
git: {
|
|
241
|
+
// Returns null when cwd is not a git repo, git is missing, or the call
|
|
242
|
+
// times out (5s ceiling). The existing `app.gitBranch` is intentionally
|
|
243
|
+
// kept — StatusBar still uses it for the cheap per-tab branch readout.
|
|
244
|
+
status: (cwd) => ipcRenderer.invoke('git:status', { cwd }),
|
|
245
|
+
fileStatus: (cwd) => ipcRenderer.invoke('git:file-status', { cwd }),
|
|
246
|
+
},
|
|
247
|
+
superagent: {
|
|
248
|
+
/** Start a SuperAgent boss run on a tab — writes a structured prompt to
|
|
249
|
+
* the PTY asking Claude to pick + dispatch specialists. Single live run
|
|
250
|
+
* per tab; starting again on a running tab terminates the prior one. */
|
|
251
|
+
start: (payload) => ipcRenderer.invoke('superagent:start', payload),
|
|
252
|
+
status: (tabId) => ipcRenderer.invoke('superagent:status', { tabId }),
|
|
253
|
+
stop: (tabId) => ipcRenderer.invoke('superagent:stop', { tabId }),
|
|
254
|
+
onStateChanged: (handler) => {
|
|
255
|
+
const listener = (_e, payload) => handler(payload);
|
|
256
|
+
ipcRenderer.on('superagent:state-changed', listener);
|
|
257
|
+
return () => ipcRenderer.removeListener('superagent:state-changed', listener);
|
|
258
|
+
},
|
|
259
|
+
},
|
|
206
260
|
});
|