@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/runtime/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAM5D,OAAO,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAC3E,OAAO,EAAsB,KAAK,IAAI,EAAE,MAAM,iCAAiC,CAAA;AAC/E,OAAO,
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/runtime/sessions.ts"],"names":[],"mappings":"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"}
|
package/runtime/sessions.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Person, senderOf } from '../session/context/turn/message/sender.js';
|
|
|
5
5
|
import { ToolCall } from '../session/context/turn/message/tool-call.js';
|
|
6
6
|
import { ToolResult } from '../session/context/turn/message/tool-result.js';
|
|
7
7
|
import { TurnEnd, TurnStart } from '../session/context/turn/turn.js';
|
|
8
|
-
import { searchLimit } from '../session/conversation.js';
|
|
8
|
+
import { forkAgentType, searchLimit } from '../session/conversation.js';
|
|
9
9
|
import { GoalChange } from '../session/goal/goal.js';
|
|
10
10
|
import { TaskEnd, TaskStart } from '../session/goal/task.js';
|
|
11
11
|
import { beforeEvents, processEvents, Session, sessionEvents } from '../session/session.js';
|
|
@@ -31,11 +31,21 @@ export const conversationMethods = {
|
|
|
31
31
|
act: 'cmod:act',
|
|
32
32
|
changed: 'cmod:changed',
|
|
33
33
|
before: 'cmod:before',
|
|
34
|
+
sessionColor: 'cmod:sessionColor',
|
|
34
35
|
};
|
|
35
|
-
const
|
|
36
|
+
const resetColors = ['default', 'reset', 'none', 'gray', 'grey'];
|
|
37
|
+
export function pickedColor(args) {
|
|
38
|
+
const picked = args.trim().toLowerCase();
|
|
39
|
+
return resetColors.includes(picked) ? undefined : picked;
|
|
40
|
+
}
|
|
41
|
+
const actPermissions = { send: 'prompt', startTask: 'tasks', fork: 'tasks', clone: 'tasks', startBackgroundTask: 'tasks', usage: 'conversation', surfaces: 'conversation', abort: 'prompt' };
|
|
36
42
|
const startsTurns = ['CronCreate'];
|
|
37
43
|
const ownSchedule = ['CronDelete', 'CronList'];
|
|
38
44
|
export const beforePermission = (event) => (event === 'toolCall' ? 'tools' : event === TaskStart ? 'tasks' : 'prompt');
|
|
45
|
+
const answerPermissions = (event, answer) => [
|
|
46
|
+
...(Object.keys(answer).some((key) => key !== 'note') ? [beforePermission(event)] : []),
|
|
47
|
+
...(answer.note === undefined ? [] : ['prompt']),
|
|
48
|
+
];
|
|
39
49
|
export const isAct = (action) => action === 'callTool' || action in actPermissions;
|
|
40
50
|
export function toolPermission(tool) {
|
|
41
51
|
return startsTurns.includes(tool) ? 'prompt' : ownSchedule.includes(tool) ? undefined : 'tools';
|
|
@@ -46,7 +56,8 @@ export function actPermission(action, input) {
|
|
|
46
56
|
export async function usageOf(claude) {
|
|
47
57
|
const [model, usage] = await Promise.all([claude.session.model(), claude.session.usage()]);
|
|
48
58
|
const { tokens, window, percent } = usage.context;
|
|
49
|
-
|
|
59
|
+
const rateLimits = usage.rateLimits.map(({ kind, percentUsed, resetsAt }) => ({ type: kind, percent: percentUsed, ...(resetsAt === undefined ? {} : { resetsAt }) }));
|
|
60
|
+
return { model, contextWindow: { ...(tokens === undefined ? {} : { tokenCount: tokens }), size: window, ...(percent === undefined ? {} : { percent }) }, rateLimits, ...(usage.cost === undefined ? {} : { cost: { usd: usage.cost.usd } }) };
|
|
50
61
|
}
|
|
51
62
|
export function payloadOf(change) {
|
|
52
63
|
if (change.type === Message)
|
|
@@ -56,8 +67,9 @@ export function payloadOf(change) {
|
|
|
56
67
|
if ('context' in change)
|
|
57
68
|
return change.context;
|
|
58
69
|
if ('task' in change) {
|
|
59
|
-
const { id, title, agentType, model, openedBy, openedAt, closedAt } = change.task;
|
|
60
|
-
|
|
70
|
+
const { id, title, agentType, model, openedBy, openedAt, closedAt, isBackground, forkedFrom } = change.task;
|
|
71
|
+
const owner = { id, title, ...(agentType === undefined ? {} : { agentType }), ...(model === undefined ? {} : { model }), ...(forkedFrom === undefined ? {} : { forkedFrom }), startedAt: openedAt };
|
|
72
|
+
return { id, title, openedBy, openedAt, ...(closedAt === undefined ? {} : { closedAt }), ...(isBackground === true ? { isBackground } : {}), owner };
|
|
61
73
|
}
|
|
62
74
|
if ('usage' in change)
|
|
63
75
|
return change.usage;
|
|
@@ -123,6 +135,8 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
123
135
|
const parents = new Map();
|
|
124
136
|
const known = new Map();
|
|
125
137
|
let current = { id: '', title: '', project: '', cwd: '', model: '', startedAt: '', lastAt: '', isRunning: true };
|
|
138
|
+
let told = { session: '' };
|
|
139
|
+
const colored = ({ color: _color, ...data }) => (told.session === data.id && told.color !== undefined ? { ...data, color: told.color } : data);
|
|
126
140
|
const keyOf = (scope) => scope.session ?? everySession;
|
|
127
141
|
const subscribe = (key) => {
|
|
128
142
|
if (queued.has(key))
|
|
@@ -195,9 +209,12 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
195
209
|
return undefined;
|
|
196
210
|
const payload = await payloadFor(session, latest);
|
|
197
211
|
const answer = await invoke(entry.method, entry.options, async (time) => takenAnswer(entry.method, beforeAnswerKeys[event], await entry.listener(payload, time)), beforeAnswerKeys[event]);
|
|
198
|
-
if (answer === undefined || answer === null || (typeof answer === 'object' && 'refuse' in answer)
|
|
212
|
+
if (answer === undefined || answer === null || (typeof answer === 'object' && 'refuse' in answer))
|
|
213
|
+
return answer;
|
|
214
|
+
const missing = answerPermissions(event, answer).find((permission) => !isGranted(permission));
|
|
215
|
+
if (missing === undefined)
|
|
199
216
|
return answer;
|
|
200
|
-
throw new Error(`Its ${entry.method} answer changes nothing until you grant ${name} "${permissionWords(
|
|
217
|
+
throw new Error(`Its ${entry.method} answer changes nothing until you grant ${name} "${permissionWords(missing)}". ${grantFix}`);
|
|
201
218
|
});
|
|
202
219
|
const answer = await foldBefore(event, change, askers, (error) => report(`session:${methodOf('before', event)}`, `The ${methodOf('before', event)} listener failed`, error));
|
|
203
220
|
return answer?.note === undefined ? answer : { ...answer, note: modNote(name, answer.note) };
|
|
@@ -262,17 +279,25 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
262
279
|
turns: async () => (await call(conversationMethods.turns, { ...owned, context: data.number })).map((turn) => turnOf(owned, turn)),
|
|
263
280
|
};
|
|
264
281
|
};
|
|
265
|
-
const taskOf = (session, data) =>
|
|
266
|
-
id: data.id
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
282
|
+
const taskOf = (session, data) => {
|
|
283
|
+
const record = data.isBackground === true ? { session: data.id } : { session, task: data.id };
|
|
284
|
+
return {
|
|
285
|
+
id: data.id,
|
|
286
|
+
title: data.title,
|
|
287
|
+
openedBy: data.openedBy,
|
|
288
|
+
openedAt: data.openedAt,
|
|
289
|
+
...(data.closedAt === undefined ? {} : { closedAt: data.closedAt }),
|
|
290
|
+
...(data.status === undefined ? {} : { status: data.status }),
|
|
291
|
+
...(data.name === undefined ? {} : { name: data.name }),
|
|
292
|
+
...(data.spawnedBy === undefined ? {} : { spawnedBy: data.spawnedBy }),
|
|
293
|
+
...(data.isBackground === true ? { isBackground: true } : {}),
|
|
294
|
+
owner: ownerOf(session, data),
|
|
295
|
+
...recordPart({ session, task: data.id }),
|
|
296
|
+
search: (text, matcher) => searched({ text, ...record }, matcher),
|
|
297
|
+
tasks: async () => (await call(conversationMethods.tasks, record)).map((task) => taskOf(record.session, task)),
|
|
298
|
+
messages: () => messagesFrom(conversationMethods.messages, record),
|
|
299
|
+
};
|
|
300
|
+
};
|
|
276
301
|
const goalOf = (where) => ({
|
|
277
302
|
search: (text, matcher) => searched({ text, ...where() }, matcher),
|
|
278
303
|
...eventMethods(() => ({ ...where(), isGoal: true }), true),
|
|
@@ -317,9 +342,8 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
317
342
|
if ('drop' in submitted && typeof submitted.drop === 'string')
|
|
318
343
|
throw new Error(`${name}: Claude Code dropped the prompt: ${submitted.drop}`);
|
|
319
344
|
};
|
|
320
|
-
const startHere = async (task) => taskOf(current.id, await spawnTask(claude, task).catch((error) => Promise.reject(new Error(`${name}: ${messageOf(error)}`))));
|
|
321
345
|
const surfacesHere = async () => [...(await claude.session.surfaces())];
|
|
322
|
-
const sessionOf = (read, owned) => {
|
|
346
|
+
const sessionOf = (read, owned, isOwner = owned !== undefined) => {
|
|
323
347
|
const id = () => read().id;
|
|
324
348
|
const isHere = () => owned === undefined && id() === current.id;
|
|
325
349
|
const scope = () => (owned === undefined ? { session: id(), isAgent: true } : { session: owned.session, task: owned.task, isAgent: true });
|
|
@@ -333,6 +357,9 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
333
357
|
get title() {
|
|
334
358
|
return read().title;
|
|
335
359
|
},
|
|
360
|
+
get color() {
|
|
361
|
+
return read().color;
|
|
362
|
+
},
|
|
336
363
|
get project() {
|
|
337
364
|
return read().project;
|
|
338
365
|
},
|
|
@@ -384,31 +411,31 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
384
411
|
await act(id(), 'send', message, owned);
|
|
385
412
|
},
|
|
386
413
|
};
|
|
387
|
-
if (
|
|
414
|
+
if (isOwner)
|
|
388
415
|
return session;
|
|
416
|
+
const started = async (starting) => taskOf(id(), await starting.catch((error) => Promise.reject(new Error(`${name}: ${messageOf(error)}`))));
|
|
389
417
|
return Object.assign(session, {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const started = await act(id(), 'startTask', task);
|
|
394
|
-
return taskOf(id(), started);
|
|
395
|
-
},
|
|
418
|
+
startTask: (task) => started(task.isBackground === true ? act(id(), 'startBackgroundTask', task) : isHere() ? spawnTask(claude, task) : act(id(), 'startTask', task)),
|
|
419
|
+
fork: (task) => started(isHere() ? spawnTask(claude, task, current.id) : act(id(), 'fork', task)),
|
|
420
|
+
clone: (task) => started(act(id(), 'clone', task)),
|
|
396
421
|
callTool: async (toolCall) => (await withFiles(await act(id(), 'callTool', toolCall))),
|
|
397
422
|
});
|
|
398
423
|
};
|
|
399
424
|
const ownerOf = (session, data) => {
|
|
400
425
|
const parent = session === current.id ? current : known.get(session);
|
|
426
|
+
const isBackground = data.isBackground === true;
|
|
401
427
|
return sessionOf(() => ({
|
|
402
428
|
id: data.id,
|
|
403
429
|
title: data.title,
|
|
404
430
|
project: parent?.project ?? '',
|
|
405
|
-
agentType: data.agentType,
|
|
431
|
+
...(data.agentType === undefined ? {} : { agentType: data.agentType }),
|
|
406
432
|
model: data.model ?? '',
|
|
407
433
|
cwd: parent?.cwd ?? '',
|
|
408
|
-
isRunning: data.closedAt === undefined && (parent?.isRunning ?? true),
|
|
434
|
+
isRunning: data.closedAt === undefined && (isBackground || (parent?.isRunning ?? true)),
|
|
409
435
|
startedAt: data.openedAt,
|
|
410
436
|
lastAt: data.closedAt ?? data.openedAt,
|
|
411
|
-
|
|
437
|
+
...(data.forkedFrom === undefined ? {} : { forkedFrom: data.forkedFrom }),
|
|
438
|
+
}), isBackground ? undefined : { session, task: data.id }, true);
|
|
412
439
|
};
|
|
413
440
|
const processListeners = new Map();
|
|
414
441
|
const processHearers = (method, payload) => [...(processListeners.get(method) ?? [])].filter(({ matcher, isEveryAgent }) => (payload['task'] === undefined || isEveryAgent) && (matcher === undefined || matches(payload, matcher)));
|
|
@@ -464,7 +491,12 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
464
491
|
const event = processEvents[named];
|
|
465
492
|
const hook = (isBefore ? event.before : undefined) ?? event.on;
|
|
466
493
|
if (method === 'beforeSessionStart')
|
|
467
|
-
routeOn('session.compact',
|
|
494
|
+
routeOn('session.compact', trackCompaction);
|
|
495
|
+
if (method === 'beforeModelChange')
|
|
496
|
+
hookOn(event.on, () => {
|
|
497
|
+
const notes = modelNotes.splice(0);
|
|
498
|
+
return notes.length === 0 ? undefined : { additionalContext: notes };
|
|
499
|
+
});
|
|
468
500
|
const failed = (input, error) => {
|
|
469
501
|
const refusal = refusalFor(method, processPayloadOf(named, input), error);
|
|
470
502
|
return refusal === undefined ? undefined : hookAnswerOf(name, named, refusal);
|
|
@@ -472,34 +504,40 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
472
504
|
return hookOn(hook, async (input) => {
|
|
473
505
|
const payload = processPayloadOf(named, input);
|
|
474
506
|
if (named === 'SessionStart' && payload['source'] === 'compact') {
|
|
475
|
-
|
|
476
|
-
|
|
507
|
+
if (!isBefore)
|
|
508
|
+
return undefined;
|
|
509
|
+
const task = compacting?.agentId;
|
|
510
|
+
const model = task === undefined ? await claude.session.model() : undefined;
|
|
511
|
+
const answer = await raise(method, { ...payload, ...defined({ task, model, title: current.title || undefined }) });
|
|
512
|
+
if (answer === undefined)
|
|
513
|
+
return undefined;
|
|
514
|
+
return hookAnswerOf(name, named, task === undefined ? answer : defined({ note: answer['note'] }));
|
|
477
515
|
}
|
|
478
516
|
if (!isBefore) {
|
|
479
517
|
void raise(method, payload);
|
|
480
518
|
return undefined;
|
|
481
519
|
}
|
|
520
|
+
if (named === 'ModelChange')
|
|
521
|
+
modelNotes.splice(0);
|
|
482
522
|
const answer = await raise(method, payload);
|
|
483
|
-
|
|
523
|
+
if (answer === undefined)
|
|
524
|
+
return undefined;
|
|
525
|
+
if (named === 'ModelChange' && typeof answer['note'] === 'string' && answer['refuse'] === undefined)
|
|
526
|
+
modelNotes.push(modNote(name, answer['note']));
|
|
527
|
+
return hookAnswerOf(name, named, answer);
|
|
484
528
|
}, isBefore ? failed : undefined);
|
|
485
529
|
};
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (typeof note !== 'string')
|
|
497
|
-
return compacted;
|
|
498
|
-
if (!isGranted('prompt')) {
|
|
499
|
-
report('session:beforeSessionStart', 'The beforeSessionStart listener failed', new Error(`${name}: its note adds text Claude reads, which needs the prompt permission.`));
|
|
500
|
-
return compacted;
|
|
530
|
+
const modelNotes = [];
|
|
531
|
+
let compacting;
|
|
532
|
+
const trackCompaction = async (e, next) => {
|
|
533
|
+
compacting = e;
|
|
534
|
+
try {
|
|
535
|
+
return await next(e);
|
|
536
|
+
}
|
|
537
|
+
finally {
|
|
538
|
+
if (compacting === e)
|
|
539
|
+
compacting = undefined;
|
|
501
540
|
}
|
|
502
|
-
return { ...compacted, messages: [...compacted.messages, { role: 'user', text: modNote(name, note), toolUses: [] }] };
|
|
503
541
|
};
|
|
504
542
|
const listen = (method, args, isEveryAgent = false) => {
|
|
505
543
|
const heard = listenerOf(name, method, args);
|
|
@@ -568,7 +606,7 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
568
606
|
follow(next) {
|
|
569
607
|
const moved = next.id !== current.id && current.id !== '';
|
|
570
608
|
const previous = current.id;
|
|
571
|
-
current = { ...next, title: next.title || (next.id === current.id ? current.title : ''), isRunning: true, lastAt: new Date().toISOString() };
|
|
609
|
+
current = colored({ ...next, title: next.title || (next.id === current.id ? current.title : ''), isRunning: true, lastAt: new Date().toISOString() });
|
|
572
610
|
if (!moved)
|
|
573
611
|
return;
|
|
574
612
|
for (const into of [listening, deciding]) {
|
|
@@ -585,6 +623,10 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
585
623
|
subscribe(previous);
|
|
586
624
|
subscribe(current.id);
|
|
587
625
|
},
|
|
626
|
+
recolor(next) {
|
|
627
|
+
told = next;
|
|
628
|
+
current = colored(current);
|
|
629
|
+
},
|
|
588
630
|
};
|
|
589
631
|
}
|
|
590
632
|
export const recordOf = (value) => (typeof value === 'object' && value !== null && !Array.isArray(value) ? value : {});
|
|
@@ -604,9 +646,9 @@ const modelChangeOf = (input) => ({
|
|
|
604
646
|
});
|
|
605
647
|
const answerKeys = {
|
|
606
648
|
Run: ['args', 'note', 'result', 'exitCode', 'refuse'],
|
|
607
|
-
ProjectSetup: [],
|
|
649
|
+
ProjectSetup: ['note'],
|
|
608
650
|
SessionStart: ['note', 'title', 'reloadSkills', 'firstPrompt'],
|
|
609
|
-
ModelChange: ['ask', 'refuse'],
|
|
651
|
+
ModelChange: ['ask', 'refuse', 'note'],
|
|
610
652
|
WorktreeCreate: ['result'],
|
|
611
653
|
Elicitation: ['refuse'],
|
|
612
654
|
ElicitationResponse: ['refuse'],
|
|
@@ -651,22 +693,23 @@ const processFields = {
|
|
|
651
693
|
TodoComplete: todoOf,
|
|
652
694
|
ReplyDisplay: (input) => ({ replyId: input['message_id'], index: input['index'], isLast: input['final'], text: input['delta'] }),
|
|
653
695
|
};
|
|
654
|
-
export async function spawnTask(claude, task) {
|
|
696
|
+
export async function spawnTask(claude, task, forkedFrom) {
|
|
655
697
|
if (task.title.trim() === '')
|
|
656
698
|
throw new Error('a task needs a title.');
|
|
699
|
+
const { name, agentType, model, cwd } = forkedFrom === undefined ? task : { prompt: task.prompt, title: task.title, agentType: forkAgentType };
|
|
657
700
|
const started = await claude.agent.spawn({
|
|
658
701
|
prompt: task.prompt,
|
|
659
702
|
description: task.title,
|
|
660
|
-
...(
|
|
661
|
-
...(
|
|
662
|
-
...(
|
|
663
|
-
...(
|
|
703
|
+
...(name === undefined ? {} : { name }),
|
|
704
|
+
...(agentType === undefined ? {} : { subagentType: agentType }),
|
|
705
|
+
...(model === undefined ? {} : { model }),
|
|
706
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
664
707
|
});
|
|
665
708
|
if (started.deny !== undefined)
|
|
666
709
|
throw new Error(`Claude Code refused the task: ${started.deny}`);
|
|
667
710
|
if (started.agentId === undefined)
|
|
668
711
|
throw new Error('Claude Code answered without starting a task.');
|
|
669
|
-
return { id: started.agentId, title: task.title, agentType:
|
|
712
|
+
return { id: started.agentId, title: task.title, ...(forkedFrom === undefined ? { agentType: agentType ?? 'general-purpose' } : { forkedFrom }), model: started.model, openedBy: '', openedAt: new Date().toISOString() };
|
|
670
713
|
}
|
|
671
714
|
export function processPayloadOf(named, input) {
|
|
672
715
|
const fields = recordOf(input);
|
|
@@ -682,6 +725,8 @@ function hookAnswerOf(name, named, answer) {
|
|
|
682
725
|
return { permissionDecision: 'deny', permissionDecisionReason: refuse };
|
|
683
726
|
return typeof answer['ask'] === 'string' ? { permissionDecision: 'ask', permissionDecisionReason: answer['ask'] } : undefined;
|
|
684
727
|
}
|
|
728
|
+
if (named === 'ProjectSetup')
|
|
729
|
+
return defined({ additionalContext: note });
|
|
685
730
|
if (named === 'WorktreeCreate')
|
|
686
731
|
return defined({ worktreePath: answer['result'] });
|
|
687
732
|
if (named === 'PermissionDenial')
|
package/runtime/toaster.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../src/runtime/toaster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAS,MAAM,aAAa,CAAA;AACpF,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAgB,SAAS,EAAE,MAAM,WAAW,CAAA;AAIxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9G,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,CAAA;CAAE,CAAA;AAEhK,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAAA;CACnH,CAAA;
|
|
1
|
+
{"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../src/runtime/toaster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAS,MAAM,aAAa,CAAA;AACpF,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAgB,SAAS,EAAE,MAAM,WAAW,CAAA;AAIxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9G,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,CAAA;CAAE,CAAA;AAEhK,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAAA;CACnH,CAAA;AA2CD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,SAAS,EAAE,eAAe,EAAE,MAAM,OAAO,GAAG,OAAO,CA+QtI"}
|
package/runtime/toaster.js
CHANGED
|
@@ -8,6 +8,8 @@ const defaultDuration = 4000;
|
|
|
8
8
|
const visibleToasts = 3;
|
|
9
9
|
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
10
10
|
const spinnerMs = 100;
|
|
11
|
+
const spinFrames = 10_000 / spinnerMs;
|
|
12
|
+
const still = '…';
|
|
11
13
|
const icons = {
|
|
12
14
|
default: { glyph: ' ' },
|
|
13
15
|
success: { glyph: '✓', color: 'success' },
|
|
@@ -31,15 +33,19 @@ export function createToaster(claude, name, version, openPermissions) {
|
|
|
31
33
|
let isHeld = false;
|
|
32
34
|
let showsAll = false;
|
|
33
35
|
let bandId;
|
|
36
|
+
const isLoading = (entry) => entry.type === 'loading' || entry.trying !== undefined;
|
|
37
|
+
const isSpinning = (entry) => entry.spinsFrom !== undefined && frame - entry.spinsFrom < spinFrames;
|
|
34
38
|
const changed = () => {
|
|
35
|
-
const
|
|
36
|
-
|
|
39
|
+
for (const entry of entries.values())
|
|
40
|
+
entry.spinsFrom = isLoading(entry) ? (entry.spinsFrom ?? frame) : undefined;
|
|
41
|
+
const spins = [...entries.values()].some(isSpinning);
|
|
42
|
+
if (spins && spinning === undefined) {
|
|
37
43
|
spinning = claude.clock.every(spinnerMs, () => {
|
|
38
44
|
frame += 1;
|
|
39
|
-
|
|
45
|
+
changed();
|
|
40
46
|
});
|
|
41
47
|
}
|
|
42
|
-
if (!
|
|
48
|
+
if (!spins && spinning !== undefined) {
|
|
43
49
|
spinning.cancel();
|
|
44
50
|
spinning = undefined;
|
|
45
51
|
}
|
|
@@ -83,7 +89,7 @@ export function createToaster(claude, name, version, openPermissions) {
|
|
|
83
89
|
if (previous !== undefined)
|
|
84
90
|
disarm(previous);
|
|
85
91
|
const reporting = hides !== undefined && previous?.hides === hides ? previous.reporting : undefined;
|
|
86
|
-
const entry = { id, type, message, options, actions, ...(hides === undefined ? {} : { hides }), isOpen: previous?.isOpen ?? false, reporting, timer: undefined };
|
|
92
|
+
const entry = { id, type, message, options, actions, ...(hides === undefined ? {} : { hides }), at: new Date(), isOpen: previous?.isOpen ?? false, reporting, timer: undefined };
|
|
87
93
|
if (type === 'error' && previous?.message !== message)
|
|
88
94
|
claude.ui.log(`${name}: ${message}${typeof options.description === 'string' ? `: ${options.description}` : ''}`, { to: 'debug' });
|
|
89
95
|
entries.set(id, entry);
|
|
@@ -134,15 +140,20 @@ export function createToaster(claude, name, version, openPermissions) {
|
|
|
134
140
|
return id;
|
|
135
141
|
hidden.delete(id);
|
|
136
142
|
const shown = entries.get(id);
|
|
137
|
-
if (shown?.hides === hides && shown.trying === undefined && shown.options.description === description)
|
|
143
|
+
if (shown?.hides === hides && shown.trying === undefined && shown.options.description === description) {
|
|
144
|
+
const previous = clockTime(shown.at);
|
|
145
|
+
shown.at = new Date();
|
|
146
|
+
if (clockTime(shown.at) !== previous)
|
|
147
|
+
changed();
|
|
138
148
|
return id;
|
|
149
|
+
}
|
|
139
150
|
const stack = error instanceof Error && error.stack !== undefined ? `\n\n${error.stack}` : '';
|
|
140
151
|
const details = async () => {
|
|
141
152
|
const modVersion = await claude.fs
|
|
142
153
|
.read(`${claude.plugin.root}/.claude-plugin/plugin.json`)
|
|
143
154
|
.then((text) => String(JSON.parse(text).version))
|
|
144
155
|
.catch((failure) => `unknown (${messageOf(failure)})`);
|
|
145
|
-
return `${name} ${modVersion}, @cmodjs/core ${coreVersion}\n${message}${description === undefined ? '' : `\n${description}`}${stack}`;
|
|
156
|
+
return `${name} ${modVersion}, @cmodjs/core ${coreVersion}, at ${(entries.get(id)?.at ?? new Date()).toISOString()}\n${message}${description === undefined ? '' : `\n${description}`}${stack}`;
|
|
146
157
|
};
|
|
147
158
|
const startReporting = async () => {
|
|
148
159
|
const shown = entries.get(id);
|
|
@@ -190,13 +201,13 @@ export function createToaster(claude, name, version, openPermissions) {
|
|
|
190
201
|
const row = (entry) => {
|
|
191
202
|
const { description } = entry.options;
|
|
192
203
|
const isText = typeof description === 'string';
|
|
193
|
-
const icon = entry.type === 'loading' || entry.trying !== undefined ? { glyph: spinner[frame % spinner.length], color: 'claude' } : icons[entry.type];
|
|
204
|
+
const icon = entry.type === 'loading' || entry.trying !== undefined ? { glyph: isSpinning(entry) ? spinner[frame % spinner.length] : still, color: 'claude' } : icons[entry.type];
|
|
194
205
|
const message = isText ? Button({ plain: true, key: `toast:${entry.id}:open`, label: entry.message, onPress: toggle(entry) }) : Text({ children: entry.message });
|
|
195
206
|
const details = !isText ? description : Text({ dimColor: true, wrap: entry.isOpen ? 'wrap' : 'truncate-end', children: entry.isOpen ? description : firstLine(description) });
|
|
196
207
|
const fixed = (child) => Box({ flexShrink: 0, children: child });
|
|
197
208
|
const close = Button({ plain: true, dimColor: true, key: `toast:${entry.id}:close`, label: entry.hides === undefined ? '✕' : 'Hide', onPress: () => hide(entry) });
|
|
198
209
|
const actions = entry.actions.map((action, index) => Button({ plain: true, key: `toast:${entry.id}:${index === 0 ? 'action' : `action-${index}`}`, label: action.label, onPress: press(entry, action.onClick) }));
|
|
199
|
-
const buttons = Box({ gap: 2, flexWrap: 'wrap', children: [...actions, close] });
|
|
210
|
+
const buttons = Box({ gap: 2, flexWrap: 'wrap', children: [...actions, close, Text({ dimColor: true, children: clockTime(entry.at) })].map(fixed) });
|
|
200
211
|
const trying = entry.trying === undefined ? undefined : Box({ gap: 1, children: [Text({ dimColor: true, children: 'Trying again:' }), typeof entry.trying === 'string' ? Text({ dimColor: true, wrap: 'truncate-end', children: entry.trying }) : entry.trying] });
|
|
201
212
|
const text = details === undefined ? [message] : [message, trying ?? details];
|
|
202
213
|
const under = trying !== undefined && details === undefined ? [trying] : entry.reporting === undefined ? [buttons] : reportChoices(entry, entry.reporting);
|
|
@@ -316,3 +327,6 @@ function reportPrompt(name, contact, details) {
|
|
|
316
327
|
: `Email it to ${contact.address}.`;
|
|
317
328
|
return `The ${name} mod failed. Report it to its author. ${where} First check whether it is reported already, and add to that report instead of filing a new one. Show me the report before you post it.\n\n${details}`;
|
|
318
329
|
}
|
|
330
|
+
function clockTime(at) {
|
|
331
|
+
return `${String(at.getHours()).padStart(2, '0')}:${String(at.getMinutes()).padStart(2, '0')}`;
|
|
332
|
+
}
|
package/runtime/ui.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { Args, ElementTable, Frozen, MarkdownProps, RenderElement } from 'claude-code';
|
|
1
2
|
import type { Mod, Turn } from '../mod.js';
|
|
2
|
-
import { type Area } from '../ui/areas.js';
|
|
3
|
+
import { type Area, type WidgetInit } from '../ui/areas.js';
|
|
3
4
|
import { type ScrollOptions, type ScrollTarget } from '../ui/panes.js';
|
|
5
|
+
import { type StyledAt } from '../ui/styles.js';
|
|
4
6
|
import type { Claude } from './claude.js';
|
|
5
7
|
import type { Router } from './router.js';
|
|
6
8
|
import type { Failure } from './toaster.js';
|
|
@@ -10,12 +12,15 @@ export declare const partMethods: {
|
|
|
10
12
|
readonly press: 'cmod:press';
|
|
11
13
|
readonly shown: 'cmod:shown';
|
|
12
14
|
readonly changed: 'cmod:partsChanged';
|
|
15
|
+
readonly stylers: 'cmod:markdownStylers';
|
|
13
16
|
};
|
|
17
|
+
export declare const stalePress = "that button drew before the last redraw. Press the one it shows now.";
|
|
14
18
|
export type PagePlace = 'sidebar' | 'settings';
|
|
15
19
|
export type WidgetDeclaration = {
|
|
16
20
|
readonly id: string;
|
|
17
21
|
readonly title: string;
|
|
18
22
|
readonly areas: readonly Area[];
|
|
23
|
+
readonly place?: NonNullable<WidgetInit['place']>;
|
|
19
24
|
};
|
|
20
25
|
export type PageDeclaration = {
|
|
21
26
|
readonly id: string;
|
|
@@ -25,6 +30,7 @@ export type PageDeclaration = {
|
|
|
25
30
|
export type PartList = {
|
|
26
31
|
readonly widgets: readonly WidgetDeclaration[];
|
|
27
32
|
readonly pages: readonly PageDeclaration[];
|
|
33
|
+
readonly stylesMarkdown?: true;
|
|
28
34
|
};
|
|
29
35
|
export type PartDraw = {
|
|
30
36
|
readonly widget: string;
|
|
@@ -36,7 +42,14 @@ export type PartDraw = {
|
|
|
36
42
|
readonly params: unknown;
|
|
37
43
|
readonly columns: number;
|
|
38
44
|
readonly isFocused: boolean;
|
|
39
|
-
}
|
|
45
|
+
} | ({
|
|
46
|
+
readonly markdown: string;
|
|
47
|
+
} & StyledAt);
|
|
48
|
+
export type BorrowedMarkdown = (mod: string, cached: string, input: {
|
|
49
|
+
readonly markdown: string;
|
|
50
|
+
} & StyledAt) => RenderElement | undefined;
|
|
51
|
+
export declare function viewportColumns(e: Frozen<Args<'ui.render'>>): number;
|
|
52
|
+
export declare function styledAt(e: Frozen<Args<'ui.render'>>, columns?: number): StyledAt;
|
|
40
53
|
export type PartPress = {
|
|
41
54
|
readonly draw: number;
|
|
42
55
|
readonly handler: number;
|
|
@@ -75,6 +88,7 @@ export type ShownPages = {
|
|
|
75
88
|
readonly shown: string | null;
|
|
76
89
|
readonly isFocused: boolean;
|
|
77
90
|
};
|
|
91
|
+
export declare function merged(updates: readonly PartsUpdate[]): PartsUpdate;
|
|
78
92
|
export type UiOptions<State extends object> = {
|
|
79
93
|
readonly name: string;
|
|
80
94
|
readonly claude: Claude;
|
|
@@ -82,6 +96,8 @@ export type UiOptions<State extends object> = {
|
|
|
82
96
|
readonly report: (failure: Failure) => void;
|
|
83
97
|
readonly announce: (feature: string) => void;
|
|
84
98
|
readonly mod: () => Mod<State>;
|
|
99
|
+
readonly borrowed: BorrowedMarkdown;
|
|
100
|
+
readonly nextDraw: () => number;
|
|
85
101
|
};
|
|
86
102
|
export type UiArea<State extends object> = {
|
|
87
103
|
readonly panes: Mod<State>['panes'];
|
|
@@ -91,12 +107,14 @@ export type UiArea<State extends object> = {
|
|
|
91
107
|
readonly styles: Mod<State>['styles'];
|
|
92
108
|
asked<Value>(run: () => Value | Promise<Value>): Promise<Value>;
|
|
93
109
|
answerInput<Answer>(run: () => Promise<Answer>, passOn: () => Promise<unknown>): Promise<Answer>;
|
|
94
|
-
answer(method: string, input: unknown): Promise<{
|
|
110
|
+
answer(method: string, input: unknown, caller: string): Promise<{
|
|
95
111
|
readonly value: unknown;
|
|
96
112
|
}> | undefined;
|
|
113
|
+
markdownIn(table: ElementTable, at: StyledAt): ((props: MarkdownProps) => RenderElement) | undefined;
|
|
114
|
+
restyled(stylers: readonly string[]): void;
|
|
97
115
|
started(): void;
|
|
98
116
|
changed(): void;
|
|
99
117
|
restorePanes(): Promise<void>;
|
|
100
118
|
};
|
|
101
|
-
export declare function createUi<State extends object>({ name, claude, router, report, announce, mod }: UiOptions<State>): UiArea<State>;
|
|
119
|
+
export declare function createUi<State extends object>({ name, claude, router, report, announce, mod, borrowed, nextDraw }: UiOptions<State>): UiArea<State>;
|
|
102
120
|
//# sourceMappingURL=ui.d.ts.map
|
package/runtime/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/runtime/ui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/runtime/ui.ts"],"names":[],"mappings":"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"}
|