@cmodjs/core 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/index.md CHANGED
@@ -71,6 +71,7 @@ A mod imports from the files below, and every other file in this package is inte
71
71
  | Import | Exports | Docs |
72
72
  | --- | --- | --- |
73
73
  | `mod.js` | `defineMod`, `ModDefinition`, `Mod`, `PartContext`, `Part`, `ProgressStep`, `PaneHandle`, `longestMs`, `messageOf` | [mod.md](mod.md), [jobs.md](jobs.md), [ui.md](ui.md) |
74
+ | `mod.js` | `Claude`, `RoutedEvent`, `RoutedHook`, `ToolCalls` | [jobs.md](jobs.md) |
74
75
  | `mod.js` | `ModEvent`, `ModHook`, `HookAnswer` | [hooks.md](hooks.md) |
75
76
  | `mod.js` | `notInstalled` | [dependencies.md](dependencies.md) |
76
77
  | `connect.js` | `connect` | [mod.md](mod.md) |
@@ -86,8 +87,7 @@ A mod imports from the files below, and every other file in this package is inte
86
87
  | `jobs/prompt.js` | `prompt` | [jobs.md](jobs.md) |
87
88
  | `jobs/status-line.js` | `statusLine`, `Usage` | [jobs.md](jobs.md) |
88
89
  | `jobs/program.js` | `program`, `Program` | [jobs.md](jobs.md) |
89
- | `jobs/part-context.js` | `afterCall`, `modWithin`, `modOf`, `workspaceReader`, `targetWords` | [jobs.md](jobs.md) |
90
- | `jobs/permissions/match-target.js` | `targetOf`, `matchTarget`, `folderInScope`, `Target`, `TargetKey`, `TargetOf`, `TargetCalls`, `MatchedCall` | [jobs.md](jobs.md) |
90
+ | `jobs/part-context.js` | `afterCall`, `modWithin`, `modOf`, `workspaceReader` | [jobs.md](jobs.md) |
91
91
  | `jobs/permissions/decide-permission.js` | `decidePermission`, `stricterVerdict`, `Rule`, `PermissionRules`, `Decision`, `Verdict` | [jobs.md](jobs.md) |
92
92
  | `jobs/permissions/find-project-scope.js` | `findProjectScope`, `ProjectScope`, `Workspace` | [jobs.md](jobs.md) |
93
93
 
