@cmodjs/core 1.6.0 → 2.0.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/docs/commands.md +7 -7
- package/docs/dependencies.md +1 -1
- package/docs/index.md +12 -11
- package/docs/jobs.md +12 -16
- package/docs/mod.md +111 -36
- package/docs/permissions.md +14 -18
- package/docs/session.md +171 -82
- package/docs/state.md +5 -5
- package/docs/testing.md +57 -41
- package/docs/ui.md +9 -9
- package/jobs/permissions/decide-permission.d.ts.map +1 -1
- package/jobs/permissions/decide-permission.js +1 -1
- package/jobs/prompt.d.ts +1 -3
- package/jobs/prompt.d.ts.map +1 -1
- package/jobs/prompt.js +2 -21
- package/jobs/slash-command.d.ts +1 -1
- package/jobs/slash-command.d.ts.map +1 -1
- package/jobs/slash-command.js +1 -1
- package/jobs/status-line.d.ts +0 -1
- package/jobs/status-line.d.ts.map +1 -1
- package/jobs/status-line.js +3 -4
- package/mod.d.ts +53 -105
- package/mod.d.ts.map +1 -1
- package/mod.js +18 -80
- package/package.json +1 -1
- package/records.d.ts +1 -1
- package/records.js +1 -1
- package/register.d.ts.map +1 -1
- package/register.js +8 -5
- package/runtime/before.d.ts +11 -4
- package/runtime/before.d.ts.map +1 -1
- package/runtime/before.js +131 -67
- package/runtime/claude.d.ts +6 -1
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/conversations.d.ts.map +1 -1
- package/runtime/conversations.js +82 -38
- package/runtime/deadline.d.ts +17 -0
- package/runtime/deadline.d.ts.map +1 -1
- package/runtime/deadline.js +34 -0
- package/runtime/dependencies.d.ts +2 -0
- package/runtime/dependencies.d.ts.map +1 -1
- package/runtime/dependencies.js +12 -0
- package/runtime/grants.d.ts.map +1 -1
- package/runtime/grants.js +13 -8
- package/runtime/hooks.d.ts +15 -11
- package/runtime/hooks.d.ts.map +1 -1
- package/runtime/hooks.js +8 -165
- package/runtime/lifecycle.d.ts +4 -2
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +96 -62
- package/runtime/permission-check.d.ts +15 -0
- package/runtime/permission-check.d.ts.map +1 -0
- package/runtime/permission-check.js +37 -0
- package/runtime/sessions.d.ts +35 -5
- package/runtime/sessions.d.ts.map +1 -1
- package/runtime/sessions.js +304 -82
- package/runtime/state.d.ts.map +1 -1
- package/runtime/state.js +14 -11
- package/runtime/tool-calls.d.ts +0 -1
- package/runtime/tool-calls.d.ts.map +1 -1
- package/runtime/tool-calls.js +0 -19
- package/session/context/turn/message/instruction-file.d.ts +9 -0
- package/session/context/turn/message/instruction-file.d.ts.map +1 -0
- package/session/context/turn/message/instruction-file.js +4 -0
- package/session/context/turn/message/message.d.ts +6 -4
- package/session/context/turn/message/message.d.ts.map +1 -1
- package/session/context/turn/message/message.js +12 -8
- package/session/context/turn/message/sender.d.ts +2 -1
- package/session/context/turn/message/sender.d.ts.map +1 -1
- package/session/context/turn/message/sender.js +4 -1
- package/session/context/turn/message/tool-call.d.ts +5 -0
- package/session/context/turn/message/tool-call.d.ts.map +1 -1
- package/session/context/turn/message/tool-result.d.ts +6 -1
- package/session/context/turn/message/tool-result.d.ts.map +1 -1
- package/session/context/turn/turn.d.ts +7 -0
- package/session/context/turn/turn.d.ts.map +1 -1
- package/session/conversation.d.ts +10 -3
- package/session/conversation.d.ts.map +1 -1
- package/session/conversation.js +14 -5
- package/session/goal/goal.d.ts +1 -1
- package/session/goal/goal.d.ts.map +1 -1
- package/session/goal/task.d.ts +2 -2
- package/session/goal/task.d.ts.map +1 -1
- package/session/session.d.ts +361 -26
- package/session/session.d.ts.map +1 -1
- package/session/session.js +40 -0
- package/src/jobs/permissions/decide-permission.ts +2 -1
- package/src/jobs/prompt.ts +3 -20
- package/src/jobs/slash-command.ts +2 -2
- package/src/jobs/status-line.ts +4 -7
- package/src/mod.ts +52 -147
- package/src/records.ts +1 -1
- package/src/register.ts +8 -5
- package/src/runtime/before.ts +140 -66
- package/src/runtime/claude.ts +5 -1
- package/src/runtime/conversations.ts +75 -37
- package/src/runtime/deadline.ts +38 -0
- package/src/runtime/dependencies.ts +12 -0
- package/src/runtime/grants.ts +11 -7
- package/src/runtime/hooks.ts +24 -163
- package/src/runtime/lifecycle.ts +110 -77
- package/src/runtime/permission-check.ts +47 -0
- package/src/runtime/sessions.ts +334 -91
- package/src/runtime/state.ts +15 -8
- package/src/runtime/tool-calls.ts +0 -19
- package/src/session/context/turn/message/instruction-file.ts +13 -0
- package/src/session/context/turn/message/message.ts +17 -11
- package/src/session/context/turn/message/sender.ts +5 -2
- package/src/session/context/turn/message/tool-call.ts +3 -0
- package/src/session/context/turn/message/tool-result.ts +6 -1
- package/src/session/context/turn/turn.ts +4 -0
- package/src/session/conversation.ts +21 -8
- package/src/session/goal/goal.ts +1 -1
- package/src/session/goal/task.ts +2 -2
- package/src/session/session.ts +227 -24
- package/src/testing/claude-code.ts +23 -0
- package/src/testing/fake-claude.ts +5 -1
- package/src/testing/fake-sessions.ts +38 -24
- package/src/testing.ts +88 -19
- package/testing/claude-code.d.ts +12 -0
- package/testing/claude-code.d.ts.map +1 -0
- package/testing/claude-code.js +10 -0
- package/testing/fake-claude.d.ts +4 -0
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +4 -1
- package/testing/fake-sessions.d.ts +8 -6
- package/testing/fake-sessions.d.ts.map +1 -1
- package/testing/fake-sessions.js +35 -20
- package/testing.d.ts +38 -9
- package/testing.d.ts.map +1 -1
- package/testing.js +58 -8
- package/docs/hooks.md +0 -259
- package/session/context/turn/message/document.d.ts +0 -7
- package/session/context/turn/message/document.d.ts.map +0 -1
- package/session/context/turn/message/document.js +0 -1
- package/src/session/context/turn/message/document.ts +0 -8
package/runtime/before.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ContextEnd } from '../session/context/context.js';
|
|
2
|
-
import {
|
|
3
|
-
import { Message, messagesOf, rowOfAppend, withTexts } from '../session/context/turn/message/message.js';
|
|
2
|
+
import { InstructionFile, isRulePath } from '../session/context/turn/message/instruction-file.js';
|
|
3
|
+
import { instructionPathOf, Message, messagesOf, noFiles, rowOfAppend, withTexts } from '../session/context/turn/message/message.js';
|
|
4
4
|
import { Note } from '../session/context/turn/message/note.js';
|
|
5
5
|
import { Notice } from '../session/context/turn/message/notice.js';
|
|
6
6
|
import { Prompt } from '../session/context/turn/message/prompt.js';
|
|
@@ -10,10 +10,16 @@ import { Skill } from '../session/context/turn/message/skill.js';
|
|
|
10
10
|
import { ToolCall } from '../session/context/turn/message/tool-call.js';
|
|
11
11
|
import { ToolResult } from '../session/context/turn/message/tool-result.js';
|
|
12
12
|
import { TurnEnd } from '../session/context/turn/turn.js';
|
|
13
|
-
import {
|
|
13
|
+
import { Task, TaskStart } from '../session/goal/task.js';
|
|
14
|
+
import { sessionEvents } from '../session/session.js';
|
|
14
15
|
import { cmodPluginName } from './dependencies.js';
|
|
15
16
|
import { toolInputOf } from './tool-calls.js';
|
|
16
|
-
|
|
17
|
+
import { resolve } from '../vendor.js';
|
|
18
|
+
const appended = [Note, Reply, Notice];
|
|
19
|
+
const withNote = (below, note) => {
|
|
20
|
+
const fields = (below ?? {});
|
|
21
|
+
return note === undefined ? fields : { ...fields, additionalContext: [...(fields['additionalContext'] ?? []), note] };
|
|
22
|
+
};
|
|
17
23
|
const relayTag = /^(?:<cross-session-message[^>]*>\s*)?<cmod-relay>([\s\S]*)<\/cmod-relay>(?:\s*<\/cross-session-message>[\s\S]*)?$/;
|
|
18
24
|
export function relayOf(e) {
|
|
19
25
|
const isFromCmod = e.origin.kind === 'peer' && !('teammate' in e.origin) && e.origin.plugin === cmodPluginName;
|
|
@@ -26,34 +32,56 @@ export function installBefore({ claude, router, hooks }) {
|
|
|
26
32
|
const message = (where, unplaced, task, isInTurn = true) => {
|
|
27
33
|
const turn = isInTurn ? (task === undefined ? where.turn : where.taskTurns[task]) : undefined;
|
|
28
34
|
const context = task === undefined ? where.context : (where.tasks[task]?.context ?? where.context);
|
|
29
|
-
|
|
35
|
+
const call = unplaced.type === ToolResult ? where.openCalls?.[unplaced.callId] : undefined;
|
|
36
|
+
return { type: Message, message: { ...unplaced, ...call, session: where.session, context, ...(turn === undefined ? {} : { turn: turn.prompt.id }), ...(task === undefined ? {} : { task }) } };
|
|
37
|
+
};
|
|
38
|
+
const titles = new Map();
|
|
39
|
+
const spawned = new Map();
|
|
40
|
+
const agentFolders = new Map();
|
|
41
|
+
const toolResultHook = (isFailure) => async (e, next) => {
|
|
42
|
+
if (!(await wants(ToolResult)))
|
|
43
|
+
return next(e);
|
|
44
|
+
const where = await place();
|
|
45
|
+
const name = String(e['tool_name']);
|
|
46
|
+
const callId = String(e['tool_use_id']);
|
|
47
|
+
const input = (typeof e['tool_input'] === 'object' && e['tool_input'] !== null ? e['tool_input'] : {});
|
|
48
|
+
const task = typeof e['agent_id'] === 'string' ? e['agent_id'] : undefined;
|
|
49
|
+
const result = { id: callId, at: now(), type: ToolResult, callId, name, input, cwd: String(e['cwd']), files: noFiles, output: isFailure ? e['error'] : e['tool_response'], isError: isFailure };
|
|
50
|
+
const answer = await asked(ToolResult, message(where, result, task));
|
|
51
|
+
const below = await next(e);
|
|
52
|
+
const rewritten = answer.output === undefined || isFailure ? {} : name.startsWith('mcp__') ? { updatedMCPToolOutput: answer.output } : { updatedToolOutput: answer.output };
|
|
53
|
+
const failed = answer.isError === true && !isFailure ? { block: answer.note ?? `${name} failed.` } : {};
|
|
54
|
+
return { ...withNote(below, answer.isError === true ? undefined : answer.note), ...rewritten, ...failed };
|
|
30
55
|
};
|
|
31
56
|
const added = [
|
|
32
57
|
router.add('prompt.submit', async (e, next) => {
|
|
33
|
-
if (!(await wants(Prompt))
|
|
58
|
+
if (!(await wants(Prompt)))
|
|
34
59
|
return next(e);
|
|
35
60
|
const where = await place();
|
|
36
61
|
const answer = await asked(Prompt, message(where, { id: '', at: now(), type: Prompt, text: e.text, from: senderOf(e.origin, false) }, undefined, false));
|
|
37
62
|
if (answer.refuse !== undefined)
|
|
38
63
|
return { drop: answer.refuse };
|
|
39
|
-
|
|
64
|
+
const text = answer.text ?? e.text;
|
|
65
|
+
if (answer.title !== undefined)
|
|
66
|
+
titles.set(text, answer.title);
|
|
67
|
+
const context = answer.note === undefined ? e.context : [...(e.context ?? []), answer.note];
|
|
68
|
+
const ran = await next({ ...e, text, ...(context === undefined ? {} : { context }) });
|
|
69
|
+
const passed = titles.get(text);
|
|
70
|
+
if (passed !== undefined && ('drop' in ran || ran.text !== text)) {
|
|
71
|
+
titles.delete(text);
|
|
72
|
+
if (!('drop' in ran) && typeof ran.text === 'string')
|
|
73
|
+
titles.set(ran.text, passed);
|
|
74
|
+
}
|
|
75
|
+
return ran;
|
|
40
76
|
}),
|
|
41
|
-
router.add('
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const answer = await asked(Prompt, message(where, { id: '', at: now(), type: Prompt, text: typed, from: senderOf(e.origin, false) }, undefined, false));
|
|
47
|
-
if (answer.refuse !== undefined)
|
|
48
|
-
return { text: answer.refuse };
|
|
49
|
-
if (answer.text === undefined || answer.text === typed)
|
|
50
|
-
return next(e);
|
|
51
|
-
const same = new RegExp(`^/${e.command}(?:\\s+|$)`).exec(answer.text);
|
|
52
|
-
if (same !== null)
|
|
53
|
-
return next({ ...e, args: answer.text.slice(same[0].length) });
|
|
54
|
-
void claude.prompt.submit({ text: answer.text });
|
|
55
|
-
return {};
|
|
77
|
+
router.add('classic.UserPromptSubmit', async (e, next) => {
|
|
78
|
+
const named = titles.get(e.prompt);
|
|
79
|
+
titles.delete(e.prompt);
|
|
80
|
+
const below = await next(e);
|
|
81
|
+
return named === undefined ? below : { ...below, sessionTitle: named };
|
|
56
82
|
}),
|
|
83
|
+
router.add('classic.PostToolUse', toolResultHook(false)),
|
|
84
|
+
router.add('classic.PostToolUseFailure', toolResultHook(true)),
|
|
57
85
|
router.add('session.receive', async (e, next) => {
|
|
58
86
|
if (!(await wants(Prompt)) || relayOf(e) !== undefined)
|
|
59
87
|
return next(e);
|
|
@@ -71,11 +99,11 @@ export function installBefore({ claude, router, hooks }) {
|
|
|
71
99
|
return answer.text === undefined ? next(e) : { text: answer.text };
|
|
72
100
|
}),
|
|
73
101
|
router.add('prompt.attachment', async (e, next) => {
|
|
74
|
-
if (!(await wants(
|
|
102
|
+
if (!(await wants(InstructionFile)) || e.type !== 'nested_memory')
|
|
75
103
|
return next(e);
|
|
76
104
|
const where = await place();
|
|
77
|
-
const path =
|
|
78
|
-
const answer = await asked(
|
|
105
|
+
const path = instructionPathOf(e.text);
|
|
106
|
+
const answer = await asked(InstructionFile, message(where, { id: '', at: now(), type: InstructionFile, path, text: e.text, isRule: isRulePath(path) }, e.agentId));
|
|
79
107
|
if (answer.refuse !== undefined)
|
|
80
108
|
return { text: null };
|
|
81
109
|
return answer.text === undefined ? next(e) : { text: answer.text };
|
|
@@ -104,7 +132,8 @@ export function installBefore({ claude, router, hooks }) {
|
|
|
104
132
|
return next(e);
|
|
105
133
|
const where = await place();
|
|
106
134
|
const input = toolInputOf(e);
|
|
107
|
-
const
|
|
135
|
+
const cwd = (e.agentId === undefined ? undefined : agentFolders.get(e.agentId)) ?? (await claude.session.cwd());
|
|
136
|
+
const answer = await asked(ToolCall, message(where, { id: e.tool_use_id, at: now(), type: ToolCall, callId: e.tool_use_id, name: e.tool, input, cwd, files: noFiles }, e.agentId));
|
|
108
137
|
if (answer.refuse !== undefined)
|
|
109
138
|
return { deny: answer.refuse };
|
|
110
139
|
if (answer.result !== undefined)
|
|
@@ -115,27 +144,54 @@ export function installBefore({ claude, router, hooks }) {
|
|
|
115
144
|
return next({ ...reserved, ...answer.input });
|
|
116
145
|
}),
|
|
117
146
|
router.add('agent.spawn', async (e, next) => {
|
|
147
|
+
spawned.set(e.tool_use_id, e.prompt);
|
|
148
|
+
const start = async (args) => {
|
|
149
|
+
const started = await next(args);
|
|
150
|
+
const folder = args.isTeammate === true ? undefined : (args.cwd ?? (args.parentAgentId === undefined ? undefined : agentFolders.get(args.parentAgentId)));
|
|
151
|
+
if (started.agentId !== undefined && folder !== undefined)
|
|
152
|
+
agentFolders.set(started.agentId, resolve(await claude.session.cwd(), folder));
|
|
153
|
+
return started;
|
|
154
|
+
};
|
|
118
155
|
if (!(await wants(TaskStart)))
|
|
119
|
-
return
|
|
156
|
+
return start(e);
|
|
120
157
|
const where = await place();
|
|
121
158
|
const task = { id: '', title: e.description, agentType: e.subagentType, model: e.model ?? e.parentModel, openedBy: e.tool_use_id, openedAt: now(), ...(e.parentAgentId === undefined ? {} : { parent: e.parentAgentId }) };
|
|
122
159
|
const answer = await asked(TaskStart, { type: TaskStart, task: { ...task, context: where.context } });
|
|
123
|
-
if (answer.refuse !== undefined)
|
|
160
|
+
if (answer.refuse !== undefined) {
|
|
161
|
+
spawned.delete(e.tool_use_id);
|
|
124
162
|
return { deny: answer.refuse };
|
|
125
|
-
|
|
163
|
+
}
|
|
164
|
+
return start(answer.owner === undefined ? e : { ...e, model: answer.owner.model });
|
|
126
165
|
}),
|
|
127
|
-
router.add('classic.
|
|
128
|
-
if (!(await wants(TaskEnd)) && !(await wants(TurnEnd)))
|
|
129
|
-
return next(e);
|
|
166
|
+
router.add('classic.SubagentStart', async (e, next) => {
|
|
130
167
|
const where = await place();
|
|
131
|
-
const
|
|
132
|
-
|
|
168
|
+
const openedBy = where.tasks[e.agent_id]?.openedBy;
|
|
169
|
+
const prompt = openedBy === undefined ? undefined : spawned.get(openedBy);
|
|
170
|
+
if (openedBy !== undefined)
|
|
171
|
+
spawned.delete(openedBy);
|
|
172
|
+
if (!(await wants(Prompt)))
|
|
133
173
|
return next(e);
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
|
|
174
|
+
const open = where.taskTurns[e.agent_id]?.prompt;
|
|
175
|
+
const text = open?.text ?? prompt;
|
|
176
|
+
if (text === undefined)
|
|
177
|
+
return next(e);
|
|
178
|
+
const answer = await asked(Prompt, message(where, { id: open?.id ?? '', at: now(), type: Prompt, text, from: open?.from ?? { type: Task } }, e.agent_id, false));
|
|
179
|
+
return withNote(await next(e), answer.note);
|
|
180
|
+
}),
|
|
181
|
+
router.add('classic.SubagentStop', async (e, next) => {
|
|
182
|
+
const stopped = (answer) => {
|
|
183
|
+
if (answer.block === undefined)
|
|
184
|
+
agentFolders.delete(e.agent_id);
|
|
185
|
+
return answer;
|
|
186
|
+
};
|
|
187
|
+
if (!(await wants(TurnEnd)))
|
|
188
|
+
return stopped(await next(e));
|
|
189
|
+
const turn = (await place()).taskTurns[e.agent_id];
|
|
190
|
+
if (turn === undefined)
|
|
191
|
+
return stopped(await next(e));
|
|
192
|
+
const answer = await asked(TurnEnd, { type: TurnEnd, turn: { ...turn, closedAt: now() } });
|
|
137
193
|
const below = await next(e);
|
|
138
|
-
return refuse === undefined ? below : { ...below, block: refuse };
|
|
194
|
+
return stopped(answer.refuse === undefined ? below : { ...below, block: answer.refuse });
|
|
139
195
|
}),
|
|
140
196
|
router.add('classic.Stop', async (e, next) => {
|
|
141
197
|
if (!(await wants(TurnEnd)))
|
|
@@ -162,6 +218,8 @@ export function installBefore({ claude, router, hooks }) {
|
|
|
162
218
|
return { dispose: () => added.forEach((each) => each.dispose()) };
|
|
163
219
|
}
|
|
164
220
|
export function withAnswer(change, answer) {
|
|
221
|
+
if (change.type === Message && answer.output !== undefined && change.message.type === ToolResult)
|
|
222
|
+
return { ...change, message: { ...change.message, output: answer.output } };
|
|
165
223
|
if (change.type === Message && answer.text !== undefined)
|
|
166
224
|
return { ...change, message: { ...change.message, text: answer.text } };
|
|
167
225
|
if (change.type === Message && answer.input !== undefined && change.message.type === ToolCall)
|
|
@@ -170,18 +228,47 @@ export function withAnswer(change, answer) {
|
|
|
170
228
|
return { ...change, task: { ...change.task, model: answer.owner.model } };
|
|
171
229
|
return change;
|
|
172
230
|
}
|
|
173
|
-
export
|
|
231
|
+
export const methodOf = (prefix, event) => `${prefix}${Object.entries(sessionEvents).find(([, each]) => each === event)?.[0] ?? event}`;
|
|
232
|
+
export const beforeAnswerKeys = {
|
|
233
|
+
prompt: ['text', 'note', 'title', 'refuse'],
|
|
234
|
+
note: ['text'],
|
|
235
|
+
skill: ['text'],
|
|
236
|
+
instructionFile: ['text', 'refuse'],
|
|
237
|
+
reply: ['text'],
|
|
238
|
+
toolCall: ['input', 'result', 'refuse'],
|
|
239
|
+
toolResult: ['output', 'isError', 'note'],
|
|
240
|
+
notice: ['text'],
|
|
241
|
+
taskStart: ['owner', 'refuse'],
|
|
242
|
+
turnEnd: ['refuse'],
|
|
243
|
+
contextEnd: ['refuse'],
|
|
244
|
+
};
|
|
245
|
+
export function foldBefore(event, change, askers, report) {
|
|
246
|
+
return foldAnswers(methodOf('before', event), beforeAnswerKeys[event], ['refuse', 'result'], change, askers, report, withAnswer);
|
|
247
|
+
}
|
|
248
|
+
export function takenAnswer(method, takes, answer) {
|
|
249
|
+
if (answer === undefined || answer === null || answer === false)
|
|
250
|
+
return undefined;
|
|
251
|
+
if (typeof answer !== 'object' || Array.isArray(answer))
|
|
252
|
+
throw new Error(`it answered ${JSON.stringify(answer)}, but ${method} takes an object or nothing: ${takes.map((key) => `{ ${key} }`).join(', ') || 'no answer'}.`);
|
|
253
|
+
const unread = Object.keys(answer).filter((key) => !takes.includes(key));
|
|
254
|
+
if (unread.length > 0)
|
|
255
|
+
throw new Error(`it answered ${unread.join(' and ')}, which ${method} does not take. It takes ${takes.map((key) => `{ ${key} }`).join(', ') || 'no answer'}.`);
|
|
256
|
+
return answer;
|
|
257
|
+
}
|
|
258
|
+
export async function foldAnswers(method, takes, ends, change, askers, report, applied = (same) => same) {
|
|
174
259
|
let latest = change;
|
|
175
260
|
let result;
|
|
176
261
|
for (const ask of askers) {
|
|
177
262
|
try {
|
|
178
|
-
const answer =
|
|
179
|
-
if (answer ===
|
|
263
|
+
const answer = takenAnswer(method, takes, await ask(latest));
|
|
264
|
+
if (typeof answer !== 'object' || answer === null)
|
|
180
265
|
continue;
|
|
181
|
-
|
|
182
|
-
|
|
266
|
+
const given = answer;
|
|
267
|
+
const notes = [result?.['note'], given['note']].filter((note) => typeof note === 'string');
|
|
268
|
+
result = { ...result, ...given, ...(notes.length === 0 ? {} : { note: notes.join('\n\n') }) };
|
|
269
|
+
if (ends.some((key) => given[key] !== undefined))
|
|
183
270
|
return result;
|
|
184
|
-
latest =
|
|
271
|
+
latest = applied(latest, answer);
|
|
185
272
|
}
|
|
186
273
|
catch (error) {
|
|
187
274
|
report(error);
|
|
@@ -189,26 +276,3 @@ export async function foldAnswers(event, change, askers, report) {
|
|
|
189
276
|
}
|
|
190
277
|
return result;
|
|
191
278
|
}
|
|
192
|
-
export function answerOf(event, answer) {
|
|
193
|
-
if (typeof answer !== 'object' || answer === null)
|
|
194
|
-
return undefined;
|
|
195
|
-
const given = answer;
|
|
196
|
-
const allowed = {
|
|
197
|
-
prompt: ['text', 'refuse'],
|
|
198
|
-
note: ['text'],
|
|
199
|
-
skill: ['text'],
|
|
200
|
-
document: ['text', 'refuse'],
|
|
201
|
-
reply: ['text'],
|
|
202
|
-
toolCall: ['input', 'result', 'refuse'],
|
|
203
|
-
toolResult: ['text'],
|
|
204
|
-
notice: ['text'],
|
|
205
|
-
taskStart: ['owner', 'refuse'],
|
|
206
|
-
taskEnd: ['refuse'],
|
|
207
|
-
turnEnd: ['refuse'],
|
|
208
|
-
contextEnd: ['refuse'],
|
|
209
|
-
};
|
|
210
|
-
const unread = Object.keys(given).filter((key) => !allowed[event].includes(key));
|
|
211
|
-
if (unread.length > 0)
|
|
212
|
-
throw new Error(`a before(${event}) listener answered ${unread.join(' and ')}, which ${event} does not take. It takes ${allowed[event].map((key) => `{ ${key} }`).join(', ')}.`);
|
|
213
|
-
return given;
|
|
214
|
-
}
|
package/runtime/claude.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentInfo, AgentSpawnArgs, AgentSpawnResult, Args, EngineInterface, AskOptions, CommandSpec, ConfigRow, ElementTable, FsEntry, FsStat, FsStatOptions, HookStream, HttpInit, HttpResponse, InvalidatableEventName, PaneCloseArgs, PaneOpenArgs, ProcessRunInit, ProcessRunResult, ProcessSpawnChunk, ProcessSpawnRequest, ProcessSpawnResult, RenderSurface, ResolveInput, SessionUsage, Settings, SettingsReadArgs, Timer, ToolSpec, UiCopyArgs, UiFocusArgs, UiFocusResult, UiCopyResult, UiLogOptions, UiOpenResult, UiPane, UiScrollArgs, UiScrollResult } from 'claude-code';
|
|
1
|
+
import type { AgentInfo, AgentSpawnArgs, AgentSpawnResult, Args, EngineInterface, AskOptions, CommandInfo, CommandRunArgs, CommandRunResult, CommandSpec, ConfigRow, ElementTable, FsEntry, FsStat, FsStatOptions, HookStream, HttpInit, HttpResponse, InvalidatableEventName, PaneCloseArgs, PaneOpenArgs, ProcessRunInit, ProcessRunResult, ProcessSpawnChunk, ProcessSpawnRequest, ProcessSpawnResult, RenderSurface, ResolveInput, SessionUsage, Settings, SettingsReadArgs, Timer, ToolSpec, UiCopyArgs, UiFocusArgs, UiFocusResult, UiCopyResult, UiLogOptions, UiOpenResult, UiPane, UiScrollArgs, UiScrollResult } from 'claude-code';
|
|
2
2
|
export type Claude = {
|
|
3
3
|
readonly plugin: {
|
|
4
4
|
readonly name: string;
|
|
@@ -63,6 +63,9 @@ export type Claude = {
|
|
|
63
63
|
readonly prompt: {
|
|
64
64
|
submit: EngineInterface['prompt']['submit'];
|
|
65
65
|
};
|
|
66
|
+
readonly turn: {
|
|
67
|
+
abort: EngineInterface['turn']['abort'];
|
|
68
|
+
};
|
|
66
69
|
readonly model: {
|
|
67
70
|
complete: EngineInterface['model']['complete'];
|
|
68
71
|
};
|
|
@@ -70,6 +73,8 @@ export type Claude = {
|
|
|
70
73
|
register(command: CommandSpec): Promise<{
|
|
71
74
|
command: string;
|
|
72
75
|
}>;
|
|
76
|
+
list(): Promise<readonly CommandInfo[]>;
|
|
77
|
+
run(args: CommandRunArgs): Promise<CommandRunResult>;
|
|
73
78
|
};
|
|
74
79
|
readonly tool: {
|
|
75
80
|
register(tool: ToolSpec): Promise<{
|
package/runtime/claude.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../src/runtime/conversations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAY5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AA2BzC,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,CAAA;IAClH,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAED,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../src/runtime/conversations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAY5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AA2BzC,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,CAAA;IAClH,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAED,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG,aAAa,CA6iBlR"}
|
package/runtime/conversations.js
CHANGED
|
@@ -8,10 +8,10 @@ import { GoalChange } from '../session/goal/goal.js';
|
|
|
8
8
|
import { receivedMatcher } from '../utils/matcher.js';
|
|
9
9
|
import { ifMissing } from '../utils/paths.js';
|
|
10
10
|
import { formatExit, messageOf } from '../utils/text.js';
|
|
11
|
-
import {
|
|
11
|
+
import { foldBefore, installBefore, relayOf } from './before.js';
|
|
12
12
|
import { cmodPluginName } from './dependencies.js';
|
|
13
13
|
import { readLines, runCmod } from './programs.js';
|
|
14
|
-
import { actPermission,
|
|
14
|
+
import { actPermission, conversationMethods, everySession, isAct, isHeardBy, resultOf, spawnTask, usageOf } from './sessions.js';
|
|
15
15
|
const bufferedTaskRows = 200;
|
|
16
16
|
const beforeDeadlineMs = 5000;
|
|
17
17
|
const livenessMs = 5000;
|
|
@@ -34,7 +34,23 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
34
34
|
const liveIds = new Set();
|
|
35
35
|
const waitingRows = new Map();
|
|
36
36
|
let follower;
|
|
37
|
-
const
|
|
37
|
+
const engineTurns = new Map();
|
|
38
|
+
router.add('turn.start', async (e, next) => {
|
|
39
|
+
const agent = e.agentId ?? '';
|
|
40
|
+
engineTurns.set(agent, e.turnId);
|
|
41
|
+
return next(e);
|
|
42
|
+
});
|
|
43
|
+
const endTurn = (ending, task) => (below) => {
|
|
44
|
+
if (below.block !== undefined)
|
|
45
|
+
return below;
|
|
46
|
+
engineTurns.delete(task ?? '');
|
|
47
|
+
dispatch(session, conversation.endTurn(new Date().toISOString(), ending, task));
|
|
48
|
+
return below;
|
|
49
|
+
};
|
|
50
|
+
router.add('classic.Stop', async (e, next) => endTurn({ reason: 'answer', ...(e.last_assistant_message === undefined ? {} : { answer: e.last_assistant_message }) })(await next(e)));
|
|
51
|
+
router.add('classic.StopFailure', async (e, next) => endTurn({ reason: 'error', failure: { type: String(e.error), text: e.error_details ?? e.last_assistant_message ?? String(e.error) } })(await next(e)));
|
|
52
|
+
router.add('classic.SubagentStop', async (e, next) => endTurn({ reason: 'answer', ...(e.last_assistant_message === undefined ? {} : { answer: e.last_assistant_message }) }, e.agent_id)(await next(e)));
|
|
53
|
+
const json = async (args) => JSON.parse(await runCmod(claude, [...args, '--json', '--project', project()], await claude.session.id()));
|
|
38
54
|
const isGranted = async (caller, item) => {
|
|
39
55
|
if (caller === cmodPluginName)
|
|
40
56
|
return true;
|
|
@@ -61,6 +77,8 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
61
77
|
}
|
|
62
78
|
};
|
|
63
79
|
const restartFollower = async () => {
|
|
80
|
+
if (session === '')
|
|
81
|
+
return;
|
|
64
82
|
const wantsEvery = [...heard.values()].some((sessions) => (sessions.get(everySession) ?? []).length > 0);
|
|
65
83
|
const named = [...heard.values()].flatMap((sessions) => [...sessions].filter(([id, list]) => id !== session && id !== everySession && list.length > 0).map(([id]) => id));
|
|
66
84
|
const others = [...new Set(named)].sort();
|
|
@@ -98,16 +116,39 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
98
116
|
if (sent.isDelivered !== true)
|
|
99
117
|
throw ended(to);
|
|
100
118
|
};
|
|
119
|
+
const waitingOn = new Map();
|
|
120
|
+
let liveness;
|
|
121
|
+
let isChecking = false;
|
|
122
|
+
const checkLiveness = async () => {
|
|
123
|
+
if (isChecking)
|
|
124
|
+
return;
|
|
125
|
+
isChecking = true;
|
|
126
|
+
try {
|
|
127
|
+
const waiting = [...waitingOn];
|
|
128
|
+
const running = new Set((await json(['history', 'sessions', '--running', '--all'])).map((each) => each.id));
|
|
129
|
+
for (const [settle, to] of waiting)
|
|
130
|
+
if (!running.has(to))
|
|
131
|
+
settle.reject(ended(to));
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
isChecking = false;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const watchLife = (settle, to) => {
|
|
138
|
+
waitingOn.set(settle, to);
|
|
139
|
+
liveness ??= claude.clock.every(livenessMs, () => void checkLiveness().catch((error) => report('liveness', 'Could not check which sessions still run', error)));
|
|
140
|
+
return {
|
|
141
|
+
cancel() {
|
|
142
|
+
waitingOn.delete(settle);
|
|
143
|
+
if (waitingOn.size > 0)
|
|
144
|
+
return;
|
|
145
|
+
liveness?.cancel();
|
|
146
|
+
liveness = undefined;
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
};
|
|
101
150
|
const ask = (to, relay, deadlineMs) => new Promise((resolve, reject) => {
|
|
102
151
|
const id = `${session}:${(asks += 1)}`;
|
|
103
|
-
const timer = deadlineMs === undefined
|
|
104
|
-
? claude.clock.every(livenessMs, () => {
|
|
105
|
-
void isRunning(to).then((isLive) => {
|
|
106
|
-
if (!isLive)
|
|
107
|
-
settle.reject(ended(to));
|
|
108
|
-
});
|
|
109
|
-
})
|
|
110
|
-
: claude.clock.after(deadlineMs, () => settle.reject(new Error(`session ${to} did not answer within ${deadlineMs / 1000} s`)));
|
|
111
152
|
const settle = {
|
|
112
153
|
resolve(value) {
|
|
113
154
|
if (asked.delete(id))
|
|
@@ -120,6 +161,7 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
120
161
|
reject(error);
|
|
121
162
|
},
|
|
122
163
|
};
|
|
164
|
+
const timer = deadlineMs === undefined ? watchLife(settle, to) : claude.clock.after(deadlineMs, () => settle.reject(new Error(`session ${to} did not answer within ${deadlineMs / 1000} s`)));
|
|
123
165
|
asked.set(id, settle);
|
|
124
166
|
post(to, { ...relay, id, from: session }).catch((error) => settle.reject(error instanceof Error ? error : new Error(messageOf(error))));
|
|
125
167
|
});
|
|
@@ -156,17 +198,16 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
156
198
|
watching = readWatchers().catch((error) => report('before', 'Kept the other sessions’ before listeners from before', error));
|
|
157
199
|
};
|
|
158
200
|
const place = () => {
|
|
159
|
-
const { context, contextOpenedAt, turn, tasks, taskTurns } = conversation.state;
|
|
160
|
-
return { session, context, contextOpenedAt, ...(turn === undefined ? {} : { turn }), tasks, taskTurns };
|
|
201
|
+
const { context, contextOpenedAt, turn, tasks, taskTurns, openCalls } = conversation.state;
|
|
202
|
+
return { session, context, contextOpenedAt, ...(turn === undefined ? {} : { turn }), tasks, taskTurns, ...(openCalls === undefined ? {} : { openCalls }) };
|
|
161
203
|
};
|
|
162
204
|
const deciders = (event) => {
|
|
163
205
|
const all = [...[...ownWatches.values()].filter((watch) => watch.target === session || watch.target === everySession).map((watch) => ({ ...watch, from: session })), ...watchers];
|
|
164
206
|
return [...new Map(all.filter((watcher) => watcher.events.includes(event)).map((watcher) => [`${watcher.from}\n${watcher.mod}`, watcher])).values()];
|
|
165
207
|
};
|
|
166
208
|
const askHere = async (mod, event, change, from = session, isInProject = true) => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
throw new Error(`${mod} needs the ${needed} permission for before(${event}). Turn it on in /mods ${mod}.`);
|
|
209
|
+
if (from !== session && !(await isGranted(mod, 'conversation')))
|
|
210
|
+
throw new Error(`${mod} needs the conversation permission to change what happens in another session. Turn it on in /mods ${mod}.`);
|
|
170
211
|
return claude.cmod.call({ to: mod, method: conversationMethods.before, input: { session: from, event, change, isInProject } });
|
|
171
212
|
};
|
|
172
213
|
const askAway = async (watcher, event, change) => {
|
|
@@ -194,7 +235,7 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
194
235
|
await Promise.all([starting, watching]);
|
|
195
236
|
return deciders(event).length > 0;
|
|
196
237
|
},
|
|
197
|
-
decide: (event, change) =>
|
|
238
|
+
decide: (event, change) => foldBefore(event, change, deciders(event).map((watcher) => (latest) => (watcher.from === session ? askHere(watcher.mod, event, latest) : askAway(watcher, event, latest))), (error) => report(`before:${event}`, `Passed the ${event} on without a mod's answer`, error)),
|
|
198
239
|
},
|
|
199
240
|
});
|
|
200
241
|
const start = (id, source) => {
|
|
@@ -325,11 +366,13 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
325
366
|
const perform = async (caller, action, input, task) => {
|
|
326
367
|
await checkAct(caller, action, input);
|
|
327
368
|
await starting;
|
|
369
|
+
if (action === 'abort')
|
|
370
|
+
return abortTurn(input, task);
|
|
328
371
|
if (task !== undefined)
|
|
329
372
|
return performInTask(action, input, task);
|
|
330
373
|
if (action === 'usage')
|
|
331
374
|
return usageOf(claude);
|
|
332
|
-
if (action === '
|
|
375
|
+
if (action === 'surfaces')
|
|
333
376
|
return [...(await claude.session.surfaces())];
|
|
334
377
|
if (action === 'send') {
|
|
335
378
|
const { type, text, as } = input;
|
|
@@ -342,27 +385,27 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
342
385
|
throw new Error(`Claude Code dropped the prompt: ${delivered.drop}`);
|
|
343
386
|
return null;
|
|
344
387
|
}
|
|
345
|
-
if (action === 'startTask')
|
|
346
|
-
|
|
347
|
-
const started = await claude.agent.spawn({
|
|
348
|
-
prompt: args.prompt,
|
|
349
|
-
...(args.name === undefined ? {} : { description: args.name, name: args.name }),
|
|
350
|
-
...(args.agentType === undefined ? {} : { subagentType: args.agentType }),
|
|
351
|
-
...(args.model === undefined ? {} : { model: args.model }),
|
|
352
|
-
...(args.cwd === undefined ? {} : { cwd: args.cwd }),
|
|
353
|
-
});
|
|
354
|
-
if (started.deny !== undefined)
|
|
355
|
-
throw new Error(`Claude Code refused the task: ${started.deny}`);
|
|
356
|
-
return { id: started.agentId ?? '', title: args.name ?? '', agentType: args.agentType ?? 'general-purpose', model: started.model, openedBy: '', openedAt: new Date().toISOString() };
|
|
357
|
-
}
|
|
388
|
+
if (action === 'startTask')
|
|
389
|
+
return spawnTask(claude, input);
|
|
358
390
|
const { name, input: toolInput } = input;
|
|
359
|
-
return resultOf(place(), await claude.tool.call({ ...toolInput, tool: name }));
|
|
391
|
+
return resultOf(place(), { name, input: toolInput, cwd: await claude.session.cwd() }, await claude.tool.call({ ...toolInput, tool: name }));
|
|
392
|
+
};
|
|
393
|
+
const abortTurn = async (input, task) => {
|
|
394
|
+
const turnId = engineTurns.get(task ?? '');
|
|
395
|
+
if (turnId === undefined)
|
|
396
|
+
throw new Error(`no turn is running in ${task === undefined ? `session ${session}` : `task ${task}`}.`);
|
|
397
|
+
const asked = isObject(input) ? input['turn'] : undefined;
|
|
398
|
+
const open = task === undefined ? conversation.state.turn : conversation.state.taskTurns[task];
|
|
399
|
+
if (open?.prompt.id !== asked)
|
|
400
|
+
throw new Error(`turn ${String(asked)} has ended, so there is nothing to abort.`);
|
|
401
|
+
await claude.turn.abort({ turnId });
|
|
402
|
+
return null;
|
|
360
403
|
};
|
|
361
404
|
const performInTask = async (action, input, task) => {
|
|
362
405
|
const running = conversation.state.tasks[task];
|
|
363
406
|
if (action === 'usage')
|
|
364
407
|
return json(['history', 'usage', session, '--task', task]);
|
|
365
|
-
if (action === '
|
|
408
|
+
if (action === 'surfaces')
|
|
366
409
|
return running === undefined || running.closedAt !== undefined ? [] : [...(await claude.session.surfaces())];
|
|
367
410
|
if (action !== 'send')
|
|
368
411
|
throw new Error(`cmod: ${action} runs only on a session's own main loop.`);
|
|
@@ -378,7 +421,7 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
378
421
|
const isLive = await isRunning(target);
|
|
379
422
|
if (!isLive && action === 'usage')
|
|
380
423
|
return json(['history', 'usage', target, ...(task === undefined ? [] : ['--task', task])]);
|
|
381
|
-
if (!isLive && action === '
|
|
424
|
+
if (!isLive && action === 'surfaces')
|
|
382
425
|
return [];
|
|
383
426
|
if (!isLive)
|
|
384
427
|
throw ended(task ?? target);
|
|
@@ -424,8 +467,8 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
424
467
|
},
|
|
425
468
|
async [conversationMethods.search](request) {
|
|
426
469
|
const before = isObject(request['before']) ? request['before'] : undefined;
|
|
427
|
-
const record = [...textArg('--session', request['session']), ...textArg('--task', request['task']), ...textArg('--turn', request['turn']), ...countArg('--context', request['context']), ...(request['
|
|
428
|
-
return json(['history', 'search', String(request['text']), ...scopeArgs(request), ...record, ...(request['running'] === true ? ['--running'] : []), ...
|
|
470
|
+
const record = [...textArg('--session', request['session']), ...textArg('--task', request['task']), ...textArg('--turn', request['turn']), ...countArg('--context', request['context']), ...(request['isAgent'] === true ? ['--agent'] : [])];
|
|
471
|
+
return json(['history', 'search', String(request['text']), ...scopeArgs(request), ...record, ...(request['running'] === true ? ['--running'] : []), ...(before === undefined ? [] : ['--before', `${String(before['session'])}:${String(before['id'])}`])]);
|
|
429
472
|
},
|
|
430
473
|
async [conversationMethods.messages](request) {
|
|
431
474
|
const id = String(request['session']);
|
|
@@ -523,7 +566,7 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
523
566
|
const task = typeof request['task'] === 'string' ? request['task'] : undefined;
|
|
524
567
|
if (!isAct(action))
|
|
525
568
|
throw new Error(`cmod takes no action named ${action}.`);
|
|
526
|
-
if (target === session)
|
|
569
|
+
if (target === (await claude.session.id()))
|
|
527
570
|
return perform(caller, action, request['input'], task);
|
|
528
571
|
return actElsewhere(caller, target, action, request['input'], task);
|
|
529
572
|
},
|
|
@@ -541,7 +584,8 @@ export function serveConversations({ claude, router, store, project, report }) {
|
|
|
541
584
|
if (method === undefined)
|
|
542
585
|
return undefined;
|
|
543
586
|
const input = isObject(e.input) ? e.input : {};
|
|
544
|
-
|
|
587
|
+
const isDropping = (e.method === conversationMethods.subscribe || e.method === conversationMethods.watchBefore) && Array.isArray(input['subscriptions']) && input['subscriptions'].length === 0;
|
|
588
|
+
if (e.method !== conversationMethods.act && !isDropping && input['session'] !== (await claude.session.id()) && !(await isGranted(e.caller, 'conversation')))
|
|
545
589
|
return { deny: `${e.caller ?? 'A mod'} reads your conversations without your grant. Turn it on in /mods ${e.caller ?? ''}.`.trim() };
|
|
546
590
|
try {
|
|
547
591
|
return { value: await method(input, e.caller) };
|
package/runtime/deadline.d.ts
CHANGED
|
@@ -5,5 +5,22 @@ export type Deadline = {
|
|
|
5
5
|
};
|
|
6
6
|
export declare const longestMs = 600000;
|
|
7
7
|
export declare const toolDeadline: Deadline;
|
|
8
|
+
export type ListenOptions = {
|
|
9
|
+
readonly timeoutMs?: number;
|
|
10
|
+
readonly onFailure?: 'pass' | 'refuse';
|
|
11
|
+
};
|
|
12
|
+
export type ListenTime = {
|
|
13
|
+
readonly deadline: number;
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
};
|
|
16
|
+
export declare const listenerMs = 10000;
|
|
17
|
+
export declare class PassedTimeout extends Error {
|
|
18
|
+
}
|
|
19
|
+
export declare function listenerOf(name: string, method: string, args: readonly unknown[]): {
|
|
20
|
+
readonly matcher: unknown;
|
|
21
|
+
readonly listener: (payload: never, time: ListenTime) => unknown;
|
|
22
|
+
readonly options: ListenOptions;
|
|
23
|
+
};
|
|
24
|
+
export declare function withinTime<Value>(clock: Pick<Claude['clock'], 'now'>, method: string, { timeoutMs }: ListenOptions, run: (time: ListenTime) => Value | Promise<Value>): Promise<Value>;
|
|
8
25
|
export declare function beforeDeadline<Value>(claude: Claude, { ms, job }: Deadline, call: string, task: Promise<Value>): Promise<Value>;
|
|
9
26
|
//# sourceMappingURL=deadline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deadline.d.ts","sourceRoot":"","sources":["../src/runtime/deadline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,eAAO,MAAM,SAAS,SAAU,CAAA;AAEhC,eAAO,MAAM,YAAY,EAAE,QAAqC,CAAA;AAEhE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAe/H"}
|
|
1
|
+
{"version":3,"file":"deadline.d.ts","sourceRoot":"","sources":["../src/runtime/deadline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,eAAO,MAAM,SAAS,SAAU,CAAA;AAEhC,eAAO,MAAM,YAAY,EAAE,QAAqC,CAAA;AAEhE,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAA;AAEnG,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAA;AAEpF,eAAO,MAAM,UAAU,QAAS,CAAA;AAEhC,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAI3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;CAAE,CASnN;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,SAAsB,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAezM;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAe/H"}
|