@cmodjs/core 1.6.0 → 2.0.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.
Files changed (128) hide show
  1. package/docs/commands.md +4 -4
  2. package/docs/index.md +12 -11
  3. package/docs/jobs.md +12 -16
  4. package/docs/mod.md +111 -36
  5. package/docs/permissions.md +14 -18
  6. package/docs/session.md +171 -82
  7. package/docs/state.md +5 -5
  8. package/docs/testing.md +57 -41
  9. package/docs/ui.md +9 -9
  10. package/jobs/permissions/decide-permission.d.ts.map +1 -1
  11. package/jobs/permissions/decide-permission.js +1 -1
  12. package/jobs/prompt.d.ts +1 -3
  13. package/jobs/prompt.d.ts.map +1 -1
  14. package/jobs/prompt.js +2 -21
  15. package/jobs/slash-command.d.ts +1 -1
  16. package/jobs/slash-command.d.ts.map +1 -1
  17. package/jobs/slash-command.js +1 -1
  18. package/jobs/status-line.d.ts +0 -1
  19. package/jobs/status-line.d.ts.map +1 -1
  20. package/jobs/status-line.js +3 -4
  21. package/mod.d.ts +53 -105
  22. package/mod.d.ts.map +1 -1
  23. package/mod.js +18 -80
  24. package/package.json +1 -1
  25. package/records.d.ts +1 -1
  26. package/records.js +1 -1
  27. package/register.d.ts.map +1 -1
  28. package/register.js +3 -1
  29. package/runtime/before.d.ts +5 -1
  30. package/runtime/before.d.ts.map +1 -1
  31. package/runtime/before.js +81 -39
  32. package/runtime/claude.d.ts +6 -1
  33. package/runtime/claude.d.ts.map +1 -1
  34. package/runtime/conversations.d.ts.map +1 -1
  35. package/runtime/conversations.js +45 -26
  36. package/runtime/deadline.d.ts +17 -0
  37. package/runtime/deadline.d.ts.map +1 -1
  38. package/runtime/deadline.js +34 -0
  39. package/runtime/dependencies.d.ts +2 -0
  40. package/runtime/dependencies.d.ts.map +1 -1
  41. package/runtime/dependencies.js +12 -0
  42. package/runtime/grants.d.ts.map +1 -1
  43. package/runtime/grants.js +13 -8
  44. package/runtime/hooks.d.ts +28 -11
  45. package/runtime/hooks.d.ts.map +1 -1
  46. package/runtime/hooks.js +20 -123
  47. package/runtime/lifecycle.d.ts +2 -1
  48. package/runtime/lifecycle.d.ts.map +1 -1
  49. package/runtime/lifecycle.js +66 -49
  50. package/runtime/sessions.d.ts +31 -5
  51. package/runtime/sessions.d.ts.map +1 -1
  52. package/runtime/sessions.js +342 -81
  53. package/runtime/tool-calls.d.ts +0 -1
  54. package/runtime/tool-calls.d.ts.map +1 -1
  55. package/runtime/tool-calls.js +0 -19
  56. package/session/context/turn/message/instruction-file.d.ts +9 -0
  57. package/session/context/turn/message/instruction-file.d.ts.map +1 -0
  58. package/session/context/turn/message/instruction-file.js +4 -0
  59. package/session/context/turn/message/message.d.ts +5 -4
  60. package/session/context/turn/message/message.d.ts.map +1 -1
  61. package/session/context/turn/message/message.js +7 -6
  62. package/session/context/turn/message/sender.d.ts +2 -1
  63. package/session/context/turn/message/sender.d.ts.map +1 -1
  64. package/session/context/turn/message/sender.js +4 -1
  65. package/session/context/turn/message/tool-call.d.ts +5 -0
  66. package/session/context/turn/message/tool-call.d.ts.map +1 -1
  67. package/session/context/turn/message/tool-result.d.ts +6 -1
  68. package/session/context/turn/message/tool-result.d.ts.map +1 -1
  69. package/session/context/turn/turn.d.ts +7 -0
  70. package/session/context/turn/turn.d.ts.map +1 -1
  71. package/session/conversation.d.ts +10 -3
  72. package/session/conversation.d.ts.map +1 -1
  73. package/session/conversation.js +14 -5
  74. package/session/goal/goal.d.ts +1 -1
  75. package/session/goal/goal.d.ts.map +1 -1
  76. package/session/goal/task.d.ts +2 -2
  77. package/session/goal/task.d.ts.map +1 -1
  78. package/session/session.d.ts +361 -26
  79. package/session/session.d.ts.map +1 -1
  80. package/session/session.js +40 -0
  81. package/src/jobs/permissions/decide-permission.ts +2 -1
  82. package/src/jobs/prompt.ts +3 -20
  83. package/src/jobs/slash-command.ts +2 -2
  84. package/src/jobs/status-line.ts +4 -7
  85. package/src/mod.ts +52 -147
  86. package/src/records.ts +1 -1
  87. package/src/register.ts +3 -1
  88. package/src/runtime/before.ts +90 -37
  89. package/src/runtime/claude.ts +5 -1
  90. package/src/runtime/conversations.ts +41 -25
  91. package/src/runtime/deadline.ts +38 -0
  92. package/src/runtime/dependencies.ts +12 -0
  93. package/src/runtime/grants.ts +11 -7
  94. package/src/runtime/hooks.ts +48 -116
  95. package/src/runtime/lifecycle.ts +65 -50
  96. package/src/runtime/sessions.ts +366 -90
  97. package/src/runtime/tool-calls.ts +0 -19
  98. package/src/session/context/turn/message/instruction-file.ts +13 -0
  99. package/src/session/context/turn/message/message.ts +11 -9
  100. package/src/session/context/turn/message/sender.ts +5 -2
  101. package/src/session/context/turn/message/tool-call.ts +3 -0
  102. package/src/session/context/turn/message/tool-result.ts +6 -1
  103. package/src/session/context/turn/turn.ts +4 -0
  104. package/src/session/conversation.ts +21 -8
  105. package/src/session/goal/goal.ts +1 -1
  106. package/src/session/goal/task.ts +2 -2
  107. package/src/session/session.ts +227 -24
  108. package/src/testing/claude-code.ts +23 -0
  109. package/src/testing/fake-claude.ts +5 -1
  110. package/src/testing/fake-sessions.ts +38 -24
  111. package/src/testing.ts +84 -16
  112. package/testing/claude-code.d.ts +12 -0
  113. package/testing/claude-code.d.ts.map +1 -0
  114. package/testing/claude-code.js +10 -0
  115. package/testing/fake-claude.d.ts +4 -0
  116. package/testing/fake-claude.d.ts.map +1 -1
  117. package/testing/fake-claude.js +4 -1
  118. package/testing/fake-sessions.d.ts +8 -6
  119. package/testing/fake-sessions.d.ts.map +1 -1
  120. package/testing/fake-sessions.js +35 -20
  121. package/testing.d.ts +38 -9
  122. package/testing.d.ts.map +1 -1
  123. package/testing.js +54 -5
  124. package/docs/hooks.md +0 -259
  125. package/session/context/turn/message/document.d.ts +0 -7
  126. package/session/context/turn/message/document.d.ts.map +0 -1
  127. package/session/context/turn/message/document.js +0 -1
  128. 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 { Document } from '../session/context/turn/message/document.js';
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 { 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,14 @@ 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 { TaskEnd, TaskStart } from '../session/goal/task.js';
13
+ import { Task, TaskStart } from '../session/goal/task.js';
14
14
  import { cmodPluginName } from './dependencies.js';
15
15
  import { toolInputOf } from './tool-calls.js';
16
- const appended = [Note, Reply, ToolResult, Notice];
16
+ const appended = [Note, Reply, Notice];
17
+ const withNote = (below, note) => {
18
+ const fields = (below ?? {});
19
+ return note === undefined ? fields : { ...fields, additionalContext: [...(fields['additionalContext'] ?? []), note] };
20
+ };
17
21
  const relayTag = /^(?:<cross-session-message[^>]*>\s*)?<cmod-relay>([\s\S]*)<\/cmod-relay>(?:\s*<\/cross-session-message>[\s\S]*)?$/;
18
22
  export function relayOf(e) {
19
23
  const isFromCmod = e.origin.kind === 'peer' && !('teammate' in e.origin) && e.origin.plugin === cmodPluginName;
@@ -26,34 +30,55 @@ export function installBefore({ claude, router, hooks }) {
26
30
  const message = (where, unplaced, task, isInTurn = true) => {
27
31
  const turn = isInTurn ? (task === undefined ? where.turn : where.taskTurns[task]) : undefined;
28
32
  const context = task === undefined ? where.context : (where.tasks[task]?.context ?? where.context);
29
- return { type: Message, message: { ...unplaced, session: where.session, context, ...(turn === undefined ? {} : { turn: turn.prompt.id }), ...(task === undefined ? {} : { task }) } };
33
+ const call = unplaced.type === ToolResult ? where.openCalls?.[unplaced.callId] : undefined;
34
+ return { type: Message, message: { ...unplaced, ...call, session: where.session, context, ...(turn === undefined ? {} : { turn: turn.prompt.id }), ...(task === undefined ? {} : { task }) } };
35
+ };
36
+ const titles = new Map();
37
+ const spawned = new Map();
38
+ const toolResultHook = (isFailure) => async (e, next) => {
39
+ if (!(await wants(ToolResult)))
40
+ return next(e);
41
+ const where = await place();
42
+ const name = String(e['tool_name']);
43
+ const callId = String(e['tool_use_id']);
44
+ const input = (typeof e['tool_input'] === 'object' && e['tool_input'] !== null ? e['tool_input'] : {});
45
+ const task = typeof e['agent_id'] === 'string' ? e['agent_id'] : undefined;
46
+ 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 };
47
+ const answer = await asked(ToolResult, message(where, result, task));
48
+ const below = await next(e);
49
+ const rewritten = answer.output === undefined || isFailure ? {} : name.startsWith('mcp__') ? { updatedMCPToolOutput: answer.output } : { updatedToolOutput: answer.output };
50
+ const failed = answer.isError === true && !isFailure ? { block: answer.note ?? `${name} failed.` } : {};
51
+ return { ...withNote(below, answer.isError === true ? undefined : answer.note), ...rewritten, ...failed };
30
52
  };
31
53
  const added = [
32
54
  router.add('prompt.submit', async (e, next) => {
33
- if (!(await wants(Prompt)) || e.text.startsWith('/'))
55
+ if (!(await wants(Prompt)))
34
56
  return next(e);
35
57
  const where = await place();
36
58
  const answer = await asked(Prompt, message(where, { id: '', at: now(), type: Prompt, text: e.text, from: senderOf(e.origin, false) }, undefined, false));
37
59
  if (answer.refuse !== undefined)
38
60
  return { drop: answer.refuse };
39
- return next(answer.text === undefined ? e : { ...e, text: answer.text });
61
+ const text = answer.text ?? e.text;
62
+ if (answer.title !== undefined)
63
+ titles.set(text, answer.title);
64
+ const context = answer.note === undefined ? e.context : [...(e.context ?? []), answer.note];
65
+ const ran = await next({ ...e, text, ...(context === undefined ? {} : { context }) });
66
+ const passed = titles.get(text);
67
+ if (passed !== undefined && ('drop' in ran || ran.text !== text)) {
68
+ titles.delete(text);
69
+ if (!('drop' in ran) && typeof ran.text === 'string')
70
+ titles.set(ran.text, passed);
71
+ }
72
+ return ran;
40
73
  }),
41
- router.add('command.run', async (e, next) => {
42
- if (!(await wants(Prompt)))
43
- return next(e);
44
- const typed = e.args === '' ? `/${e.command}` : `/${e.command} ${e.args}`;
45
- const where = await place();
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 {};
74
+ router.add('classic.UserPromptSubmit', async (e, next) => {
75
+ const named = titles.get(e.prompt);
76
+ titles.delete(e.prompt);
77
+ const below = await next(e);
78
+ return named === undefined ? below : { ...below, sessionTitle: named };
56
79
  }),
80
+ router.add('classic.PostToolUse', toolResultHook(false)),
81
+ router.add('classic.PostToolUseFailure', toolResultHook(true)),
57
82
  router.add('session.receive', async (e, next) => {
58
83
  if (!(await wants(Prompt)) || relayOf(e) !== undefined)
59
84
  return next(e);
@@ -71,11 +96,11 @@ export function installBefore({ claude, router, hooks }) {
71
96
  return answer.text === undefined ? next(e) : { text: answer.text };
72
97
  }),
73
98
  router.add('prompt.attachment', async (e, next) => {
74
- if (!(await wants(Document)) || e.type !== 'nested_memory')
99
+ if (!(await wants(InstructionFile)) || e.type !== 'nested_memory')
75
100
  return next(e);
76
101
  const where = await place();
77
102
  const path = /^Contents of (.+?) \(/.exec(e.text)?.[1] ?? '';
78
- const answer = await asked(Document, message(where, { id: '', at: now(), type: Document, path, text: e.text }, e.agentId));
103
+ const answer = await asked(InstructionFile, message(where, { id: '', at: now(), type: InstructionFile, path, text: e.text, isRule: isRulePath(path) }, e.agentId));
79
104
  if (answer.refuse !== undefined)
80
105
  return { text: null };
81
106
  return answer.text === undefined ? next(e) : { text: answer.text };
@@ -104,7 +129,7 @@ export function installBefore({ claude, router, hooks }) {
104
129
  return next(e);
105
130
  const where = await place();
106
131
  const input = toolInputOf(e);
107
- 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: await claude.session.cwd() }, e.agentId));
132
+ 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: await claude.session.cwd(), files: noFiles }, e.agentId));
108
133
  if (answer.refuse !== undefined)
109
134
  return { deny: answer.refuse };
110
135
  if (answer.result !== undefined)
@@ -115,27 +140,42 @@ export function installBefore({ claude, router, hooks }) {
115
140
  return next({ ...reserved, ...answer.input });
116
141
  }),
117
142
  router.add('agent.spawn', async (e, next) => {
143
+ spawned.set(e.tool_use_id, e.prompt);
118
144
  if (!(await wants(TaskStart)))
119
145
  return next(e);
120
146
  const where = await place();
121
147
  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
148
  const answer = await asked(TaskStart, { type: TaskStart, task: { ...task, context: where.context } });
123
- if (answer.refuse !== undefined)
149
+ if (answer.refuse !== undefined) {
150
+ spawned.delete(e.tool_use_id);
124
151
  return { deny: answer.refuse };
152
+ }
125
153
  return next(answer.owner === undefined ? e : { ...e, model: answer.owner.model });
126
154
  }),
155
+ router.add('classic.SubagentStart', async (e, next) => {
156
+ const where = await place();
157
+ const openedBy = where.tasks[e.agent_id]?.openedBy;
158
+ const prompt = openedBy === undefined ? undefined : spawned.get(openedBy);
159
+ if (openedBy !== undefined)
160
+ spawned.delete(openedBy);
161
+ if (!(await wants(Prompt)))
162
+ return next(e);
163
+ const open = where.taskTurns[e.agent_id]?.prompt;
164
+ const text = open?.text ?? prompt;
165
+ if (text === undefined)
166
+ return next(e);
167
+ const answer = await asked(Prompt, message(where, { id: open?.id ?? '', at: now(), type: Prompt, text, from: open?.from ?? { type: Task } }, e.agent_id, false));
168
+ return withNote(await next(e), answer.note);
169
+ }),
127
170
  router.add('classic.SubagentStop', async (e, next) => {
128
- if (!(await wants(TaskEnd)) && !(await wants(TurnEnd)))
171
+ if (!(await wants(TurnEnd)))
129
172
  return next(e);
130
- const where = await place();
131
- const task = where.tasks[e.agent_id];
132
- if (task === undefined)
173
+ const turn = (await place()).taskTurns[e.agent_id];
174
+ if (turn === undefined)
133
175
  return next(e);
134
- const turn = where.taskTurns[e.agent_id];
135
- const ending = (await wants(TaskEnd)) ? await asked(TaskEnd, { type: TaskEnd, task: { ...task, closedAt: now() } }) : {};
136
- const refuse = ending.refuse ?? ((await wants(TurnEnd)) && turn !== undefined ? (await asked(TurnEnd, { type: TurnEnd, turn: { ...turn, closedAt: now() } })).refuse : undefined);
176
+ const answer = await asked(TurnEnd, { type: TurnEnd, turn: { ...turn, closedAt: now() } });
137
177
  const below = await next(e);
138
- return refuse === undefined ? below : { ...below, block: refuse };
178
+ return answer.refuse === undefined ? below : { ...below, block: answer.refuse };
139
179
  }),
140
180
  router.add('classic.Stop', async (e, next) => {
141
181
  if (!(await wants(TurnEnd)))
@@ -162,6 +202,8 @@ export function installBefore({ claude, router, hooks }) {
162
202
  return { dispose: () => added.forEach((each) => each.dispose()) };
163
203
  }
164
204
  export function withAnswer(change, answer) {
205
+ if (change.type === Message && answer.output !== undefined && change.message.type === ToolResult)
206
+ return { ...change, message: { ...change.message, output: answer.output } };
165
207
  if (change.type === Message && answer.text !== undefined)
166
208
  return { ...change, message: { ...change.message, text: answer.text } };
167
209
  if (change.type === Message && answer.input !== undefined && change.message.type === ToolCall)
@@ -178,7 +220,8 @@ export async function foldAnswers(event, change, askers, report) {
178
220
  const answer = answerOf(event, await ask(latest));
179
221
  if (answer === undefined)
180
222
  continue;
181
- result = { ...result, ...answer };
223
+ const notes = [result?.note, answer.note].filter((note) => note !== undefined);
224
+ result = { ...result, ...answer, ...(notes.length === 0 ? {} : { note: notes.join('\n\n') }) };
182
225
  if (answer.refuse !== undefined || answer.result !== undefined)
183
226
  return result;
184
227
  latest = withAnswer(latest, answer);
@@ -194,16 +237,15 @@ export function answerOf(event, answer) {
194
237
  return undefined;
195
238
  const given = answer;
196
239
  const allowed = {
197
- prompt: ['text', 'refuse'],
240
+ prompt: ['text', 'note', 'title', 'refuse'],
198
241
  note: ['text'],
199
242
  skill: ['text'],
200
- document: ['text', 'refuse'],
243
+ instructionFile: ['text', 'refuse'],
201
244
  reply: ['text'],
202
245
  toolCall: ['input', 'result', 'refuse'],
203
- toolResult: ['text'],
246
+ toolResult: ['output', 'isError', 'note'],
204
247
  notice: ['text'],
205
248
  taskStart: ['owner', 'refuse'],
206
- taskEnd: ['refuse'],
207
249
  turnEnd: ['refuse'],
208
250
  contextEnd: ['refuse'],
209
251
  };
@@ -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<{
@@ -1 +1 @@
1
- {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,IAAI,EACJ,eAAe,EACf,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,OAAO,EACP,MAAM,EACN,aAAa,EACb,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,KAAK,EACL,QAAQ,EACR,UAAU,EACV,WAAW,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,YAAY,EACZ,cAAc,EACf,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACjE,QAAQ,CAAC,EAAE,EAAE;QACX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;QACtC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;QAC/C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;QACzD,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAA;QAC/C,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAChF,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;QAC/C,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzC,KAAK,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAA;QACnC,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;QACnD,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;QAC7C,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;QAChD,OAAO,CAAC,CAAC,EAAE,YAAY,GAAG,YAAY,CAAC,aAAa,CAAC,CAAA;KACtD,CAAA;IACD,QAAQ,CAAC,OAAO,EAAE;QAChB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAC9E,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAA;KACvF,CAAA;IACD,QAAQ,CAAC,EAAE,EAAE;QACX,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QACnC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAChD,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;QACvC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;KAC7D,CAAA;IACD,QAAQ,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;KAAE,CAAA;IAC7E,QAAQ,CAAC,QAAQ,EAAE;QAAE,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAA;IACvE,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;KAAE,CAAA;IACjD,QAAQ,CAAC,KAAK,EAAE;QACd,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAClC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;KAC1B,CAAA;IACD,QAAQ,CAAC,KAAK,EAAE;QACd,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;QACtB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,KAAK,CAAA;QACxC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,KAAK,CAAA;KACzC,CAAA;IACD,QAAQ,CAAC,OAAO,EAAE;QAChB,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;QACrB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;QACvB,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;QACtB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;QACxB,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,CAAA;QAC9B,QAAQ,IAAI,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAA;QAC7C,QAAQ,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAA;QAChD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAA;QAC5C,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAA;KACzC,CAAA;IACD,QAAQ,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAA;IAChE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAA;KAAE,CAAA;IAClE,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAA;IAClF,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;KAAE,CAAA;IAC7G,QAAQ,CAAC,KAAK,EAAE;QACd,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;QAC5B,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;KACvD,CAAA;IACD,QAAQ,CAAC,GAAG,EAAE;QACZ,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;QACnC,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;QACvC,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;KAC1C,CAAA;IACD,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAA;CACpE,CAAA"}
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,CAugBlR"}
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,CAuhBlR"}
@@ -11,7 +11,7 @@ import { formatExit, messageOf } from '../utils/text.js';
11
11
  import { foldAnswers, installBefore, relayOf } from './before.js';
12
12
  import { cmodPluginName } from './dependencies.js';
13
13
  import { readLines, runCmod } from './programs.js';
14
- import { actPermission, beforePermission, conversationMethods, everySession, isAct, isHeardBy, resultOf, usageOf } from './sessions.js';
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,6 +34,22 @@ 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 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)));
37
53
  const json = async (args) => JSON.parse(await runCmod(claude, [...args, '--json', '--project', project()], session === '' ? await claude.session.id() : session));
38
54
  const isGranted = async (caller, item) => {
39
55
  if (caller === cmodPluginName)
@@ -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();
@@ -156,17 +174,16 @@ export function serveConversations({ claude, router, store, project, report }) {
156
174
  watching = readWatchers().catch((error) => report('before', 'Kept the other sessions’ before listeners from before', error));
157
175
  };
158
176
  const place = () => {
159
- const { context, contextOpenedAt, turn, tasks, taskTurns } = conversation.state;
160
- return { session, context, contextOpenedAt, ...(turn === undefined ? {} : { turn }), tasks, taskTurns };
177
+ const { context, contextOpenedAt, turn, tasks, taskTurns, openCalls } = conversation.state;
178
+ return { session, context, contextOpenedAt, ...(turn === undefined ? {} : { turn }), tasks, taskTurns, ...(openCalls === undefined ? {} : { openCalls }) };
161
179
  };
162
180
  const deciders = (event) => {
163
181
  const all = [...[...ownWatches.values()].filter((watch) => watch.target === session || watch.target === everySession).map((watch) => ({ ...watch, from: session })), ...watchers];
164
182
  return [...new Map(all.filter((watcher) => watcher.events.includes(event)).map((watcher) => [`${watcher.from}\n${watcher.mod}`, watcher])).values()];
165
183
  };
166
184
  const askHere = async (mod, event, change, from = session, isInProject = true) => {
167
- for (const needed of ['conversation', beforePermission(event)])
168
- if (!(await isGranted(mod, needed)))
169
- throw new Error(`${mod} needs the ${needed} permission for before(${event}). Turn it on in /mods ${mod}.`);
185
+ if (from !== session && !(await isGranted(mod, 'conversation')))
186
+ throw new Error(`${mod} needs the conversation permission to change what happens in another session. Turn it on in /mods ${mod}.`);
170
187
  return claude.cmod.call({ to: mod, method: conversationMethods.before, input: { session: from, event, change, isInProject } });
171
188
  };
172
189
  const askAway = async (watcher, event, change) => {
@@ -325,11 +342,13 @@ export function serveConversations({ claude, router, store, project, report }) {
325
342
  const perform = async (caller, action, input, task) => {
326
343
  await checkAct(caller, action, input);
327
344
  await starting;
345
+ if (action === 'abort')
346
+ return abortTurn(input, task);
328
347
  if (task !== undefined)
329
348
  return performInTask(action, input, task);
330
349
  if (action === 'usage')
331
350
  return usageOf(claude);
332
- if (action === 'clients')
351
+ if (action === 'surfaces')
333
352
  return [...(await claude.session.surfaces())];
334
353
  if (action === 'send') {
335
354
  const { type, text, as } = input;
@@ -342,27 +361,27 @@ export function serveConversations({ claude, router, store, project, report }) {
342
361
  throw new Error(`Claude Code dropped the prompt: ${delivered.drop}`);
343
362
  return null;
344
363
  }
345
- if (action === 'startTask') {
346
- const args = input;
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
- }
364
+ if (action === 'startTask')
365
+ return spawnTask(claude, input);
358
366
  const { name, input: toolInput } = input;
359
- return resultOf(place(), await claude.tool.call({ ...toolInput, tool: name }));
367
+ return resultOf(place(), { name, input: toolInput, cwd: await claude.session.cwd() }, await claude.tool.call({ ...toolInput, tool: name }));
368
+ };
369
+ const abortTurn = async (input, task) => {
370
+ const turnId = engineTurns.get(task ?? '');
371
+ if (turnId === undefined)
372
+ throw new Error(`no turn is running in ${task === undefined ? `session ${session}` : `task ${task}`}.`);
373
+ const asked = isObject(input) ? input['turn'] : undefined;
374
+ const open = task === undefined ? conversation.state.turn : conversation.state.taskTurns[task];
375
+ if (open?.prompt.id !== asked)
376
+ throw new Error(`turn ${String(asked)} has ended, so there is nothing to abort.`);
377
+ await claude.turn.abort({ turnId });
378
+ return null;
360
379
  };
361
380
  const performInTask = async (action, input, task) => {
362
381
  const running = conversation.state.tasks[task];
363
382
  if (action === 'usage')
364
383
  return json(['history', 'usage', session, '--task', task]);
365
- if (action === 'clients')
384
+ if (action === 'surfaces')
366
385
  return running === undefined || running.closedAt !== undefined ? [] : [...(await claude.session.surfaces())];
367
386
  if (action !== 'send')
368
387
  throw new Error(`cmod: ${action} runs only on a session's own main loop.`);
@@ -378,7 +397,7 @@ export function serveConversations({ claude, router, store, project, report }) {
378
397
  const isLive = await isRunning(target);
379
398
  if (!isLive && action === 'usage')
380
399
  return json(['history', 'usage', target, ...(task === undefined ? [] : ['--task', task])]);
381
- if (!isLive && action === 'clients')
400
+ if (!isLive && action === 'surfaces')
382
401
  return [];
383
402
  if (!isLive)
384
403
  throw ended(task ?? target);
@@ -424,8 +443,8 @@ export function serveConversations({ claude, router, store, project, report }) {
424
443
  },
425
444
  async [conversationMethods.search](request) {
426
445
  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['isGoal'] === true ? ['--goal'] : [])];
428
- return json(['history', 'search', String(request['text']), ...scopeArgs(request), ...record, ...(request['running'] === true ? ['--running'] : []), ...countArg('--limit', request['limit']), ...(before === undefined ? [] : ['--before', `${String(before['session'])}:${String(before['id'])}`])]);
446
+ const record = [...textArg('--session', request['session']), ...textArg('--task', request['task']), ...textArg('--turn', request['turn']), ...countArg('--context', request['context']), ...(request['isAgent'] === true ? ['--agent'] : [])];
447
+ return json(['history', 'search', String(request['text']), ...scopeArgs(request), ...record, ...(request['running'] === true ? ['--running'] : []), ...(before === undefined ? [] : ['--before', `${String(before['session'])}:${String(before['id'])}`])]);
429
448
  },
430
449
  async [conversationMethods.messages](request) {
431
450
  const id = String(request['session']);
@@ -541,7 +560,7 @@ export function serveConversations({ claude, router, store, project, report }) {
541
560
  if (method === undefined)
542
561
  return undefined;
543
562
  const input = isObject(e.input) ? e.input : {};
544
- if (e.method !== conversationMethods.act && !(await isGranted(e.caller, 'conversation')))
563
+ if (e.method !== conversationMethods.act && input['session'] !== session && !(await isGranted(e.caller, 'conversation')))
545
564
  return { deny: `${e.caller ?? 'A mod'} reads your conversations without your grant. Turn it on in /mods ${e.caller ?? ''}.`.trim() };
546
565
  try {
547
566
  return { value: await method(input, e.caller) };
@@ -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"}
@@ -1,5 +1,39 @@
1
1
  export const longestMs = 600_000;
2
2
  export const toolDeadline = { ms: 30000, job: 'tool' };
3
+ export const listenerMs = 10_000;
4
+ export class PassedTimeout extends Error {
5
+ }
6
+ const timers = globalThis;
7
+ export function listenerOf(name, method, args) {
8
+ const hasMatcher = typeof args[1] === 'function';
9
+ const listener = (hasMatcher ? args[1] : args[0]);
10
+ const options = ((hasMatcher ? args[2] : args[1]) ?? {});
11
+ if (typeof listener !== 'function')
12
+ throw new Error(`${name}: ${method} takes a listener, or a matcher and then a listener.`);
13
+ const { timeoutMs, onFailure } = options;
14
+ if (timeoutMs !== undefined && (typeof timeoutMs !== 'number' || !Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > longestMs))
15
+ throw new Error(`${name}: ${method}'s timeoutMs is ${String(timeoutMs)}. Give a whole number of milliseconds above 0 and at most ${longestMs}.`);
16
+ if (onFailure !== undefined && onFailure !== 'pass' && onFailure !== 'refuse')
17
+ throw new Error(`${name}: ${method}'s onFailure is ${String(onFailure)}. Give 'pass' or 'refuse'.`);
18
+ return { matcher: hasMatcher ? args[0] : undefined, listener, options };
19
+ }
20
+ export async function withinTime(clock, method, { timeoutMs = listenerMs }, run) {
21
+ const controller = new AbortController();
22
+ const deadline = (await clock.now()) + timeoutMs;
23
+ let timer;
24
+ const passed = new Promise((_resolve, reject) => {
25
+ timer = timers.setTimeout(() => {
26
+ controller.abort();
27
+ reject(new PassedTimeout(`${method} passed its ${timeoutMs / 1000} s timeout`));
28
+ }, timeoutMs);
29
+ });
30
+ try {
31
+ return await Promise.race([Promise.resolve().then(() => run({ deadline, signal: controller.signal })), passed]);
32
+ }
33
+ finally {
34
+ timers.clearTimeout(timer);
35
+ }
36
+ }
3
37
  export function beforeDeadline(claude, { ms, job }, call, task) {
4
38
  return new Promise((resolve, reject) => {
5
39
  const passed = job === undefined ? `its ${ms / 1000} s deadline` : `the ${ms / 1000} s deadline of ${job}`;
@@ -1,10 +1,12 @@
1
1
  import type { Args, CmodDependencies, EventResult, Frozen } from 'claude-code';
2
2
  import type { Claude } from './claude.js';
3
+ import type { Router } from './router.js';
3
4
  export declare const cmodPluginName = "cmod";
4
5
  export declare function answerCall(name: string, api: {
5
6
  readonly [method: string]: (input: never) => unknown;
6
7
  }, e: Frozen<Args<'cmod.call'>>): Promise<EventResult<'cmod.call'>>;
7
8
  export declare function dependencyCalls(claude: Claude, within: (call: string, task: Promise<unknown>) => Promise<unknown>): CmodDependencies;
8
9
  export declare function withBareRefusals(claude: Claude): Claude;
10
+ export declare function answeringOwnCalls(claude: Claude, router: Router): Claude;
9
11
  export declare function notInstalled(name: string): string;
10
12
  //# sourceMappingURL=dependencies.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../src/runtime/dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,cAAc,SAAS,CAAA;AAEpC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;CAAE,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAQ7K;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,gBAAgB,CAOpI;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD"}
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../src/runtime/dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,cAAc,SAAS,CAAA;AAEpC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;CAAE,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAQ7K;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,gBAAgB,CAOpI;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CASxE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -23,6 +23,18 @@ export function withBareRefusals(claude) {
23
23
  });
24
24
  return { ...claude, cmod: { call } };
25
25
  }
26
+ export function answeringOwnCalls(claude, router) {
27
+ const name = claude.plugin.name;
28
+ const call = async (input) => {
29
+ if (input.to !== name)
30
+ return claude.cmod.call(input);
31
+ const answer = await router.dispatch('cmod.call', { ...input, caller: name }, async () => ({ deny: `${name} has no method ${input.method}.` }));
32
+ if (answer.deny !== undefined)
33
+ throw new Error(answer.deny);
34
+ return answer.value;
35
+ };
36
+ return { ...claude, cmod: { call } };
37
+ }
26
38
  export function notInstalled(name) {
27
39
  return `${name} is not installed. Add it with /plugin.`;
28
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/runtime/grants.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE,CAAA;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;CAClD,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAI/C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAIzD;AAkBD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAItG;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1F;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAElJ;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAkFrE;AAmBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAWvG;AAiBD,wBAAgB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9G;AA4BD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAa9G;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CA+BxJ"}
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/runtime/grants.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE,CAAA;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;CAClD,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAI/C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAIzD;AAkBD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAItG;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1F;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAElJ;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAwFrE;AAmBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAWvG;AAiBD,wBAAgB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9G;AA0BD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAa9G;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CA+BxJ"}
package/runtime/grants.js CHANGED
@@ -72,10 +72,6 @@ export function checkingGrants(claude, grants) {
72
72
  },
73
73
  session: {
74
74
  ...claude.session,
75
- messages: (async (...args) => {
76
- await gate('session.messages', 'conversation');
77
- return claude.session.messages(...args);
78
- }),
79
75
  append: async (args) => {
80
76
  await gate('send', 'prompt');
81
77
  return claude.session.append(args);
@@ -91,13 +87,24 @@ export function checkingGrants(claude, grants) {
91
87
  return claude.prompt.submit(args);
92
88
  },
93
89
  },
90
+ command: {
91
+ ...claude.command,
92
+ run: async (args) => {
93
+ await gate(`commands.run(${args.command})`, 'prompt');
94
+ return claude.command.run(args);
95
+ },
96
+ },
94
97
  cmod: {
95
98
  async call(args) {
96
99
  const named = args.to === cmodPluginName ? conversationCalls[args.method] : undefined;
97
100
  const given = args.method === conversationMethods.act && isObject(args.input) ? String(args.input['action']) : undefined;
98
101
  const action = given !== undefined && isAct(given) ? given : undefined;
99
- if (named !== undefined)
100
- await gate(action ?? named, action === undefined ? 'conversation' : actPermission(action, isObject(args.input) ? args.input['input'] : undefined));
102
+ const isThisSession = isObject(args.input) && args.input['session'] === (await claude.session.id());
103
+ const isDropping = (args.method === conversationMethods.subscribe || args.method === conversationMethods.watchBefore) && isObject(args.input) && Array.isArray(args.input['subscriptions']) && args.input['subscriptions'].length === 0;
104
+ if (named !== undefined && action !== undefined)
105
+ await gate(action, actPermission(action, isObject(args.input) ? args.input['input'] : undefined));
106
+ else if (named !== undefined && !isThisSession && !isDropping)
107
+ await gate(named, 'conversation');
101
108
  return claude.cmod.call(args);
102
109
  },
103
110
  },
@@ -191,10 +198,8 @@ function declaration(item, home) {
191
198
  const classicParts = {
192
199
  additionalContext: 'prompt',
193
200
  initialUserMessage: 'prompt',
194
- suppressOriginalPrompt: 'prompt',
195
201
  updatedToolOutput: 'prompt',
196
202
  updatedMCPToolOutput: 'prompt',
197
- updatedInput: 'tools',
198
203
  retry: 'approve',
199
204
  };
200
205
  const blocksKeepWorking = ['classic.Stop', 'classic.PostToolUse'];