@cmodjs/core 4.0.3 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/commands.md +44 -9
- package/docs/index.md +3 -3
- package/docs/install-steps.md +8 -8
- package/docs/jobs.md +2 -1
- package/docs/mod.md +1 -1
- package/docs/options.md +1 -1
- package/docs/permissions.md +1 -1
- package/docs/session.md +46 -13
- package/docs/testing.md +15 -11
- package/docs/ui.md +43 -11
- package/installer.d.ts +3 -2
- package/installer.d.ts.map +1 -1
- package/jobs/program.d.ts +1 -0
- package/jobs/program.d.ts.map +1 -1
- package/jobs/program.js +39 -23
- package/mod.d.ts +3 -2
- package/mod.d.ts.map +1 -1
- package/mod.js +1 -0
- package/package.json +1 -1
- package/records.d.ts +15 -1
- package/records.d.ts.map +1 -1
- package/records.js +39 -1
- package/register.d.ts.map +1 -1
- package/register.js +8 -5
- package/runtime/before.d.ts +6 -2
- package/runtime/before.d.ts.map +1 -1
- package/runtime/before.js +56 -18
- package/runtime/buttons.d.ts +10 -0
- package/runtime/buttons.d.ts.map +1 -0
- package/runtime/buttons.js +12 -0
- package/runtime/conversations.d.ts +3 -0
- package/runtime/conversations.d.ts.map +1 -1
- package/runtime/conversations.js +164 -27
- package/runtime/engine.d.ts +2 -0
- package/runtime/engine.d.ts.map +1 -1
- package/runtime/grants.d.ts +1 -0
- package/runtime/grants.d.ts.map +1 -1
- package/runtime/grants.js +5 -2
- package/runtime/hotkeys.d.ts.map +1 -1
- package/runtime/hotkeys.js +7 -4
- package/runtime/installer.d.ts +10 -6
- package/runtime/installer.d.ts.map +1 -1
- package/runtime/installer.js +106 -48
- package/runtime/lifecycle.d.ts +2 -2
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +144 -42
- package/runtime/pages.d.ts +3 -1
- package/runtime/pages.d.ts.map +1 -1
- package/runtime/pages.js +48 -14
- package/runtime/parts.d.ts +1 -0
- package/runtime/parts.d.ts.map +1 -1
- package/runtime/parts.js +6 -3
- package/runtime/programs.d.ts +1 -0
- package/runtime/programs.d.ts.map +1 -1
- package/runtime/programs.js +4 -1
- package/runtime/sessions.d.ts +10 -3
- package/runtime/sessions.d.ts.map +1 -1
- package/runtime/sessions.js +104 -59
- package/runtime/toaster.d.ts.map +1 -1
- package/runtime/toaster.js +23 -9
- package/runtime/ui.d.ts +22 -4
- package/runtime/ui.d.ts.map +1 -1
- package/runtime/ui.js +161 -59
- package/runtime/watches.d.ts.map +1 -1
- package/runtime/watches.js +18 -4
- package/runtime/widgets.d.ts +7 -5
- package/runtime/widgets.d.ts.map +1 -1
- package/runtime/widgets.js +31 -21
- package/session/context/turn/message/attached-file.d.ts +13 -0
- package/session/context/turn/message/attached-file.d.ts.map +1 -0
- package/session/context/turn/message/attached-file.js +21 -0
- package/session/context/turn/message/message.d.ts +3 -2
- package/session/context/turn/message/message.d.ts.map +1 -1
- package/session/context/turn/message/message.js +20 -6
- package/session/conversation.d.ts +15 -3
- package/session/conversation.d.ts.map +1 -1
- package/session/conversation.js +23 -4
- package/session/goal/task.d.ts +5 -0
- package/session/goal/task.d.ts.map +1 -1
- package/session/session.d.ts +36 -7
- package/session/session.d.ts.map +1 -1
- package/session/session.js +2 -1
- package/src/installer.ts +3 -2
- package/src/jobs/program.ts +41 -21
- package/src/mod.ts +3 -2
- package/src/records.ts +49 -1
- package/src/register.ts +11 -8
- package/src/runtime/before.ts +61 -22
- package/src/runtime/buttons.ts +22 -0
- package/src/runtime/conversations.ts +170 -34
- package/src/runtime/engine.ts +2 -0
- package/src/runtime/grants.ts +6 -2
- package/src/runtime/hotkeys.ts +7 -4
- package/src/runtime/installer.ts +147 -83
- package/src/runtime/lifecycle.ts +149 -48
- package/src/runtime/pages.ts +56 -12
- package/src/runtime/parts.ts +8 -4
- package/src/runtime/programs.ts +5 -1
- package/src/runtime/sessions.ts +106 -59
- package/src/runtime/toaster.ts +27 -9
- package/src/runtime/ui.ts +166 -62
- package/src/runtime/watches.ts +20 -5
- package/src/runtime/widgets.ts +35 -23
- package/src/session/context/turn/message/attached-file.ts +36 -0
- package/src/session/context/turn/message/message.ts +20 -7
- package/src/session/conversation.ts +31 -6
- package/src/session/goal/task.ts +6 -0
- package/src/session/session.ts +18 -7
- package/src/testing/fake-claude.ts +21 -6
- package/src/testing/fake-elements.ts +57 -8
- package/src/testing/fake-sessions.ts +72 -24
- package/src/testing.ts +114 -33
- package/src/ui/areas.ts +1 -0
- package/src/ui/components.ts +14 -8
- package/src/ui/elements.ts +6 -2
- package/src/ui/markdown.ts +3 -3
- package/src/ui/panes.ts +2 -2
- package/src/ui/styles.ts +6 -2
- package/testing/fake-claude.d.ts +3 -0
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +18 -5
- package/testing/fake-elements.d.ts.map +1 -1
- package/testing/fake-elements.js +52 -7
- package/testing/fake-sessions.d.ts +24 -10
- package/testing/fake-sessions.d.ts.map +1 -1
- package/testing/fake-sessions.js +66 -20
- package/testing.d.ts +8 -12
- package/testing.d.ts.map +1 -1
- package/testing.js +113 -27
- package/ui/areas.d.ts +4 -0
- package/ui/areas.d.ts.map +1 -1
- package/ui/components.d.ts +1 -0
- package/ui/components.d.ts.map +1 -1
- package/ui/components.js +11 -7
- package/ui/elements.d.ts +3 -0
- package/ui/elements.d.ts.map +1 -1
- package/ui/elements.js +6 -1
- package/ui/markdown.d.ts +2 -2
- package/ui/markdown.d.ts.map +1 -1
- package/ui/panes.d.ts +2 -1
- package/ui/panes.d.ts.map +1 -1
- package/ui/styles.d.ts +11 -2
- package/ui/styles.d.ts.map +1 -1
package/testing.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createRouter } from './runtime/router.js';
|
|
|
7
7
|
import { toolInputOf } from './runtime/tool-calls.js';
|
|
8
8
|
import { createLifecycle } from './runtime/lifecycle.js';
|
|
9
9
|
import { MissingOptions } from './runtime/options.js';
|
|
10
|
-
import { conversationMethods } from './runtime/sessions.js';
|
|
10
|
+
import { conversationMethods, pickedColor } from './runtime/sessions.js';
|
|
11
11
|
import { Message } from './session/context/turn/message/message.js';
|
|
12
12
|
import { Note, untagged } from './session/context/turn/message/note.js';
|
|
13
13
|
import { Prompt } from './session/context/turn/message/prompt.js';
|
|
@@ -27,7 +27,7 @@ import { drawWith, elementOf } from './ui/elements.js';
|
|
|
27
27
|
import { drawnParts } from './runtime/parts.js';
|
|
28
28
|
import { serveWidgets } from './runtime/widgets.js';
|
|
29
29
|
import { engineOf } from './runtime/engine.js';
|
|
30
|
-
import { pagesOf } from './runtime/pages.js';
|
|
30
|
+
import { pagesOf, servePages } from './runtime/pages.js';
|
|
31
31
|
import { partMethods } from './runtime/ui.js';
|
|
32
32
|
const defaultColumns = 80;
|
|
33
33
|
const defaultRows = 24;
|
|
@@ -50,9 +50,11 @@ export function testMod(definition, options = {}) {
|
|
|
50
50
|
fake.claude.session.cwd = async () => cwd;
|
|
51
51
|
const conversations = fakeSessions({
|
|
52
52
|
callTool: (args) => fake.claude.tool.call(args),
|
|
53
|
+
listAgents: () => fake.fakes.agent.list?.() ?? Promise.resolve([]),
|
|
53
54
|
project: () => projectRoot,
|
|
54
55
|
cwd: () => cwd,
|
|
55
56
|
given: options.sessions ?? [],
|
|
57
|
+
decide: (event, change) => decide(event, change),
|
|
56
58
|
push: (mod, session, change) => {
|
|
57
59
|
if (mod !== name)
|
|
58
60
|
return;
|
|
@@ -62,6 +64,15 @@ export function testMod(definition, options = {}) {
|
|
|
62
64
|
});
|
|
63
65
|
conversations.start(sessionId);
|
|
64
66
|
const callMod = async (method, input, caller = cmodPluginName) => calledAnswer(caller, await lifecycle.route('cmod.call', { to: name, method, input, caller }, async () => ({ deny: notInstalled(name) })));
|
|
67
|
+
const tellColor = async (told) => {
|
|
68
|
+
if (name !== cmodPluginName)
|
|
69
|
+
await callMod(conversationMethods.sessionColor, told);
|
|
70
|
+
};
|
|
71
|
+
const tellHeldColor = async () => {
|
|
72
|
+
const held = conversations.color();
|
|
73
|
+
if (held.color !== undefined)
|
|
74
|
+
await tellColor(held);
|
|
75
|
+
};
|
|
65
76
|
let declaredPages = [];
|
|
66
77
|
let openPages = [];
|
|
67
78
|
let shownPage;
|
|
@@ -87,38 +98,69 @@ export function testMod(definition, options = {}) {
|
|
|
87
98
|
await tellShown();
|
|
88
99
|
};
|
|
89
100
|
let widgets;
|
|
101
|
+
let stylesMarkdown = false;
|
|
102
|
+
const ownMarkdown = new Map();
|
|
103
|
+
const missedMarkdown = new Map();
|
|
90
104
|
const updated = async ({ parts, redraw, requests }) => {
|
|
91
|
-
if (parts !== undefined)
|
|
105
|
+
if (parts !== undefined) {
|
|
92
106
|
declaredPages = pagesOf(parts);
|
|
107
|
+
stylesMarkdown = parts.stylesMarkdown === true;
|
|
108
|
+
ownMarkdown.clear();
|
|
109
|
+
}
|
|
93
110
|
if (parts !== undefined || redraw !== undefined)
|
|
94
111
|
(await widgetsOf()).update(name, { ...(parts === undefined ? {} : { parts }), ...(redraw === undefined ? {} : { redraw }) });
|
|
95
112
|
if (requests !== undefined && requests.length > 0)
|
|
96
113
|
await applyRequests(requests);
|
|
97
114
|
};
|
|
98
115
|
const pressPart = (input) => callMod(partMethods.press, input).then((update) => updated((update ?? {})));
|
|
116
|
+
const markdownIn = (table, at) => (props) => {
|
|
117
|
+
const drawnAt = `${at.surface}\u0000${at.columns}\u0000${props.text}`;
|
|
118
|
+
const drawn = stylesMarkdown ? ownMarkdown.get(drawnAt) : null;
|
|
119
|
+
if (drawn === undefined)
|
|
120
|
+
missedMarkdown.set(drawnAt, { markdown: props.text, ...at });
|
|
121
|
+
if (drawn === undefined || drawn === null || drawn.tree === null)
|
|
122
|
+
return table.Markdown(props);
|
|
123
|
+
const { draw, tree } = drawn;
|
|
124
|
+
return drawWith(table, () => elementOf(tree, '', (handler, args) => void pressPart({ draw, handler, args })));
|
|
125
|
+
};
|
|
126
|
+
const withOwnMarkdown = async (draw) => {
|
|
127
|
+
const first = await draw();
|
|
128
|
+
if (missedMarkdown.size === 0)
|
|
129
|
+
return first;
|
|
130
|
+
for (const [drawnAt, input] of missedMarkdown)
|
|
131
|
+
ownMarkdown.set(drawnAt, (await callMod(partMethods.draw, input)));
|
|
132
|
+
missedMarkdown.clear();
|
|
133
|
+
return draw();
|
|
134
|
+
};
|
|
135
|
+
const cmodClaude = { ...fake.claude, cmod: { call: async (input) => (input.to === name ? callMod(input.method, input.input) : fake.claude.cmod.call(input)) } };
|
|
136
|
+
const reportPart = (_id, message, error) => fake.claude.ui.log(`cmod: ${message}: ${messageOf(error)}`, { to: 'debug' });
|
|
137
|
+
const parts = drawnParts({ claude: cmodClaude, report: reportPart, press: (_mod, input) => void pressPart(input).catch((error) => fake.claude.ui.log(`cmod: ${name} did not take the press: ${messageOf(error)}`, { to: 'debug' })) });
|
|
99
138
|
const servedWidgets = async () => {
|
|
100
139
|
const own = name === cmodPluginName && lifecycle.mod !== undefined ? engineOf(lifecycle.mod).widgets : undefined;
|
|
101
140
|
if (own !== undefined)
|
|
102
141
|
return own;
|
|
103
|
-
const claude = { ...fake.claude, cmod: { call: async (input) => (input.to === name ? callMod(input.method, input.input) : fake.claude.cmod.call(input)) } };
|
|
104
|
-
const report = (_id, message, error) => fake.claude.ui.log(`cmod: ${message}: ${messageOf(error)}`, { to: 'debug' });
|
|
105
|
-
const press = (_mod, input) => void pressPart(input).catch((error) => fake.claude.ui.log(`cmod: ${name} did not take the press: ${messageOf(error)}`, { to: 'debug' }));
|
|
106
142
|
return serveWidgets({
|
|
107
|
-
claude,
|
|
143
|
+
claude: cmodClaude,
|
|
108
144
|
router: cmodPlugin,
|
|
109
145
|
store: storeFolder({ HOME: await fake.claude.env.home(), XDG_DATA_HOME: await fake.claude.env.dataHome() }),
|
|
110
|
-
report,
|
|
146
|
+
report: reportPart,
|
|
111
147
|
turnClosedBy: () => conversations.lastTurn(),
|
|
112
|
-
parts
|
|
148
|
+
parts,
|
|
149
|
+
markdownIn,
|
|
113
150
|
});
|
|
114
151
|
};
|
|
115
152
|
const widgetsOf = () => (widgets ??= servedWidgets());
|
|
153
|
+
const cmodBeneath = createRouter();
|
|
154
|
+
const pages = servePages({ claude: cmodClaude, router: cmodBeneath, report: reportPart, widgets: { update: (mod, update) => void widgetsOf().then((served) => served.update(mod, update)) }, parts, tellStylers: () => undefined });
|
|
155
|
+
pages.apply((_mod, requests) => applyRequests(requests));
|
|
116
156
|
const dependencies = fakeDependencies(name, options.dependencies ?? {}, conversations);
|
|
117
157
|
fake.fakes.cmod.call = async (call) => {
|
|
118
158
|
if (call.to !== cmodPluginName || call.method !== partMethods.changed)
|
|
119
159
|
return dependencies(call);
|
|
120
|
-
|
|
121
|
-
|
|
160
|
+
const { requests, isAsked, ...listing } = call.input;
|
|
161
|
+
const isHeld = isAsked === true && requests !== undefined && pages.update(name, { requests, isAsked });
|
|
162
|
+
await updated(isAsked === true ? listing : call.input);
|
|
163
|
+
return { isHeld };
|
|
122
164
|
};
|
|
123
165
|
const appendRow = fake.claude.session.append;
|
|
124
166
|
fake.claude.session.append = async (args) => {
|
|
@@ -147,6 +189,7 @@ export function testMod(definition, options = {}) {
|
|
|
147
189
|
const state = Object.fromEntries(declared.map(([lifetime, values]) => [lifetime, { ...values, ...starting?.[lifetime] }]));
|
|
148
190
|
const lifecycle = createLifecycle({ ...definition, state }, () => permissionRoutes, (options.options ?? {}), false);
|
|
149
191
|
let started;
|
|
192
|
+
let isColorTold = false;
|
|
150
193
|
const start = async () => {
|
|
151
194
|
started ??= lifecycle.start(fake.claude, async (claude) => {
|
|
152
195
|
const steps = await modSteps();
|
|
@@ -170,44 +213,80 @@ export function testMod(definition, options = {}) {
|
|
|
170
213
|
}
|
|
171
214
|
if (lifecycle.phase !== 'active')
|
|
172
215
|
throw failure ?? new Error(`${name} did not start: the lifecycle is ${lifecycle.phase}.`);
|
|
216
|
+
if (isColorTold)
|
|
217
|
+
return;
|
|
218
|
+
isColorTold = true;
|
|
219
|
+
await tellHeldColor();
|
|
173
220
|
};
|
|
174
221
|
const cmodPlugin = createRouter();
|
|
175
222
|
const askMod = async (event, change) => {
|
|
176
223
|
const asked = { to: name, method: conversationMethods.before, input: { session: sessionId, event, change }, caller: cmodPluginName };
|
|
177
224
|
return calledAnswer(cmodPluginName, await lifecycle.route('cmod.call', asked, async () => ({ deny: notInstalled(name) })));
|
|
178
225
|
};
|
|
226
|
+
const decide = (event, change) => foldBefore(event, change, [(latest) => askMod(event, latest)], (error) => fake.claude.ui.log(`cmod: passed the ${event} on without ${name}'s answer: ${messageOf(error)}`, { to: 'debug' }));
|
|
179
227
|
installBefore({
|
|
180
228
|
claude: fake.claude,
|
|
181
229
|
router: cmodPlugin,
|
|
182
230
|
hooks: {
|
|
183
231
|
place: async () => conversations.place(),
|
|
184
232
|
wants: async (event) => conversations.wants(name, event),
|
|
185
|
-
fold: () =>
|
|
233
|
+
fold: () => decide,
|
|
186
234
|
},
|
|
187
235
|
});
|
|
188
236
|
const route = async (event, input, below) => {
|
|
189
237
|
await start();
|
|
190
238
|
if (event === 'ui.render') {
|
|
239
|
+
const { component, requestId } = input;
|
|
240
|
+
if (component === 'Pane')
|
|
241
|
+
fake.placePane(requestId);
|
|
191
242
|
await widgetsOf();
|
|
192
243
|
await fake.settle();
|
|
193
244
|
}
|
|
194
|
-
return cmodPlugin.dispatch(event, input, (passed) => lifecycle.route(event, passed, async (e) => (
|
|
245
|
+
return cmodPlugin.dispatch(event, input, (passed) => lifecycle.route(event, passed, async (e) => (await claudeCodeRuns(event, e, below))));
|
|
195
246
|
};
|
|
196
|
-
const
|
|
247
|
+
const claudeCodeRuns = async (event, e, below) => {
|
|
248
|
+
if (event === 'session.compact' && e.trigger !== 'precompute') {
|
|
249
|
+
const started = await fire('SessionStart', { source: 'compact' });
|
|
250
|
+
fake.shown.notes.push(...(started.additionalContext ?? []).map(untagged));
|
|
251
|
+
}
|
|
252
|
+
if (below !== undefined)
|
|
253
|
+
return below;
|
|
254
|
+
const answer = claudeCodeAnswer(event, e);
|
|
255
|
+
if (event === 'ui.close') {
|
|
256
|
+
const { id, origin } = e;
|
|
257
|
+
if (origin.kind === 'person' && fake.shown.openPanes.has(id))
|
|
258
|
+
await drawPane(id);
|
|
259
|
+
fake.shown.openPanes.delete(id);
|
|
260
|
+
}
|
|
261
|
+
if (event === 'agent.spawn') {
|
|
262
|
+
const started = await route('classic.SubagentStart', { hook_event_name: 'SubagentStart', agent_id: answer.agentId, agent_type: e.subagentType }, undefined);
|
|
263
|
+
fake.shown.notes.push(...(started.additionalContext ?? []).map(untagged));
|
|
264
|
+
}
|
|
265
|
+
return answer;
|
|
266
|
+
};
|
|
267
|
+
const runCommand = async (command, args, builtIn = {}) => {
|
|
197
268
|
await start();
|
|
198
269
|
const reached = new Set();
|
|
199
|
-
const ownRun = async () => (reached.add(command),
|
|
200
|
-
const answer = await cmodPlugin.dispatch('command.run', { command, args, origin: { kind: 'composer' }, presentation }, (passed) => lifecycle.route('command.run', passed, ownRun));
|
|
270
|
+
const ownRun = async () => (reached.add(command), builtIn);
|
|
271
|
+
const answer = await cmodPlugin.dispatch('command.run', { command, args, origin: { kind: 'composer' }, presentation }, (passed) => lifecycle.route('command.run', passed, (e) => cmodBeneath.dispatch('command.run', e, ownRun)));
|
|
201
272
|
if (reached.has(command) && answer.text === undefined)
|
|
202
273
|
throw new Error(!fake.shown.commands.includes(command) ? `${name} has no slash command /${command}. Add it in setup with mod.use(slashCommand({ name: '${command}', … })).` : `${name}: /${command} reached Claude Code's own run of the command, so Claude Code shows "${name} registered /${command} but no command.run hook answered it". Answer it without calling next(e).`);
|
|
203
274
|
return answer;
|
|
204
275
|
};
|
|
205
|
-
const
|
|
276
|
+
const runColor = async (args) => {
|
|
277
|
+
if (args.trim() === '')
|
|
278
|
+
throw new Error(`Claude Code's /color with no color picks one at random, so a test names the color, such as tested.type('/color cyan').`);
|
|
279
|
+
const color = pickedColor(args);
|
|
280
|
+
const answer = await runCommand('color', args, { text: color === undefined ? 'Session color reset to default' : `Session color set to: ${color}` });
|
|
281
|
+
await tellColor(conversations.recolor(color));
|
|
282
|
+
return answer;
|
|
283
|
+
};
|
|
284
|
+
const drawPane = async (paneId, asked) => {
|
|
206
285
|
await start();
|
|
207
286
|
if (!fake.shown.openPanes.has(paneId))
|
|
208
287
|
throw new Error(`The pane "${paneId}" of ${name} closed, and a user sees a pane only while it is open.`);
|
|
209
288
|
const opened = fake.calls.findLast((call) => call.call === 'ui.open' && call.args[0].id === paneId)?.args[0];
|
|
210
|
-
const columns = opened?.columns ?? defaultColumns;
|
|
289
|
+
const columns = asked ?? opened?.columns ?? defaultColumns;
|
|
211
290
|
const isFocused = (await fake.claude.ui.panes()).some((open) => open.id === paneId && open.isFocused);
|
|
212
291
|
const props = { title: opened?.title ?? paneId, isFocused, bodyColumns: columns, placement: 'dock', scroll: { offset: 0, bodyRows: defaultRows }, view: {} };
|
|
213
292
|
const drawing = await route('ui.render', { surface: 'terminal', component: 'Pane', requestId: paneId, props }, elements.Box({}));
|
|
@@ -221,7 +300,7 @@ export function testMod(definition, options = {}) {
|
|
|
221
300
|
const drawn = (await callMod(partMethods.draw, { page: pageId, params: page.params, columns, isFocused: page.isFocused }));
|
|
222
301
|
await fake.settle();
|
|
223
302
|
const tree = drawn?.tree ?? null;
|
|
224
|
-
const drawing = tree === null || drawn === null ? elements.Box({}) : drawWith(elements, () => elementOf(tree, '', (handler, args) => void pressPart({ draw: drawn.draw, handler, args })));
|
|
303
|
+
const drawing = tree === null || drawn === null ? elements.Box({}) : await withOwnMarkdown(async () => drawWith(elements, () => elementOf(tree, '', (handler, args) => void pressPart({ draw: drawn.draw, handler, args })), markdownIn(elements, { surface: 'terminal', columns })));
|
|
225
304
|
return { drawing, columns };
|
|
226
305
|
};
|
|
227
306
|
const shownNow = (isPane) => {
|
|
@@ -240,7 +319,7 @@ export function testMod(definition, options = {}) {
|
|
|
240
319
|
const draw = async (columns) => {
|
|
241
320
|
await start();
|
|
242
321
|
const { id } = shownNow(isPane);
|
|
243
|
-
return { id, ...(isPane ? await drawPane(id) : await drawPage(id, columns)) };
|
|
322
|
+
return { id, ...(isPane ? await drawPane(id, columns) : await drawPage(id, columns)) };
|
|
244
323
|
};
|
|
245
324
|
const drawnElement = async (type, key) => {
|
|
246
325
|
const { id, drawing } = await draw();
|
|
@@ -274,7 +353,7 @@ export function testMod(definition, options = {}) {
|
|
|
274
353
|
return { element: e.element };
|
|
275
354
|
};
|
|
276
355
|
if (isPane)
|
|
277
|
-
await lifecycle.route('ui.press', pressed, run);
|
|
356
|
+
await lifecycle.route('ui.press', pressed, (e) => cmodBeneath.dispatch('ui.press', e, run));
|
|
278
357
|
else
|
|
279
358
|
await run(pressed);
|
|
280
359
|
await fake.settle();
|
|
@@ -304,7 +383,7 @@ export function testMod(definition, options = {}) {
|
|
|
304
383
|
const turn = area === TurnEndArea ? conversations.lastTurn() : undefined;
|
|
305
384
|
if (area === TurnEndArea && turn?.closedAt === undefined)
|
|
306
385
|
throw new Error(`${name} has no ended turn, so TurnEnd draws nothing. End one with tested.add({ type: Prompt, text: '…' }), then tested.endTurn().`);
|
|
307
|
-
return { drawing: elements.Box({ flexDirection: 'column', children: [...(await served.draw(area, elements, columns, turn))] }), columns };
|
|
386
|
+
return { drawing: elements.Box({ flexDirection: 'column', children: [...(await withOwnMarkdown(() => served.draw(area, elements, { surface: 'terminal', columns }, turn)))] }), columns };
|
|
308
387
|
};
|
|
309
388
|
const drawSlot = async (component, props, requestId = `${component}_${(slotDraws += 1)}`) => {
|
|
310
389
|
await start();
|
|
@@ -326,8 +405,11 @@ export function testMod(definition, options = {}) {
|
|
|
326
405
|
const toolUse = toolUseEvents.includes(event) ? { tool_use_id: `toolu_${(toolUses += 1)}` } : {};
|
|
327
406
|
const transcript = `/test/transcripts/${sessionId}.jsonl`;
|
|
328
407
|
const filled = { session_id: sessionId, transcript_path: transcript, cwd, hook_event_name: event, ...toolUse, ...input };
|
|
329
|
-
if (event === 'SessionStart'
|
|
330
|
-
|
|
408
|
+
if (event === 'SessionStart') {
|
|
409
|
+
const source = input.source;
|
|
410
|
+
const started = 'transcript_path' in input ? route('classic.SessionStart', filled, below) : files.write(transcript, '').then(() => route('classic.SessionStart', filled, below));
|
|
411
|
+
return source === 'startup' || source === 'clear' ? started : started.then(async (answer) => (await tellHeldColor(), answer));
|
|
412
|
+
}
|
|
331
413
|
if (event !== 'PreToolUse')
|
|
332
414
|
return route(`classic.${event}`, filled, below);
|
|
333
415
|
return firePreToolUse(filled, below);
|
|
@@ -406,9 +488,9 @@ export function testMod(definition, options = {}) {
|
|
|
406
488
|
await start();
|
|
407
489
|
return settled(conversations.add(message, added?.task));
|
|
408
490
|
},
|
|
409
|
-
endTurn: async (ending) => {
|
|
491
|
+
endTurn: async (ending, options) => {
|
|
410
492
|
await start();
|
|
411
|
-
await settled(conversations.endTurn(ending === undefined ? undefined : { ...ending, ...(ending.failure === undefined ? {} : { reason: 'error' }) }));
|
|
493
|
+
await settled(conversations.endTurn(ending === undefined ? undefined : { ...ending, ...(ending.failure === undefined ? {} : { reason: 'error' }) }, options?.task));
|
|
412
494
|
},
|
|
413
495
|
compact: async () => {
|
|
414
496
|
await start();
|
|
@@ -439,7 +521,7 @@ export function testMod(definition, options = {}) {
|
|
|
439
521
|
if (typed === null)
|
|
440
522
|
throw new Error(`type takes a slash command the way the user types it, such as tested.type('/help'), and "${line}" does not start with /.`);
|
|
441
523
|
const [, command = '', args = ''] = typed;
|
|
442
|
-
return replyOf(await runCommand(command, args));
|
|
524
|
+
return replyOf(await (command === 'color' ? runColor(args) : runCommand(command, args)));
|
|
443
525
|
},
|
|
444
526
|
async callTool(toolName, input) {
|
|
445
527
|
const tool = `mcp__${name}__${toolName}`;
|
|
@@ -530,6 +612,10 @@ function claudeCodeAnswer(event, e) {
|
|
|
530
612
|
const { model, parentModel } = e;
|
|
531
613
|
return { agentId: 'agent-1', model: model ?? parentModel };
|
|
532
614
|
}
|
|
615
|
+
if (event === 'session.append') {
|
|
616
|
+
const { message, uuid } = e;
|
|
617
|
+
return { message, uuid };
|
|
618
|
+
}
|
|
533
619
|
if (event !== 'prompt.submit')
|
|
534
620
|
return {};
|
|
535
621
|
const { text, context, origin } = e;
|
package/ui/areas.d.ts
CHANGED
|
@@ -19,6 +19,10 @@ export type WidgetInit<State extends object = Record<never, never>> = {
|
|
|
19
19
|
readonly id: string;
|
|
20
20
|
readonly title: string;
|
|
21
21
|
readonly areas: readonly [Area, ...Area[]];
|
|
22
|
+
readonly place?: {
|
|
23
|
+
readonly side?: 'left' | 'right';
|
|
24
|
+
readonly size?: 'fit' | 'fill';
|
|
25
|
+
};
|
|
22
26
|
render(mod: Mod<State>, context: WidgetContext): RenderElement | undefined;
|
|
23
27
|
};
|
|
24
28
|
export type Widget = {
|
package/ui/areas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"areas.d.ts","sourceRoot":"","sources":["../src/ui/areas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAE1C,eAAO,MAAM,WAAW,gBAAgB,CAAA;AACxC,eAAO,MAAM,WAAW,gBAAgB,CAAA;AACxC,eAAO,MAAM,OAAO,YAAY,CAAA;AAChC,eAAO,MAAM,OAAO,YAAY,CAAA;AAChC,eAAO,MAAM,SAAS,cAAc,CAAA;AAEpC,eAAO,MAAM,KAAK,4EAAmE,CAAA;AAErF,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzL,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;IAC1C,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,aAAa,GAAG,SAAS,CAAA;CAC3E,CAAA;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAA;IAC/B,MAAM,IAAI,IAAI,CAAA;CACf,CAAA"}
|
|
1
|
+
{"version":3,"file":"areas.d.ts","sourceRoot":"","sources":["../src/ui/areas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAE1C,eAAO,MAAM,WAAW,gBAAgB,CAAA;AACxC,eAAO,MAAM,WAAW,gBAAgB,CAAA;AACxC,eAAO,MAAM,OAAO,YAAY,CAAA;AAChC,eAAO,MAAM,OAAO,YAAY,CAAA;AAChC,eAAO,MAAM,SAAS,cAAc,CAAA;AAEpC,eAAO,MAAM,KAAK,4EAAmE,CAAA;AAErF,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzL,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAA;IACrF,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,aAAa,GAAG,SAAS,CAAA;CAC3E,CAAA;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAA;IAC/B,MAAM,IAAI,IAAI,CAAA;CACf,CAAA"}
|
package/ui/components.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { RenderChildren, RenderElement } from 'claude-code';
|
|
|
2
2
|
export type Tab = {
|
|
3
3
|
readonly key: string;
|
|
4
4
|
readonly label: string;
|
|
5
|
+
readonly hotkey?: string;
|
|
5
6
|
};
|
|
6
7
|
export declare function Tabs({ tabs, selected, onSelect, children }: {
|
|
7
8
|
readonly tabs: readonly Tab[];
|
package/ui/components.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/ui/components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhE,MAAM,MAAM,GAAG,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/ui/components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhE,MAAM,MAAM,GAAG,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5F,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GAAG,aAAa,CAOtN;AAED,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,GAAG,aAAa,CAGlG;AAED,wBAAgB,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GAAG,aAAa,CASxH;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG,aAAa,CAExK;AAED,wBAAgB,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GAAG,aAAa,CAExH;AAED,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG,aAAa,CAEzK;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAAG,aAAa,CAEpK;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GAAG,aAAa,CAS7J;AAED,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAGlH"}
|
package/ui/components.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { Box, Button, Text } from './elements.js';
|
|
2
2
|
export function Tabs({ tabs, selected, onSelect, children }) {
|
|
3
|
-
const row = tabs.map((
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
? Text({ children: [...(hotkey === undefined ? [] : [Text({ color: 'claude', children: hotkey }), ': ']), Text({ bold: true, underline: true, children: tab.label })] })
|
|
7
|
-
: Button({ plain: true, dimColor: true, key: `tab:${tab.key}`, ...(hotkey === undefined ? {} : { hotkey }), label: tab.label, onPress: () => onSelect(tab.key) });
|
|
8
|
-
});
|
|
3
|
+
const row = tabs.map(({ key, label, hotkey }) => key === selected
|
|
4
|
+
? Text({ children: [...(hotkey === undefined ? [] : [Text({ color: 'claude', children: hotkey }), ': ']), Text({ bold: true, underline: true, children: label })] })
|
|
5
|
+
: Button({ plain: true, dimColor: true, key: `tab:${key}`, ...(hotkey === undefined ? {} : { hotkey }), label, onPress: () => onSelect(key) }));
|
|
9
6
|
return Box({ flexDirection: 'column', gap: 1, children: [Box({ gap: 3, children: row }), children] });
|
|
10
7
|
}
|
|
11
8
|
export function Split({ children }) {
|
|
@@ -13,7 +10,14 @@ export function Split({ children }) {
|
|
|
13
10
|
return Box({ gap: 1, children: children.map((child) => Box({ width, children: child })) });
|
|
14
11
|
}
|
|
15
12
|
export function Panel({ title, children }) {
|
|
16
|
-
return Box({
|
|
13
|
+
return Box({
|
|
14
|
+
flexDirection: 'column',
|
|
15
|
+
flexGrow: 1,
|
|
16
|
+
children: [
|
|
17
|
+
Box({ flexDirection: 'column', flexGrow: 1, minWidth: [...title].length + 6, borderStyle: 'round', borderColor: 'subtle', paddingX: 1, children }),
|
|
18
|
+
Box({ position: 'absolute', top: 0, left: 2, children: Text({ bold: true, wrap: 'truncate-end', children: ` ${title} ` }) }),
|
|
19
|
+
],
|
|
20
|
+
});
|
|
17
21
|
}
|
|
18
22
|
export function Toggle({ label, checked, onChange }) {
|
|
19
23
|
return Button({ plain: true, key: `toggle:${label}`, label: `${checked ? '[x]' : '[ ]'} ${label}`, onPress: () => onChange(!checked) });
|
package/ui/elements.d.ts
CHANGED
|
@@ -12,4 +12,7 @@ export declare const Markdown: import("claude-code").ElementConstructor<Markdown
|
|
|
12
12
|
export declare const Input: import("claude-code").ElementConstructor<import("claude-code").InputProps>;
|
|
13
13
|
export declare const Select: import("claude-code").ElementConstructor<import("claude-code").SelectProps>;
|
|
14
14
|
export declare const Image: import("claude-code").ElementConstructor<import("claude-code").ImageProps>;
|
|
15
|
+
export declare const Svg: import("claude-code").ElementConstructor<import("claude-code").SvgProps>;
|
|
16
|
+
export declare const Raster: import("claude-code").ElementConstructor<import("claude-code").RasterProps>;
|
|
17
|
+
export declare const Client: import("claude-code").ElementConstructor<import("claude-code").ClientProps>;
|
|
15
18
|
//# sourceMappingURL=elements.d.ts.map
|
package/ui/elements.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../src/ui/elements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,YAAY,EAAY,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAcpG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,aAAa,GAAG,KAAK,CASjI;AAwBD,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAA;AAErD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../src/ui/elements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,YAAY,EAAY,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAcpG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,aAAa,GAAG,KAAK,CASjI;AAwBD,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAA;AAErD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAWxE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAa/H;AAED,eAAO,MAAM,GAAG,0EAAiB,CAAA;AACjC,eAAO,MAAM,IAAI,2EAAkB,CAAA;AACnC,eAAO,MAAM,MAAM,6EAAoB,CAAA;AACvC,eAAO,MAAM,IAAI,2EAAkB,CAAA;AACnC,eAAO,MAAM,IAAI,2EAAkB,CAAA;AACnC,eAAO,MAAM,QAAQ,yDAAsB,CAAA;AAC3C,eAAO,MAAM,KAAK,4EAAmB,CAAA;AACrC,eAAO,MAAM,MAAM,6EAAoB,CAAA;AACvC,eAAO,MAAM,KAAK,4EAAmB,CAAA;AACrC,eAAO,MAAM,GAAG,0EAAiB,CAAA;AACjC,eAAO,MAAM,MAAM,6EAAoB,CAAA;AACvC,eAAO,MAAM,MAAM,6EAAoB,CAAA"}
|
package/ui/elements.js
CHANGED
|
@@ -40,6 +40,8 @@ export function elementData(value, handlers) {
|
|
|
40
40
|
return value;
|
|
41
41
|
if (unbuilt in value) {
|
|
42
42
|
const { name, props } = value[unbuilt];
|
|
43
|
+
if (name === 'Client')
|
|
44
|
+
throw new Error('Client draws only in panes and styles.');
|
|
43
45
|
return { [elementKey]: name, props: elementData(props, handlers) };
|
|
44
46
|
}
|
|
45
47
|
if (Object.getPrototypeOf(value) !== Object.prototype)
|
|
@@ -73,4 +75,7 @@ export const Markdown = element('Markdown');
|
|
|
73
75
|
export const Input = element('Input');
|
|
74
76
|
export const Select = element('Select');
|
|
75
77
|
export const Image = element('Image');
|
|
76
|
-
const
|
|
78
|
+
export const Svg = element('Svg');
|
|
79
|
+
export const Raster = element('Raster');
|
|
80
|
+
export const Client = element('Client');
|
|
81
|
+
const constructors = { Box, Text, Button, Link, Code, Markdown, Input, Select, Image, Svg, Raster };
|
package/ui/markdown.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { KindProps } from './styles.js';
|
|
2
2
|
type BlockText = {
|
|
3
3
|
readonly text: string;
|
|
4
4
|
readonly source: string;
|
|
@@ -46,6 +46,6 @@ export declare const Table: Block<"table">;
|
|
|
46
46
|
export declare const ThematicBreak: Block<"thematicBreak">;
|
|
47
47
|
export declare const HtmlBlock: Block<"html">;
|
|
48
48
|
export declare function createReader(): MarkdownReader;
|
|
49
|
-
export declare function markdownBlocks<K extends Block>(text: string, kind: K):
|
|
49
|
+
export declare function markdownBlocks<K extends Block>(text: string, kind: K): KindProps<K>[];
|
|
50
50
|
export {};
|
|
51
51
|
//# sourceMappingURL=markdown.d.ts.map
|
package/ui/markdown.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/ui/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/ui/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,KAAK,SAAS,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnE,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;KAAE,CAAA;IAClD,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACtG,IAAI,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAA;IACjG,KAAK,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAA;KAAE,CAAA;IAC1E,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,UAAU,CAAC,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,SAAS,CAAA;AAExH,MAAM,MAAM,aAAa,CAAC,MAAM,IAAI;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAA;AAEtH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,SAAS,aAAa,CAAC,MAAM,CAAC,EAAE,CAAA;AAEzJ,MAAM,MAAM,KAAK,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAA;IACvB,YAAY,IAAI,cAAc,CAAA;CAC/B,CAAA;AAMD,eAAO,MAAM,OAAO,kBAAkC,CAAA;AACtD,eAAO,MAAM,SAAS,oBAAsC,CAAA;AAC5D,eAAO,MAAM,SAAS,eAAiC,CAAA;AACvD,eAAO,MAAM,UAAU,qBAAwC,CAAA;AAC/D,eAAO,MAAM,IAAI,eAA4B,CAAA;AAC7C,eAAO,MAAM,KAAK,gBAA8B,CAAA;AAChD,eAAO,MAAM,aAAa,wBAA8C,CAAA;AACxE,eAAO,MAAM,SAAS,eAAiC,CAAA;AA4BvD,wBAAgB,YAAY,IAAI,cAAc,CA0C7C;AA0DD,wBAAgB,cAAc,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAGrF"}
|
package/ui/panes.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Frozen, PaneCloseInput, RenderElement, RenderPropsOf, UiScrollInput } from 'claude-code';
|
|
2
|
-
import type { Mod } from '../mod.js';
|
|
2
|
+
import type { Mod, Surface } from '../mod.js';
|
|
3
3
|
export type ScrollTarget = 'start' | 'end' | {
|
|
4
4
|
readonly key: string;
|
|
5
5
|
};
|
|
@@ -14,6 +14,7 @@ export type OpenOptions<Params> = {
|
|
|
14
14
|
readonly params: Params;
|
|
15
15
|
});
|
|
16
16
|
export type PaneProps<Params> = Frozen<RenderPropsOf['Pane']> & {
|
|
17
|
+
readonly surface: Surface;
|
|
17
18
|
readonly params: Params;
|
|
18
19
|
};
|
|
19
20
|
export type PaneInit<State extends object = Record<never, never>, Params = undefined> = {
|
package/ui/panes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panes.d.ts","sourceRoot":"","sources":["../src/ui/panes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtG,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"panes.d.ts","sourceRoot":"","sources":["../src/ui/panes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtG,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE7C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAErE,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAA;CAAE,CAAA;AAEvF,MAAM,MAAM,WAAW,CAAC,MAAM,IAAI;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAA;CAAE,GAAG,CAAC,SAAS,SAAS,MAAM,GAAG;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAErJ,MAAM,MAAM,SAAS,CAAC,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtH,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,IAAI;IACtF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,SAAS,CAAC,CAAA;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,SAAS,CAAC,CAAA;IAC/D,QAAQ,CAAC,aAAa,CAAC,EAAE,IAAI,CAAA;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;IAC1B,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,aAAa,CAAA;IAChE,QAAQ,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3E,CAAA;AAED,MAAM,MAAM,IAAI,CAAC,MAAM,GAAG,SAAS,IAAI;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,IAAI,CAAC,GAAG,OAAO,EAAE,SAAS,SAAS,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5H,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtE,MAAM,IAAI,IAAI,CAAA;CACf,CAAA;AAED,MAAM,MAAM,SAAS,CAAC,MAAM,IAAI;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAElH,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,IAAI;IACtF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,aAAa,CAAA;CACjE,CAAA;AAED,MAAM,MAAM,IAAI,CAAC,MAAM,GAAG,SAAS,IAAI;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,IAAI,CAAC,GAAG,OAAO,EAAE,SAAS,SAAS,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5H,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtE,MAAM,IAAI,IAAI,CAAA;CACf,CAAA;AAID,eAAO,MAAM,QAAQ,YAAI,SAAS,EAAE,MAAM,CAAU,CAAA;AAEpD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAGrF;AAED,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,IAAI,CAMzG"}
|
package/ui/styles.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Frozen, RenderComponent, RenderElement, RenderPropsOf } from 'claude-code';
|
|
2
|
-
import type { Mod } from '../mod.js';
|
|
2
|
+
import type { Mod, Surface } from '../mod.js';
|
|
3
3
|
import type { Block, BlockProps } from './markdown.js';
|
|
4
4
|
export declare const ToolGroup = "toolGroup";
|
|
5
5
|
export declare const ToolProgress = "toolProgress";
|
|
@@ -27,9 +27,18 @@ type PropsOf<K extends Kind> = K extends Row ? RowProps[K] : K extends Block<inf
|
|
|
27
27
|
type DefaultOf<K extends Kind> = K extends Row ? Partial<Omit<RowProps[K], 'onScreen'>> : {
|
|
28
28
|
readonly source?: string;
|
|
29
29
|
};
|
|
30
|
-
export type StyleProps<K extends Kind> = Frozen<PropsOf<K>> & {
|
|
30
|
+
export type StyleProps<K extends Kind> = Frozen<PropsOf<K>> & StyledAt & (K extends Row ? {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
} : {
|
|
33
|
+
readonly id?: string;
|
|
34
|
+
}) & {
|
|
31
35
|
readonly Default: (props: Frozen<DefaultOf<K>>) => RenderElement;
|
|
32
36
|
};
|
|
37
|
+
export type KindProps<K extends Kind> = Omit<StyleProps<K>, 'Default' | 'surface' | 'columns' | 'id'>;
|
|
38
|
+
export type StyledAt = {
|
|
39
|
+
readonly surface: Surface;
|
|
40
|
+
readonly columns: number;
|
|
41
|
+
};
|
|
33
42
|
export type StyleInit<K extends Kind, State extends object = Record<never, never>> = {
|
|
34
43
|
readonly kind: K;
|
|
35
44
|
render(mod: Mod<State>, props: StyleProps<K>): RenderElement;
|
package/ui/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/ui/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACxF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/ui/styles.ts"],"names":[],"mappings":"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"}
|