@cmodjs/core 3.1.0 → 4.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 (200) hide show
  1. package/docs/commands.md +38 -21
  2. package/docs/dependencies.md +27 -20
  3. package/docs/index.md +21 -17
  4. package/docs/install-steps.md +37 -29
  5. package/docs/jobs.md +25 -52
  6. package/docs/mod.md +93 -65
  7. package/docs/options.md +2 -2
  8. package/docs/permissions.md +4 -4
  9. package/docs/session.md +14 -12
  10. package/docs/testing.md +55 -32
  11. package/docs/ui.md +255 -263
  12. package/hotkeys.d.ts +22 -0
  13. package/hotkeys.d.ts.map +1 -0
  14. package/hotkeys.js +26 -0
  15. package/installer.d.ts +1 -1
  16. package/installer.d.ts.map +1 -1
  17. package/installer.js +11 -6
  18. package/jobs/check.d.ts +2 -1
  19. package/jobs/check.d.ts.map +1 -1
  20. package/jobs/check.js +2 -2
  21. package/jobs/context.d.ts +2 -1
  22. package/jobs/context.d.ts.map +1 -1
  23. package/jobs/context.js +1 -1
  24. package/jobs/permissions.d.ts +2 -1
  25. package/jobs/permissions.d.ts.map +1 -1
  26. package/jobs/permissions.js +2 -2
  27. package/jobs/program.js +1 -1
  28. package/jobs/prompt.d.ts +2 -1
  29. package/jobs/prompt.d.ts.map +1 -1
  30. package/jobs/prompt.js +20 -13
  31. package/jobs/schedule.d.ts +2 -1
  32. package/jobs/schedule.d.ts.map +1 -1
  33. package/jobs/schedule.js +15 -1
  34. package/jobs/slash-command.d.ts +6 -2
  35. package/jobs/slash-command.d.ts.map +1 -1
  36. package/jobs/slash-command.js +6 -5
  37. package/jobs/tool.d.ts +6 -4
  38. package/jobs/tool.d.ts.map +1 -1
  39. package/jobs/tool.js +3 -3
  40. package/mod.d.ts +63 -42
  41. package/mod.d.ts.map +1 -1
  42. package/mod.js +11 -1
  43. package/package.json +1 -1
  44. package/records.d.ts +13 -8
  45. package/records.d.ts.map +1 -1
  46. package/records.js +41 -31
  47. package/register.d.ts.map +1 -1
  48. package/register.js +1 -2
  49. package/runtime/announce.d.ts +1 -1
  50. package/runtime/announce.d.ts.map +1 -1
  51. package/runtime/announce.js +6 -7
  52. package/runtime/before.d.ts +2 -2
  53. package/runtime/before.d.ts.map +1 -1
  54. package/runtime/before.js +1 -1
  55. package/runtime/claude.d.ts +0 -1
  56. package/runtime/claude.d.ts.map +1 -1
  57. package/runtime/conversations.d.ts +4 -1
  58. package/runtime/conversations.d.ts.map +1 -1
  59. package/runtime/conversations.js +42 -14
  60. package/runtime/dependencies.d.ts.map +1 -1
  61. package/runtime/dependencies.js +2 -1
  62. package/runtime/engine.d.ts +5 -0
  63. package/runtime/engine.d.ts.map +1 -1
  64. package/runtime/grants.js +2 -2
  65. package/runtime/hooks.d.ts +1 -1
  66. package/runtime/hooks.d.ts.map +1 -1
  67. package/runtime/hotkeys.d.ts +15 -0
  68. package/runtime/hotkeys.d.ts.map +1 -0
  69. package/runtime/hotkeys.js +58 -0
  70. package/runtime/installer.d.ts +5 -2
  71. package/runtime/installer.d.ts.map +1 -1
  72. package/runtime/installer.js +23 -12
  73. package/runtime/lifecycle.d.ts.map +1 -1
  74. package/runtime/lifecycle.js +190 -141
  75. package/runtime/options.js +2 -2
  76. package/runtime/pages.d.ts +28 -0
  77. package/runtime/pages.d.ts.map +1 -0
  78. package/runtime/pages.js +98 -0
  79. package/runtime/parts.d.ts +14 -0
  80. package/runtime/parts.d.ts.map +1 -0
  81. package/runtime/parts.js +63 -0
  82. package/runtime/permission-check.d.ts +2 -2
  83. package/runtime/permission-check.d.ts.map +1 -1
  84. package/runtime/programs.js +1 -1
  85. package/runtime/router.d.ts +2 -2
  86. package/runtime/router.d.ts.map +1 -1
  87. package/runtime/router.js +1 -1
  88. package/runtime/sessions.d.ts +10 -9
  89. package/runtime/sessions.d.ts.map +1 -1
  90. package/runtime/sessions.js +14 -5
  91. package/runtime/state.d.ts +2 -1
  92. package/runtime/state.d.ts.map +1 -1
  93. package/runtime/state.js +1 -0
  94. package/runtime/toaster.d.ts +1 -1
  95. package/runtime/toaster.d.ts.map +1 -1
  96. package/runtime/toaster.js +10 -4
  97. package/runtime/ui.d.ts +87 -5
  98. package/runtime/ui.d.ts.map +1 -1
  99. package/runtime/ui.js +372 -109
  100. package/runtime/watches.d.ts +9 -0
  101. package/runtime/watches.d.ts.map +1 -0
  102. package/runtime/watches.js +73 -0
  103. package/runtime/widgets.d.ts +48 -0
  104. package/runtime/widgets.d.ts.map +1 -0
  105. package/runtime/widgets.js +219 -0
  106. package/session/context/turn/message/message.d.ts.map +1 -1
  107. package/session/context/turn/message/message.js +7 -2
  108. package/session/session.d.ts +11 -5
  109. package/session/session.d.ts.map +1 -1
  110. package/src/hotkeys.ts +51 -0
  111. package/src/installer.ts +8 -4
  112. package/src/jobs/check.ts +4 -3
  113. package/src/jobs/context.ts +3 -2
  114. package/src/jobs/permissions.ts +4 -3
  115. package/src/jobs/program.ts +1 -1
  116. package/src/jobs/prompt.ts +23 -14
  117. package/src/jobs/schedule.ts +16 -2
  118. package/src/jobs/slash-command.ts +10 -7
  119. package/src/jobs/tool.ts +7 -5
  120. package/src/mod.ts +59 -47
  121. package/src/records.ts +46 -31
  122. package/src/register.ts +2 -3
  123. package/src/runtime/announce.ts +6 -7
  124. package/src/runtime/before.ts +4 -4
  125. package/src/runtime/claude.ts +0 -1
  126. package/src/runtime/conversations.ts +66 -20
  127. package/src/runtime/dependencies.ts +2 -1
  128. package/src/runtime/engine.ts +5 -0
  129. package/src/runtime/grants.ts +2 -2
  130. package/src/runtime/hooks.ts +1 -0
  131. package/src/runtime/hotkeys.ts +80 -0
  132. package/src/runtime/installer.ts +24 -12
  133. package/src/runtime/lifecycle.ts +189 -136
  134. package/src/runtime/options.ts +2 -2
  135. package/src/runtime/pages.ts +127 -0
  136. package/src/runtime/parts.ts +72 -0
  137. package/src/runtime/permission-check.ts +2 -2
  138. package/src/runtime/programs.ts +1 -1
  139. package/src/runtime/router.ts +3 -3
  140. package/src/runtime/sessions.ts +24 -15
  141. package/src/runtime/state.ts +3 -1
  142. package/src/runtime/toaster.ts +10 -4
  143. package/src/runtime/ui.ts +405 -115
  144. package/src/runtime/watches.ts +75 -0
  145. package/src/runtime/widgets.ts +287 -0
  146. package/src/session/context/turn/message/message.ts +7 -2
  147. package/src/session/session.ts +10 -6
  148. package/src/testing/fake-claude.ts +9 -6
  149. package/src/testing/fake-elements.ts +7 -4
  150. package/src/testing/fake-sessions.ts +6 -4
  151. package/src/testing.ts +203 -46
  152. package/src/ui/areas.ts +27 -0
  153. package/src/ui/elements.ts +35 -0
  154. package/src/ui/markdown.ts +18 -18
  155. package/src/ui/panes.ts +73 -0
  156. package/src/ui/styles.ts +53 -0
  157. package/src/utils/subscription.ts +1 -0
  158. package/testing/fake-claude.d.ts +0 -1
  159. package/testing/fake-claude.d.ts.map +1 -1
  160. package/testing/fake-claude.js +9 -5
  161. package/testing/fake-elements.js +7 -4
  162. package/testing/fake-sessions.d.ts +2 -1
  163. package/testing/fake-sessions.d.ts.map +1 -1
  164. package/testing/fake-sessions.js +1 -0
  165. package/testing.d.ts +21 -6
  166. package/testing.d.ts.map +1 -1
  167. package/testing.js +206 -45
  168. package/ui/areas.d.ts +29 -0
  169. package/ui/areas.d.ts.map +1 -0
  170. package/ui/areas.js +6 -0
  171. package/ui/elements.d.ts +3 -0
  172. package/ui/elements.d.ts.map +1 -1
  173. package/ui/elements.js +36 -0
  174. package/ui/markdown.d.ts +14 -14
  175. package/ui/markdown.d.ts.map +1 -1
  176. package/ui/markdown.js +11 -11
  177. package/ui/panes.d.ts +71 -0
  178. package/ui/panes.d.ts.map +1 -0
  179. package/ui/panes.js +16 -0
  180. package/ui/styles.d.ts +44 -0
  181. package/ui/styles.d.ts.map +1 -0
  182. package/ui/styles.js +24 -0
  183. package/utils/subscription.d.ts +4 -0
  184. package/utils/subscription.d.ts.map +1 -0
  185. package/jobs/status-line.d.ts +0 -6
  186. package/jobs/status-line.d.ts.map +0 -1
  187. package/jobs/status-line.js +0 -39
  188. package/src/jobs/status-line.ts +0 -44
  189. package/src/ui/define-pane.ts +0 -27
  190. package/src/ui/places.ts +0 -49
  191. package/src/utils/disposable.ts +0 -3
  192. package/ui/define-pane.d.ts +0 -15
  193. package/ui/define-pane.d.ts.map +0 -1
  194. package/ui/define-pane.js +0 -12
  195. package/ui/places.d.ts +0 -43
  196. package/ui/places.d.ts.map +0 -1
  197. package/ui/places.js +0 -31
  198. package/utils/disposable.d.ts +0 -4
  199. package/utils/disposable.d.ts.map +0 -1
  200. /package/utils/{disposable.js → subscription.js} +0 -0