package/docs/jobs.md CHANGED
@@ -255,7 +255,7 @@ prompt<State>(options: {
255
255
  - With `when` or `after`, the text goes to Claude under the heading `# <name>`.
256
256
  - A `prompt` function that returns `undefined` or `''` adds nothing. One that throws adds nothing, and the error goes to Claude Code's debug log.
257
257
  - `name` cannot be blank. `when` and `after` together throw: add a second `prompt` for the other trigger. Two prompts with one name in a mod throw.
258
- - A `when` prompt runs on `prompt.submit` and adds its text to the event it passes down, so a test reads it with a spy part. [testing.md](testing.md#test-a-prompt-with-when) shows how.
258
+ - A `when` prompt runs on `prompt.submit` and adds its text to the event it passes down. In a test, `fire('prompt.submit', …)` returns that text in the answer's `context`. [testing.md](testing.md#test-a-prompt-with-when) shows how.
259
259
 
260
260
  ```ts
261
261
  import { defineMod } from '../node_modules/@cmodjs/core/mod.js'
@@ -387,7 +387,7 @@ export const timer = defineMod({
387
387
 
388
388
  ### The claude members
389
389
 
390
- `mod.js` does not export the types `Claude`, `RoutedEvent`, `RoutedHook`, or `ToolCalls`. A job of your own types `claude` through `PartContext`, such as `PartContext['claude']`, or lets `Part` infer it.
390
+ `mod.js` exports the types `Claude`, `RoutedEvent`, `RoutedHook`, and `ToolCalls`, so a job of your own names them in its own helpers, such as `(claude: Claude, calls: ToolCalls): RoutedHook<'command.run'> => …`.
391
391
 
392
392
  Each member calls the member of the same name in Claude Code's hooks API, `$`, with the same arguments. The `env` members read `$.env.get` instead.
393
393
 
@@ -440,13 +440,11 @@ The built-in jobs are written from these building blocks, which a job of your ow
440
440
  | `jobs/part-context.js` | `modWithin(part, deadline, workTree?)` | A `mod` whose calls fail at `deadline`, `{ ms, job?, longestMs? }`. |
441
441
  | `jobs/part-context.js` | `modOf(part, { call?, folder }, workspace, deadline)` | `modWithin`, with `mod.process` calls run in the call's work tree. |
442
442
  | `jobs/part-context.js` | `workspaceReader(part)` | A function that reads the session's `projectRoot`, `cwd`, `home`, file access, and project scope. |
443
- | `jobs/part-context.js` | `targetWords(target)` | A target in words, such as `edits to src/**`. |
444
- | `jobs/permissions/match-target.js` | `targetOf`, `matchTarget`, `folderInScope`, and the types `Target`, `TargetKey`, `TargetOf`, `TargetCalls`, `MatchedCall` | Checks a target and matches it against a call. |
445
443
  | `jobs/permissions/decide-permission.js` | `decidePermission`, `stricterVerdict`, and the types `Rule`, `PermissionRules`, `Decision`, `Verdict` | Decides a call against permission rules. |
446
444
  | `jobs/permissions/find-project-scope.js` | `findProjectScope`, and the types `ProjectScope`, `Workspace` | Finds the repository a project plugin belongs to. |
447
445
 
448
- `matchTarget` and `folderInScope` take a `CallEffects`, the files, URLs, and commands of one call. Only the internal `utils/call-effects.js` makes one, and no export does. So a job of your own reaches permission matching through the `permissions` and `check` jobs, not through `matchTarget`.
446
+ A job of your own matches calls against targets through the `permissions`, `check`, and `prompt` jobs. A `prompt` with `after` runs any code after a matching call, and may add no text: `prompt({ name: 'commits', after: { command: 'git commit' }, prompt: (_input, mod) => { mod.state.project.commits += 1; return undefined } })`.
449
447
 
450
448
  ## Test a job
451
449
 
452
- `tested.type('/todo milk')` runs a slash command. `tested.callTool('open_ticket', { title: 'Crash' })` runs the permission rules, then the tool. `tested.fire('tool.check', …)` asks the permission rules about any call. `tested.fire('prompt.submit', …)` with a spy part tests a `when` prompt. [testing.md](testing.md) covers each.
450
+ `tested.type('/todo milk')` runs a slash command. `tested.callTool('open_ticket', { title: 'Crash' })` runs the permission rules, then the tool. `tested.fire('tool.check', …)` asks the permission rules about any call. `tested.fire('prompt.submit', …)` returns the context a `when` prompt added. [testing.md](testing.md) covers each.
package/docs/testing.md CHANGED
@@ -80,7 +80,8 @@ fire<N extends RoutedEvent>(event: N, input: Args<N>, below?): Promise<EventResu
80
80
 
81
81
  - `fire('UserPromptSubmit', { prompt: 'hello' })` runs the mod's hooks on a `ModEvent`. `TestInput<E>` is the event's input without the fields `fire` fills: `session_id`, `transcript_path`, `cwd`, `hook_event_name`, and a new `tool_use_id` for each tool event.
82
82
  - For a tool event, `files` is worked out from the call and the test's `files`, as in Claude Code.
83
- - `below` is what the hooks beneath the mod answered, `{}` by default. Pass it to test how the mod's answer combines with another, such as a `deny` beneath. When nothing in the mod answers, `fire` returns `below` as it is.
83
+ - `below` is what the hooks beneath the mod answered. Pass it to test how the mod's answer combines with another, such as a `deny` beneath. When nothing in the mod answers, `fire` returns `below` as it is.
84
+ - Left out, `below` is `{}`, except on `prompt.submit`, where it is what Claude Code answers: the prompt that entered, `{ text, context, origin }`, with the `context` the mod's hooks added.
84
85
  - It returns the combined answer in Claude Code's own field names: `additionalContext` is a list, a `PreToolUse` decision is `allow: true`, or the key `ask` or `deny` with the reason as its value, and `decision: 'block'` is `block`.
85
86
  - `fire('tool.check', { tool: 'Edit', input: { … }, tool_use_id: 'toolu_1' }, { decision: 'allow' })` asks the mod's permission rules about any call. A name with a dot fires that Claude Code hook-module event as it is.
86
87
 
@@ -100,10 +101,10 @@ test('a force push is denied with the reason', async () => {
100
101
 
101
102
  ### Test a prompt with when
102
103
 
103
- A `prompt` with `when` runs on the hook-module event `prompt.submit`, not on `UserPromptSubmit`, so `fire('UserPromptSubmit', …)` never reaches it. It adds its text to the `context` field of the event it passes down, and `fire` returns `below`, so the answer does not show the text either. Read it with a spy part used after the prompt, which sees the event the prompt passes down:
104
+ A `prompt` with `when` runs on the hook-module event `prompt.submit`, not on `UserPromptSubmit`, so `fire('UserPromptSubmit', …)` never reaches it. `fire('prompt.submit', …)` returns the prompt that entered, with the text the prompt added in its `context`:
104
105
 
105
106
  - The `prompt.submit` input is `{ text, wait, origin }`. A prompt the person typed has `wait: false` and `origin: { kind: 'composer' }`.
106
- - `context` is a list of strings, each `# <name>\n<text>`. It is `undefined` when no prompt added anything.
107
+ - `context` is a list of strings, each `# <name>\n<text>`. The answer has no `context` when no prompt added anything.
107
108
 
108
109
  ```ts
109
110
  import { defineMod } from '../node_modules/@cmodjs/core/mod.js'
@@ -119,35 +120,18 @@ export const release = defineMod({
119
120
 
120
121
  ```ts
121
122
  import { expect, test } from 'bun:test'
122
- import { defineMod, type Part } from '../node_modules/@cmodjs/core/mod.js'
123
123
  import { testMod } from '../node_modules/@cmodjs/core/testing.js'
124
124
  import { release } from '../src/mod.js'
125
125
 
126
- function contextBelow(passedOn: unknown[]): Part<void> {
127
- return ({ on }) => {
128
- on('prompt.submit', async (e, next) => {
129
- passedOn.push(e.context)
130
- return next(e)
131
- })
132
- }
133
- }
134
-
135
126
  test('a prompt about a release gets the release steps, and another prompt gets nothing', async () => {
136
- const passedOn: unknown[] = []
137
- const tested = testMod(
138
- defineMod({
139
- ...release,
140
- setup(mod) {
141
- release.setup(mod)
142
- mod.use(contextBelow(passedOn))
143
- },
144
- }),
145
- )
146
-
147
- await tested.fire('prompt.submit', { text: 'Cut a release', wait: false, origin: { kind: 'composer' } }, { text: '' })
148
- await tested.fire('prompt.submit', { text: 'Fix the bug', wait: false, origin: { kind: 'composer' } }, { text: '' })
149
-
150
- expect(passedOn).toEqual([['# release-steps\nRun bun run release, then push the tag.'], undefined])
127
+ const tested = testMod(release)
128
+ const typed = { wait: false, origin: { kind: 'composer' } } as const
129
+
130
+ const aboutRelease = await tested.fire('prompt.submit', { text: 'Cut a release', ...typed })
131
+ const aboutBug = await tested.fire('prompt.submit', { text: 'Fix the bug', ...typed })
132
+
133
+ expect(aboutRelease).toEqual({ text: 'Cut a release', context: ['# release-steps\nRun bun run release, then push the tag.'], origin: typed.origin })
134
+ expect(aboutBug).toEqual({ text: 'Fix the bug', origin: typed.origin })
151
135
  })
152
136
  ```
153
137
 
@@ -157,7 +141,7 @@ Waits until the work a hook started without awaiting it has run, such as a `void
157
141
 
158
142
  ### lines
159
143
 
160
- - `lines(paneId)` draws an open pane and returns its rows of text. It rejects a pane that is not open: open it first with `tested.type('/<command>')` or `pane.open()` in the mod. The render gets the props `title`, `isFocused`, `bodyColumns`, and `placement: 'dock'`, and no `scroll` or `view`, so a render that reads those two gets `undefined` in a test.
144
+ - `lines(paneId)` draws an open pane and returns its rows of text. It rejects a pane that is not open: open it first with `tested.type('/<command>')` or `pane.open()` in the mod. The render gets the props `title`, `isFocused: false`, `bodyColumns`, `placement: 'dock'`, `scroll: { offset: 0, bodyRows: 24 }`, and `view: {}`, the main conversation's view.
161
145
  - `lines(slot, props, requestId?)` draws a slot render with `props` and returns its rows. `Default` draws a plain listing of the props it gets, so a test sees what the render changed. Draw `slots.AssistantMessage` with a reply's `text` to test a markdown slot render. Draws that pass one `requestId` grow one streamed reply.
162
146
 
163
147
  ```ts
package/mod.d.ts CHANGED
@@ -16,6 +16,7 @@ export type PaneHandle = {
16
16
  toggle(): Promise<void>;
17
17
  readonly isOpen: boolean;
18
18
  };
19
+ export type { Claude, RoutedEvent, RoutedHook, ToolCalls };
19
20
  export { longestMs } from './runtime/deadline.js';
20
21
  export { notInstalled } from './runtime/dependencies.js';
21
22
  export { messageOf } from './utils/text.js';
package/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["src/mod.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["src/mod.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmodjs/core",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Build Claude Code mods: hooks, panes, permissions, checks, and an install that just works.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/mod.ts CHANGED
@@ -36,6 +36,7 @@ export type PaneHandle = {
36
36
  readonly isOpen: boolean
37
37
  }
38
38
 
39
+ export type { Claude, RoutedEvent, RoutedHook, ToolCalls }
39
40
  export { longestMs } from './runtime/deadline.js'
40
41
  export { notInstalled } from './runtime/dependencies.js'
41
42
  export { messageOf } from './utils/text.js'
package/src/testing.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Args, ClassicHookInputs, CmodDependencies, CommandPresentation, CommandRunResult, EventResult, Frozen, PaneOpenArgs, RenderChildren, RenderComponent, RenderElement } from 'claude-code'
1
+ import type { Args, ClassicHookInputs, CmodDependencies, CommandPresentation, CommandRunResult, EventResult, Frozen, PaneOpenArgs, RenderChildren, RenderComponent, RenderElement, RenderPropsOf } from 'claude-code'
2
2
  import type { Reply } from './jobs/slash-command.js'
3
3
  import type { ModDefinition, ModEvent } from './mod.js'
4
4
  import { storeFolder } from './records.js'
@@ -45,6 +45,8 @@ export type TestedMod<State extends object> = {
45
45
 
46
46
  const defaultColumns = 80
47
47
 
48
+ const defaultRows = 24
49
+
48
50
  const presentation: CommandPresentation = { isFullscreen: false, columns: defaultColumns }
49
51
 
50
52
  const toolUseEvents: readonly string[] = ['PreToolUse', 'PostToolUse', 'PostToolUseFailure', 'PermissionDenied'] satisfies readonly ModEvent[]
@@ -87,7 +89,7 @@ export function testMod<State extends object>(definition: ModDefinition<State>,
87
89
 
88
90
  const route = async <N extends RoutedEvent>(event: N, input: unknown, below: unknown): Promise<EventResult<N>> => {
89
91
  await start()
90
- return lifecycle.route(event, input as Frozen<Args<N>>, async () => below as EventResult<N>)
92
+ return lifecycle.route(event, input as Frozen<Args<N>>, async (e) => (below ?? claudeCodeAnswer(event, e)) as EventResult<N>)
91
93
  }
92
94
 
93
95
  const drawPane = async (paneId: string) => {
@@ -98,7 +100,7 @@ export function testMod<State extends object>(definition: ModDefinition<State>,
98
100
  }
99
101
  const opened = fake.calls.findLast((call) => call.call === 'ui.open' && (call.args[0] as PaneOpenArgs).id === paneId)?.args[0] as PaneOpenArgs | undefined
100
102
  const columns = opened?.columns ?? defaultColumns
101
- const props = { title: opened?.title ?? paneId, isFocused: false, bodyColumns: columns, placement: 'dock' }
103
+ const props: RenderPropsOf['Pane'] = { title: opened?.title ?? paneId, isFocused: false, bodyColumns: columns, placement: 'dock', scroll: { offset: 0, bodyRows: defaultRows }, view: {} }
102
104
  const drawing = await route('ui.render', { surface: 'terminal', component: 'Pane', requestId: paneId, props }, elements.Box({}))
103
105
  return { drawing, columns }
104
106
  }
@@ -110,7 +112,7 @@ export function testMod<State extends object>(definition: ModDefinition<State>,
110
112
  return { drawing, columns: defaultColumns }
111
113
  }
112
114
 
113
- const fire = ((event: string, input: object, below: unknown = {}) => {
115
+ const fire = ((event: string, input: object, below?: unknown) => {
114
116
  if (event.includes('.')) return route(event as RoutedEvent, input, below)
115
117
  if (event === 'SessionStart') sessionId = (input as { session_id?: string }).session_id ?? sessionId
116
118
  if (event === 'UserPromptSubmit') {
@@ -192,6 +194,12 @@ function fakeDependencies(dependencies: NonNullable<TestOptions<object>['depende
192
194
  }
193
195
  }
194
196
 
197
+ function claudeCodeAnswer(event: RoutedEvent, e: unknown): unknown {
198
+ if (event !== 'prompt.submit') return {}
199
+ const { text, context, origin } = e as Args<'prompt.submit'>
200
+ return { text, ...(context === undefined ? {} : { context }), origin }
201
+ }
202
+
195
203
  function plainOutput({ component, props }: Args<'ui.render'>): RenderElement {
196
204
  const rows = Object.entries(props).map(([key, value]) => elements.Text({ children: `${key}: ${JSON.stringify(value)}` }))
197
205
  return elements.Box({ flexDirection: 'column', children: [elements.Text({ children: component }), elements.Box({ flexDirection: 'column', paddingLeft: 2, children: rows })] })
package/testing.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAyC,WAAW,EAAwC,eAAe,EAAiB,MAAM,aAAa,CAAA;AACtM,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAIvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,OAAO,EAAc,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAG5F,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAEpD,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEtE,MAAM,MAAM,WAAW,CAAC,KAAK,SAAS,MAAM,IAAI;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,EAAE,QAAQ,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;KAAE,CAAA;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,YAAY,CAAC,EAAE;QAAE,QAAQ,EAAE,IAAI,IAAI,MAAM,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,CAAC,IAAI,CAAC;KAAE,CAAA;IAC9F,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAClD,CAAA;AAED,KAAK,WAAW,GAAG,YAAY,GAAG,iBAAiB,GAAG,KAAK,GAAG,iBAAiB,GAAG,aAAa,CAAA;AAE/F,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAEnK,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAA;IAClI,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;IACtG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACxC,KAAK,CAAC,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACpK,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAA;IACzF,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACtB,CAAA;AAQD,wBAAgB,OAAO,CAAC,KAAK,SAAS,MAAM,EAAE,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,GAAE,WAAW,CAAC,KAAK,CAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAmIlI"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["src/testing.ts"],"names":[],"mappings":"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"}
package/testing.js CHANGED
@@ -5,6 +5,7 @@ import { fakeClaude } from './testing/fake-claude.js';
5
5
  import { elements, findButton, rowsOf } from './testing/fake-elements.js';
6
6
  import { fakeFiles } from './testing/fake-files.js';
7
7
  const defaultColumns = 80;
8
+ const defaultRows = 24;
8
9
  const presentation = { isFullscreen: false, columns: defaultColumns };
9
10
  const toolUseEvents = ['PreToolUse', 'PostToolUse', 'PostToolUseFailure', 'PermissionDenied'];
10
11
  export function testMod(definition, options = {}) {
@@ -44,7 +45,7 @@ export function testMod(definition, options = {}) {
44
45
  };
45
46
  const route = async (event, input, below) => {
46
47
  await start();
47
- return lifecycle.route(event, input, async () => below);
48
+ return lifecycle.route(event, input, async (e) => (below ?? claudeCodeAnswer(event, e)));
48
49
  };
49
50
  const drawPane = async (paneId) => {
50
51
  await start();
@@ -54,7 +55,7 @@ export function testMod(definition, options = {}) {
54
55
  }
55
56
  const opened = fake.calls.findLast((call) => call.call === 'ui.open' && call.args[0].id === paneId)?.args[0];
56
57
  const columns = opened?.columns ?? defaultColumns;
57
- const props = { title: opened?.title ?? paneId, isFocused: false, bodyColumns: columns, placement: 'dock' };
58
+ const props = { title: opened?.title ?? paneId, isFocused: false, bodyColumns: columns, placement: 'dock', scroll: { offset: 0, bodyRows: defaultRows }, view: {} };
58
59
  const drawing = await route('ui.render', { surface: 'terminal', component: 'Pane', requestId: paneId, props }, elements.Box({}));
59
60
  return { drawing, columns };
60
61
  };
@@ -64,7 +65,7 @@ export function testMod(definition, options = {}) {
64
65
  const drawing = await lifecycle.route('ui.render', input, async (e) => plainOutput(e));
65
66
  return { drawing, columns: defaultColumns };
66
67
  };
67
- const fire = ((event, input, below = {}) => {
68
+ const fire = ((event, input, below) => {
68
69
  if (event.includes('.'))
69
70
  return route(event, input, below);
70
71
  if (event === 'SessionStart')
@@ -155,6 +156,12 @@ function fakeDependencies(dependencies) {
155
156
  return answer.value;
156
157
  };
157
158
  }
159
+ function claudeCodeAnswer(event, e) {
160
+ if (event !== 'prompt.submit')
161
+ return {};
162
+ const { text, context, origin } = e;
163
+ return { text, ...(context === undefined ? {} : { context }), origin };
164
+ }
158
165
  function plainOutput({ component, props }) {
159
166
  const rows = Object.entries(props).map(([key, value]) => elements.Text({ children: `${key}: ${JSON.stringify(value)}` }));
160
167
  return elements.Box({ flexDirection: 'column', children: [elements.Text({ children: component }), elements.Box({ flexDirection: 'column', paddingLeft: 2, children: rows })] });