package/runtime/before.js CHANGED
@@ -215,7 +215,7 @@ export function installBefore({ claude, router, hooks }) {
215
215
  return answer.refuse === undefined ? next(e) : { skip: answer.refuse };
216
216
  }),
217
217
  ];
218
- return { dispose: () => added.forEach((each) => each.dispose()) };
218
+ return { remove: () => added.forEach((each) => each.remove()) };
219
219
  }
220
220
  export function closingContext(where, task, closedAt) {
221
221
  return task === undefined ? { number: where.context, openedAt: where.contextOpenedAt, closedAt } : { number: task.context, openedAt: task.contextOpenedAt ?? task.openedAt, closedAt, task: task.id };
@@ -5,7 +5,6 @@ export type Claude = {
5
5
  readonly root: string;
6
6
  };
7
7
  readonly ui: {
8
- status(text: string | undefined): void;
9
8
  log(text: string, options?: UiLogOptions): void;
10
9
  notice(toolUseId: string, text: string | undefined): void;
11
10
  invalidate(event: InvalidatableEventName): void;
@@ -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,4 +1,5 @@
1
1
  import type { Args, EventResult, Frozen } from 'claude-code';
2
+ import { type TurnData } from '../session/conversation.js';
2
3
  import type { Claude } from './claude.js';
3
4
  import type { Router } from './router.js';
4
5
  export type Conversations = {
@@ -6,12 +7,14 @@ export type Conversations = {
6
7
  readonly caller?: string;
7
8
  }): Promise<EventResult<'cmod.call'> | undefined>;
8
9
  moved(): void;
10
+ turnClosedBy(rowId: string): TurnData | undefined;
9
11
  };
10
- export declare function serveConversations({ claude, router, store, project, report }: {
12
+ export declare function serveConversations({ claude, router, store, project, report, clear, }: {
11
13
  readonly claude: Claude;
12
14
  readonly router: Router;
13
15
  readonly store: string;
14
16
  readonly project: () => string;
15
17
  readonly report: (id: string, message: string, error: unknown) => void;
18
+ readonly clear: (id: string) => void;
16
19
  }): Conversations;
17
20
  //# sourceMappingURL=conversations.d.ts.map
@@ -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,EAAc,MAAM,EAAE,MAAM,aAAa,CAAA;AA8BrD,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,CAqkBlR"}
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;AAK5D,OAAO,EAA2J,KAAK,QAAQ,EAAmB,MAAM,4BAA4B,CAAA;AAQpO,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,KAAK,EAAc,MAAM,EAAE,MAAM,aAAa,CAAA;AAkCrD,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;IACb,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;CAClD,CAAA;AAMD,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,MAAM,EACN,KAAK,GACN,EAAE;IACD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACtE,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CACrC,GAAG,aAAa,CA2lBhB"}
@@ -1,10 +1,11 @@
1
- import { consentPath, dataFolder, isObject, parseConsent } from '../records.js';
1
+ import { consentPath, coreVersion, dataFolder, grantFix, isObject, parseConsent } from '../records.js';
2
2
  import { Message, rowOfAppend } from '../session/context/turn/message/message.js';
3
3
  import { modNote, Note } from '../session/context/turn/message/note.js';
4
4
  import { Person } from '../session/context/turn/message/sender.js';
5
5
  import { createConversation, emptyConversation } from '../session/conversation.js';
6
6
  import { Session, UsageChange } from '../session/session.js';
7
7
  import { GoalChange } from '../session/goal/goal.js';
8
+ import { TurnEnd, TurnStart } from '../session/context/turn/turn.js';
8
9
  import { receivedMatcher } from '../utils/matcher.js';
9
10
  import { ifMissing } from '../utils/paths.js';
10
11
  import { formatExit, messageOf } from '../utils/text.js';
@@ -13,11 +14,15 @@ import { cmodPluginName } from './dependencies.js';
13
14
  import { readLines, runCmod } from './programs.js';
14
15
  import { PassedTimeout } from './deadline.js';
15
16
  import { actPermission, conversationMethods, everySession, isAct, isHeardBy, isInScope, resultOf, spawnTask, usageOf } from './sessions.js';
17
+ const relayKinds = new Set(['act', 'before', 'answer', 'watch', 'goal']);
18
+ const isRelay = (value) => isObject(value) && relayKinds.has(value['kind']);
16
19
  const bufferedTaskRows = 200;
17
20
  const beforeDeadlineMs = 5000;
18
21
  const awayFoldMs = 8000;
19
22
  const livenessMs = 5000;
20
- export function serveConversations({ claude, router, store, project, report }) {
23
+ const keptClosings = 200;
24
+ const keptMessages = 200;
25
+ export function serveConversations({ claude, router, store, project, report, clear, }) {
21
26
  const folder = dataFolder(store, cmodPluginName);
22
27
  const goals = `${folder}/goals`;
23
28
  const watches = `${folder}/before`;
@@ -64,17 +69,23 @@ export function serveConversations({ claude, router, store, project, report }) {
64
69
  };
65
70
  const ended = (id) => new Error(`session ${id} has ended`);
66
71
  const isRunning = async (id) => (await json(['history', 'sessions', '--running', '--all'])).some((each) => each.id === id);
72
+ let lastTurn;
73
+ const closings = new Map();
67
74
  const dispatch = (to, changes, isInProject = true) => {
68
75
  for (const change of changes) {
76
+ if (to === session && (change.type === TurnStart || change.type === TurnEnd) && change.turn.prompt.task === undefined)
77
+ lastTurn = change.turn;
69
78
  if (change.type === Message && !liveIds.has(change.message.id) && to === session) {
70
79
  live.push(change.message);
71
80
  liveIds.add(change.message.id);
81
+ if (live.length > keptMessages)
82
+ liveIds.delete(live.shift()?.id ?? '');
72
83
  }
73
84
  for (const [mod, sessions] of heard) {
74
85
  const subscriptions = [...(sessions.get(to) ?? []), ...(isInProject ? (sessions.get(everySession) ?? []) : [])];
75
86
  if (!subscriptions.some(({ event, matcher }) => isHeardBy(event, matcher, change)))
76
87
  continue;
77
- void claude.cmod.call({ to: mod, method: conversationMethods.changed, input: { session: to, change, isInProject } }).catch((error) => report(`changed:${mod}`, `Could not tell ${mod} about session ${to}`, error));
88
+ void claude.cmod.call({ to: mod, method: conversationMethods.changed, input: { session: to, change, isInProject } }).then(() => clear(`changed:${mod}`), (error) => report(`changed:${mod}`, `Could not tell ${mod} about session ${to}`, error));
78
89
  }
79
90
  }
80
91
  };
@@ -209,7 +220,7 @@ export function serveConversations({ claude, router, store, project, report }) {
209
220
  };
210
221
  const askHere = async (mod, event, change, from = session, isInProject = true) => {
211
222
  if (from !== session && !(await isGranted(mod, 'conversation')))
212
- throw new Error(`${mod} needs the conversation permission to change what happens in another session. Turn it on in /mods ${mod}.`);
223
+ throw new Error(`${mod} needs the conversation permission to change what happens in another session. ${grantFix}`);
213
224
  return claude.cmod.call({ to: mod, method: conversationMethods.before, input: { session: from, event, change, isInProject } });
214
225
  };
215
226
  const isUnderHere = (task, ancestor) => {
@@ -298,6 +309,11 @@ export function serveConversations({ claude, router, store, project, report }) {
298
309
  return;
299
310
  }
300
311
  dispatch(session, conversation.add(row, task));
312
+ if (task !== undefined || row.type !== 'system' || row.name !== 'turn_duration' || lastTurn === undefined)
313
+ return;
314
+ closings.set(row.id, lastTurn);
315
+ if (closings.size > keptClosings)
316
+ closings.delete(closings.keys().next().value);
301
317
  };
302
318
  router.add('classic.SessionStart', async (e, next) => {
303
319
  start(e.session_id, e.source);
@@ -353,9 +369,15 @@ export function serveConversations({ claude, router, store, project, report }) {
353
369
  if (sent === undefined)
354
370
  return next(e);
355
371
  const relay = JSON.parse(sent);
356
- claude.clock.after(0, () => void received(relay).catch((error) => report('relay', 'Could not answer another session', error)));
372
+ claude.clock.after(0, () => void (isRelay(relay) ? received(relay) : refuse(relay)).catch((error) => report('relay', 'Could not answer another session', error)));
357
373
  return { consumed: 'cmod relay' };
358
374
  });
375
+ const unknownTo = async (what) => new Error(`Session ${await claude.session.id()} runs cmod ${coreVersion}, which has no ${what}.`);
376
+ const refuse = async (relay) => {
377
+ if (!isObject(relay) || typeof relay['id'] !== 'string' || typeof relay['from'] !== 'string')
378
+ return;
379
+ await post(relay['from'], { kind: 'answer', id: relay['id'], deny: (await unknownTo(`"${String(relay['kind'])}" relay`)).message });
380
+ };
359
381
  const received = async (relay) => {
360
382
  if (relay.kind === 'answer') {
361
383
  const waiting = asked.get(relay.id);
@@ -381,13 +403,13 @@ export function serveConversations({ claude, router, store, project, report }) {
381
403
  }
382
404
  };
383
405
  if (relay.kind === 'act')
384
- return answered(() => perform(relay.caller, relay.action, relay.input, relay.task));
406
+ return answered(async () => (isAct(relay.action) ? perform(relay.caller, relay.action, relay.input, relay.task) : Promise.reject(await unknownTo(`"${String(relay.action)}" action`))));
385
407
  return answered(() => askHere(relay.mod, relay.event, relay.change, relay.from, relay.project === project()));
386
408
  };
387
409
  const checkAct = async (caller, action, input) => {
388
410
  const needed = actPermission(action, input);
389
411
  if (needed !== undefined && !(await isGranted(caller, needed)))
390
- throw new Error(`${caller} needs the ${needed} permission for ${action}. Turn it on in /mods ${caller}.`);
412
+ throw new Error(`${caller} needs the ${needed} permission for ${action}. ${grantFix}`);
391
413
  };
392
414
  const perform = async (caller, action, input, task) => {
393
415
  await checkAct(caller, action, input);
@@ -487,6 +509,7 @@ export function serveConversations({ claude, router, store, project, report }) {
487
509
  return context === 0 ? [] : [{ number: context, openedAt: contextOpenedAt }];
488
510
  };
489
511
  const lastOf = (items, last) => (typeof last === 'number' ? items.slice(-last) : [...items]);
512
+ const isHeld = (kept, last) => typeof last === 'number' && kept.length >= last;
490
513
  const methods = {
491
514
  async [conversationMethods.sessions](request) {
492
515
  const found = await json(['history', 'sessions', ...scopeArgs(request), ...(request['running'] === true ? ['--running'] : [])]);
@@ -500,23 +523,27 @@ export function serveConversations({ claude, router, store, project, report }) {
500
523
  async [conversationMethods.messages](request) {
501
524
  const id = String(request['session']);
502
525
  const filters = [...textArg('--turn', request['turn']), ...textArg('--task', request['task']), ...textArg('--after', request['after'])];
503
- const saved = await json(['history', 'messages', id, ...filters, ...countArg('--last', request['last'])]);
526
+ const saved = () => json(['history', 'messages', id, ...filters, ...countArg('--last', request['last'])]);
504
527
  if (id !== session)
505
- return saved;
528
+ return saved();
506
529
  await starting;
507
530
  const fits = (message) => (request['turn'] === undefined || message.turn === request['turn']) && message.task === request['task'];
508
531
  const after = typeof request['after'] === 'string' ? live.findIndex((message) => message.id === request['after']) : -1;
509
532
  const kept = live.slice(after + 1).filter(fits);
510
- return lastOf(merged(saved, kept, (message) => message.id), request['last']);
533
+ if (after >= 0 || isHeld(kept, request['last']))
534
+ return lastOf(kept, request['last']);
535
+ return lastOf(merged(await saved(), kept, (message) => message.id), request['last']);
511
536
  },
512
537
  async [conversationMethods.turns](request) {
513
538
  const id = String(request['session']);
514
- const saved = await json(['history', 'turns', id, ...textArg('--task', request['task']), ...countArg('--context', request['context']), ...countArg('--last', request['last'])]);
539
+ const saved = () => json(['history', 'turns', id, ...textArg('--task', request['task']), ...countArg('--context', request['context']), ...countArg('--last', request['last'])]);
515
540
  if (id !== session)
516
- return saved;
541
+ return saved();
517
542
  await starting;
518
543
  const kept = liveTurns(request['task']).filter((turn) => request['context'] === undefined || turn.context === request['context']);
519
- return lastOf(merged(saved, kept, (turn) => turn.prompt.id), request['last']);
544
+ if (isHeld(kept, request['last']))
545
+ return lastOf(kept, request['last']);
546
+ return lastOf(merged(await saved(), kept, (turn) => turn.prompt.id), request['last']);
520
547
  },
521
548
  async [conversationMethods.contexts](request) {
522
549
  const id = String(request['session']);
@@ -599,6 +626,7 @@ export function serveConversations({ claude, router, store, project, report }) {
599
626
  },
600
627
  };
601
628
  return {
629
+ turnClosedBy: (rowId) => closings.get(rowId),
602
630
  moved() {
603
631
  for (const [key, watch] of ownWatches)
604
632
  ownWatches.set(key, { ...watch, project: project() });
@@ -613,7 +641,7 @@ export function serveConversations({ claude, router, store, project, report }) {
613
641
  const input = isObject(e.input) ? e.input : {};
614
642
  const isDropping = (e.method === conversationMethods.subscribe || e.method === conversationMethods.watchBefore) && Array.isArray(input['subscriptions']) && input['subscriptions'].length === 0;
615
643
  if (e.method !== conversationMethods.act && !isDropping && input['session'] !== (await claude.session.id()) && !(await isGranted(e.caller, 'conversation')))
616
- return { deny: `${e.caller ?? 'A mod'} reads your conversations without your grant. Turn it on in /mods ${e.caller ?? ''}.`.trim() };
644
+ return { deny: `${e.caller ?? 'A mod'} reads your conversations without your grant. ${grantFix}` };
617
645
  try {
618
646
  return { value: await method(input, e.caller) };
619
647
  }
@@ -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;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"}
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;AAG9E,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"}
@@ -1,3 +1,4 @@
1
+ import { installFix } from '../records.js';
1
2
  import { messageOf } from '../utils/text.js';
2
3
  export const cmodPluginName = 'cmod';
3
4
  export async function answerCall(name, api, e) {
@@ -36,5 +37,5 @@ export function answeringOwnCalls(claude, router) {
36
37
  return { ...claude, cmod: { call } };
37
38
  }
38
39
  export function notInstalled(name) {
39
- return `${name} is not installed. Add it with /plugin.`;
40
+ return `${name} is not installed. ${installFix}`;
40
41
  }
@@ -1,13 +1,18 @@
1
1
  import type { Claude } from './claude.js';
2
+ import type { Pages } from './pages.js';
2
3
  import type { Router } from './router.js';
3
4
  import type { Failure } from './toaster.js';
4
5
  import type { ToolCalls } from './tool-calls.js';
6
+ import type { Widgets } from './widgets.js';
5
7
  export type Engine = {
6
8
  readonly claude: Claude;
7
9
  readonly router: Router;
8
10
  readonly toolCalls: ToolCalls;
9
11
  readonly report: (failure: Failure) => void;
10
12
  readonly hasPermissionCheck: () => boolean;
13
+ readonly answerInput: <Answer>(run: () => Promise<Answer>, passOn: () => Promise<unknown>) => Promise<Answer>;
14
+ readonly widgets?: Widgets;
15
+ readonly pages?: Pages;
11
16
  };
12
17
  export declare function keepEngine(mod: object, engine: Engine): void;
13
18
  export declare function engineOf(mod: object): Engine;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/runtime/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,OAAO,CAAA;CAC3C,CAAA;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI5C"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/runtime/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,OAAO,CAAA;IAC1C,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7G,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CACvB,CAAA;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI5C"}
package/runtime/grants.js CHANGED
@@ -1,4 +1,4 @@
1
- import { isObject, isSettingCovered, permissionWords, settingPaths } from '../records.js';
1
+ import { grantFix, isObject, isSettingCovered, permissionWords, settingPaths } from '../records.js';
2
2
  import { relativePath } from '../utils/paths.js';
3
3
  import { cmodPluginName } from './dependencies.js';
4
4
  import { actPermission, conversationMethods, isAct, toolPermission } from './sessions.js';
@@ -182,7 +182,7 @@ function writeItem(grants, path) {
182
182
  export function refusal(grants, call, item) {
183
183
  const { name } = grants;
184
184
  if (isCovered(new Set(grants.declared), item, grants.home))
185
- return `${name} calls ${call} without your grant to "${permissionWords(item)}". Turn it on in /mods ${name}.`;
185
+ return `${name} calls ${call} without your grant to "${permissionWords(item)}". ${grantFix}`;
186
186
  return `${name} calls ${call}, which needs ${declaration(item, grants.home)} in package.json "cmod".`;
187
187
  }
188
188
  function declaration(item, home) {
@@ -6,7 +6,7 @@ import { type CallBase } from '../utils/call-effects.js';
6
6
  export type Hook = Exclude<ClassicHookEvent, 'PreToolUse'>;
7
7
  export type HookFields = Readonly<Record<string, unknown>>;
8
8
  export type HookListener<H extends Hook> = (input: ClassicHookInputs[H]) => HookFields | undefined | Promise<HookFields | undefined>;
9
- export type RoutedEvent = `classic.${Hook}` | 'tool.check' | 'tool.call' | 'prompt.submit' | 'prompt.context' | 'prompt.attachment' | 'command.run' | 'session.measure' | 'skill.prompt' | 'ui.render' | 'ui.press' | 'ui.scroll' | 'ui.close' | 'cmod.call' | 'session.append' | 'session.compact' | 'session.receive' | 'agent.spawn' | 'turn.start';
9
+ export type RoutedEvent = `classic.${Hook}` | 'tool.check' | 'tool.call' | 'prompt.submit' | 'prompt.context' | 'prompt.attachment' | 'command.run' | 'command.describe' | 'session.measure' | 'skill.prompt' | 'ui.render' | 'ui.press' | 'ui.scroll' | 'ui.close' | 'cmod.call' | 'session.append' | 'session.compact' | 'session.receive' | 'agent.spawn' | 'turn.start';
10
10
  type CallFiles = {
11
11
  readonly read: string[];
12
12
  readonly changed: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/runtime/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAe,KAAK,QAAQ,EAAmB,MAAM,0BAA0B,CAAA;AAKtF,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAA;AAE1D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAE1D,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;AAEpI,MAAM,MAAM,WAAW,GACnB,WAAW,IAAI,EAAE,GACjB,YAAY,GACZ,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,mBAAmB,GACnB,aAAa,GACb,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,aAAa,GACb,YAAY,CAAA;AAEhB,KAAK,SAAS,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAExE,wBAAgB,WAAW,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAYxI;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,GAAG,aAAa,CAAC,WAAW,CAAC,CAM1L;AAMD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAexE;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAExG,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAgB3I"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/runtime/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAe,KAAK,QAAQ,EAAmB,MAAM,0BAA0B,CAAA;AAKtF,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAA;AAE1D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAE1D,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;AAEpI,MAAM,MAAM,WAAW,GACnB,WAAW,IAAI,EAAE,GACjB,YAAY,GACZ,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,mBAAmB,GACnB,aAAa,GACb,kBAAkB,GAClB,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,aAAa,GACb,YAAY,CAAA;AAEhB,KAAK,SAAS,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAExE,wBAAgB,WAAW,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAYxI;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,GAAG,aAAa,CAAC,WAAW,CAAC,CAM1L;AAMD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAexE;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAExG,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAgB3I"}
@@ -0,0 +1,15 @@
1
+ import type { Hotkey, Hotkeys } from '../hotkeys.js';
2
+ import type { Claude } from './claude.js';
3
+ import type { Router } from './router.js';
4
+ import type { Failure } from './toaster.js';
5
+ export declare function readCombos(claude: Claude, configRoot: string | undefined): Promise<Map<string, string>>;
6
+ export declare function createHotkeys({ name, declared, configRoot, claude, router, answerInput, report, }: {
7
+ readonly name: string;
8
+ readonly declared: Hotkeys;
9
+ readonly configRoot: string | undefined;
10
+ readonly claude: Claude;
11
+ readonly router: Router;
12
+ readonly answerInput: <Answer>(run: () => Promise<Answer>, passOn: () => Promise<unknown>) => Promise<Answer>;
13
+ readonly report: (failure: Failure) => void;
14
+ }): Promise<Readonly<Record<string, Hotkey>>>;
15
+ //# sourceMappingURL=hotkeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotkeys.d.ts","sourceRoot":"","sources":["../src/runtime/hotkeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAIpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAS7G;AAED,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,MAAM,EACN,MAAM,EACN,WAAW,EACX,MAAM,GACP,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7G,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CA4C5C"}
@@ -0,0 +1,58 @@
1
+ import { boundCombos, hotkeyCommand } from '../records.js';
2
+ import { ifMissing } from '../utils/paths.js';
3
+ import { messageOf } from '../utils/text.js';
4
+ export async function readCombos(claude, configRoot) {
5
+ if (configRoot === undefined)
6
+ return new Map();
7
+ const text = await claude.fs.read(`${configRoot}/keybindings.json`).catch(ifMissing('{}'));
8
+ try {
9
+ return boundCombos(JSON.parse(text));
10
+ }
11
+ catch (error) {
12
+ claude.ui.log(`${configRoot}/keybindings.json is not JSON, so cmod reads no combos from it: ${messageOf(error)}`, { to: 'debug' });
13
+ return new Map();
14
+ }
15
+ }
16
+ export async function createHotkeys({ name, declared, configRoot, claude, router, answerInput, report, }) {
17
+ const entries = Object.entries(declared);
18
+ if (entries.length === 0)
19
+ return {};
20
+ const combos = await readCombos(claude, configRoot);
21
+ const listeners = new Map();
22
+ const commands = new Map();
23
+ for (const [hotkey, { title }] of entries) {
24
+ listeners.set(hotkey, new Set());
25
+ claude.command.register({ name: hotkeyCommand(name, hotkey), description: title, immediate: true }).then(({ command }) => void commands.set(command, hotkey), (error) => report({ id: `hotkey:${hotkey}`, message: `The ${title} hotkey is not added`, error }));
26
+ }
27
+ router.add('command.describe', async (e, next) => {
28
+ const described = await next(e);
29
+ return commands.has(e.command) ? { ...described, isHidden: true } : described;
30
+ });
31
+ router.add('command.run', async (e, next) => {
32
+ const hotkey = commands.get(e.command);
33
+ if (hotkey === undefined)
34
+ return next(e);
35
+ return answerInput(async () => {
36
+ for (const listener of listeners.get(hotkey) ?? []) {
37
+ try {
38
+ await listener();
39
+ }
40
+ catch (error) {
41
+ report({ id: `hotkey:${hotkey}`, message: `The ${declared[hotkey]?.title ?? hotkey} hotkey failed`, error });
42
+ }
43
+ }
44
+ return {};
45
+ }, () => next(e));
46
+ });
47
+ return Object.fromEntries(entries.map(([hotkey, { title }]) => [
48
+ hotkey,
49
+ {
50
+ title,
51
+ combo: combos.get(hotkeyCommand(name, hotkey)),
52
+ onPress(listener) {
53
+ listeners.get(hotkey)?.add(listener);
54
+ return { remove: () => void listeners.get(hotkey)?.delete(listener) };
55
+ },
56
+ },
57
+ ]));
58
+ }
@@ -7,7 +7,7 @@ export declare const installerPaneOf: (name: string) => string;
7
7
  export type Consent = {
8
8
  readonly install: string;
9
9
  readonly uninstall: string;
10
- readonly keys: string;
10
+ readonly hotkeys: string;
11
11
  readonly permissions: readonly string[];
12
12
  readonly updates?: string | undefined;
13
13
  };
@@ -20,5 +20,8 @@ export type Installer = {
20
20
  step<State extends object>(mod: Mod<State>, step: Step<State>, index: number, total: number): Promise<boolean>;
21
21
  close(): Promise<void>;
22
22
  };
23
- export declare function createInstaller(name: string, claude: () => Claude): Installer;
23
+ export declare function createInstaller(name: string, claude: () => Claude, waiting: {
24
+ show(open: () => Promise<void>): void;
25
+ hide(): void;
26
+ }): Installer;
24
27
  //# sourceMappingURL=installer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAI3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,MAA0E,CAAA;AAEzH,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA;AAOD,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAA;IAC5C,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,aAAa,CAAA;IACjD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7I,IAAI,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9G,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,CAwI7E"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAI3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,MAA0E,CAAA;AAEzH,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA;AAOD,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAA;IAC5C,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,aAAa,CAAA;IACjD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7I,IAAI,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9G,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,OAAO,EAAE;IAAE,IAAI,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,GAAG,SAAS,CAoJ/I"}
@@ -1,26 +1,33 @@
1
- import { permissionWords } from '../records.js';
1
+ import { permissionWords, secretFix } from '../records.js';
2
2
  import { Box, Button, drawWith, Input, Text } from '../ui/elements.js';
3
3
  import { messageOf } from '../utils/text.js';
4
4
  export const installerPaneOf = (name) => `installer-${name.replace(/[^A-Za-z0-9_-]/g, '_')}`.slice(0, 64);
5
- export function createInstaller(name, claude) {
5
+ export function createInstaller(name, claude, waiting) {
6
6
  const paneId = installerPaneOf(name);
7
7
  let page;
8
8
  let isOpen = false;
9
+ const open = async () => {
10
+ isOpen = true;
11
+ await claude().ui.open({ id: paneId, title: `Install ${name}`, focus: true, holdToasts: true, closeOnEscape: true });
12
+ };
9
13
  const show = async (build, cancelled) => {
10
14
  page?.cancel();
11
15
  const answer = new Promise((resolve) => {
12
16
  const done = (value) => {
13
17
  if (page === shown)
14
18
  page = undefined;
19
+ waiting.hide();
15
20
  resolve(value);
16
21
  };
17
22
  const shown = { ...build(done), cancel: () => done(cancelled) };
18
23
  page = shown;
19
24
  });
20
- if (!isOpen) {
21
- isOpen = true;
22
- await claude().ui.open({ id: paneId, title: `Install ${name}`, focus: true, holdToasts: true, closeOnEscape: true });
23
- }
25
+ waiting.show(open);
26
+ if (!isOpen)
27
+ await open().catch((error) => {
28
+ waiting.hide();
29
+ throw error;
30
+ });
24
31
  claude().ui.invalidate('ui.render');
25
32
  return answer;
26
33
  };
@@ -37,18 +44,18 @@ export function createInstaller(name, claude) {
37
44
  isOpen = false;
38
45
  page?.cancel();
39
46
  },
40
- consent({ install, uninstall, keys, permissions, updates }) {
47
+ consent({ install, uninstall, hotkeys, permissions, updates }) {
41
48
  const changes = [
42
49
  ...(install === '' ? [] : [`Run ${install} now${uninstall === '' ? '' : `, and ${uninstall} when you remove it`}`]),
43
50
  ...(install === '' && uninstall !== '' ? [`Run ${uninstall} when you remove it`] : []),
44
- ...(keys === '' ? [] : [`Bind ${keys}`]),
51
+ ...(hotkeys === '' ? [] : [`Bind ${hotkeys}`]),
45
52
  ...(updates === undefined ? [] : [`Update ${name} automatically from the ${updates} marketplace`]),
46
53
  ];
47
54
  return show((answer) => ({
48
55
  draw: () => frame(`${name} wants to:`, [
49
56
  ...(permissions.length === 0 ? [] : [Box({ flexDirection: 'column', children: permissions.map((item) => bullet(permissionWords(item))) })]),
50
57
  ...(changes.length === 0 ? [] : [Text({ children: permissions.length === 0 ? 'Change your computer:' : 'and change your computer:' }), Box({ flexDirection: 'column', children: changes.map(bullet) })]),
51
- Text({ dimColor: true, children: 'You can turn each permission off later in /mods.' }),
58
+ Text({ dimColor: true, children: 'You can turn each permission off later in Settings.' }),
52
59
  ], [Button({ key: 'not-now', hotkey: 'n', label: 'Not now', onPress: () => answer(false) }), Button({ key: 'accept', hotkey: 'a', label: 'Accept', onPress: () => answer(true) })]),
53
60
  }), false);
54
61
  },
@@ -58,12 +65,16 @@ export function createInstaller(name, claude) {
58
65
  return show((answer) => ({
59
66
  draw: () => frame(`${name} needs ${missing.length === 1 ? 'one setting' : `${missing.length} settings`}:`, missing.map(([key, option]) => {
60
67
  const label = Text({ children: [Text({ bold: true, children: option.title }), option.description === '' ? '' : Text({ dimColor: true, children: ` ${option.description}` })] });
61
- if (option.type === 'secret')
62
- return Box({ flexDirection: 'column', children: [label, Text({ dimColor: true, children: `Set it in /config, where Claude Code keeps it in your keychain, then press Next.` })] });
68
+ if (option.type === 'secret') {
69
+ return Box({
70
+ flexDirection: 'column',
71
+ children: [label, Text({ dimColor: true, children: `${secretFix} Then press Next.` }), Button({ key: `secret:${key}`, label: 'Open /config', onPress: () => void claude().command.run({ command: 'config' }) })],
72
+ });
73
+ }
63
74
  const failure = failures.get(key);
64
75
  const field = Input({
65
76
  key: `option:${key}`,
66
- label: '› ',
77
+ label: 'Value',
67
78
  placeholder: option.type === 'choice' ? (option.choices ?? []).join(', ') : option.type === 'toggle' ? 'true or false' : option.type === 'list' ? 'comma-separated' : '',
68
79
  value: saved.get(key) ?? '',
69
80
  submitLabel: 'save',
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"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"}