@cmodjs/core 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/commands.md +39 -22
- package/docs/dependencies.md +27 -20
- package/docs/index.md +21 -17
- package/docs/install-steps.md +37 -29
- package/docs/jobs.md +25 -52
- package/docs/mod.md +94 -66
- package/docs/options.md +2 -2
- package/docs/permissions.md +7 -5
- package/docs/session.md +14 -12
- package/docs/testing.md +55 -32
- package/docs/ui.md +255 -263
- package/hotkeys.d.ts +22 -0
- package/hotkeys.d.ts.map +1 -0
- package/hotkeys.js +26 -0
- package/installer.d.ts +1 -1
- package/installer.d.ts.map +1 -1
- package/installer.js +11 -6
- package/jobs/check.d.ts +2 -1
- package/jobs/check.d.ts.map +1 -1
- package/jobs/check.js +2 -2
- package/jobs/context.d.ts +2 -1
- package/jobs/context.d.ts.map +1 -1
- package/jobs/context.js +1 -1
- package/jobs/permissions.d.ts +2 -1
- package/jobs/permissions.d.ts.map +1 -1
- package/jobs/permissions.js +2 -2
- package/jobs/program.js +1 -1
- package/jobs/prompt.d.ts +2 -1
- package/jobs/prompt.d.ts.map +1 -1
- package/jobs/prompt.js +20 -13
- package/jobs/schedule.d.ts +2 -1
- package/jobs/schedule.d.ts.map +1 -1
- package/jobs/schedule.js +15 -1
- package/jobs/slash-command.d.ts +6 -2
- package/jobs/slash-command.d.ts.map +1 -1
- package/jobs/slash-command.js +6 -5
- package/jobs/tool.d.ts +6 -4
- package/jobs/tool.d.ts.map +1 -1
- package/jobs/tool.js +3 -3
- package/mod.d.ts +63 -42
- package/mod.d.ts.map +1 -1
- package/mod.js +11 -1
- package/package.json +1 -1
- package/records.d.ts +14 -8
- package/records.d.ts.map +1 -1
- package/records.js +44 -31
- package/register.d.ts.map +1 -1
- package/register.js +1 -2
- package/runtime/announce.d.ts +1 -1
- package/runtime/announce.d.ts.map +1 -1
- package/runtime/announce.js +6 -7
- package/runtime/before.d.ts +2 -2
- package/runtime/before.d.ts.map +1 -1
- package/runtime/before.js +1 -1
- package/runtime/claude.d.ts +0 -1
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/conversations.d.ts +4 -1
- package/runtime/conversations.d.ts.map +1 -1
- package/runtime/conversations.js +42 -14
- package/runtime/dependencies.d.ts.map +1 -1
- package/runtime/dependencies.js +2 -1
- package/runtime/engine.d.ts +5 -0
- package/runtime/engine.d.ts.map +1 -1
- package/runtime/grants.js +2 -2
- package/runtime/hooks.d.ts +1 -1
- package/runtime/hooks.d.ts.map +1 -1
- package/runtime/hotkeys.d.ts +15 -0
- package/runtime/hotkeys.d.ts.map +1 -0
- package/runtime/hotkeys.js +58 -0
- package/runtime/installer.d.ts +5 -2
- package/runtime/installer.d.ts.map +1 -1
- package/runtime/installer.js +23 -12
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +190 -141
- package/runtime/options.js +2 -2
- package/runtime/pages.d.ts +28 -0
- package/runtime/pages.d.ts.map +1 -0
- package/runtime/pages.js +98 -0
- package/runtime/parts.d.ts +14 -0
- package/runtime/parts.d.ts.map +1 -0
- package/runtime/parts.js +63 -0
- package/runtime/permission-check.d.ts +2 -2
- package/runtime/permission-check.d.ts.map +1 -1
- package/runtime/permission-check.js +12 -4
- package/runtime/programs.js +1 -1
- package/runtime/router.d.ts +2 -2
- package/runtime/router.d.ts.map +1 -1
- package/runtime/router.js +1 -1
- package/runtime/sessions.d.ts +10 -9
- package/runtime/sessions.d.ts.map +1 -1
- package/runtime/sessions.js +14 -5
- package/runtime/state.d.ts +2 -1
- package/runtime/state.d.ts.map +1 -1
- package/runtime/state.js +1 -0
- package/runtime/toaster.d.ts +1 -1
- package/runtime/toaster.d.ts.map +1 -1
- package/runtime/toaster.js +10 -4
- package/runtime/ui.d.ts +87 -5
- package/runtime/ui.d.ts.map +1 -1
- package/runtime/ui.js +372 -109
- package/runtime/watches.d.ts +9 -0
- package/runtime/watches.d.ts.map +1 -0
- package/runtime/watches.js +73 -0
- package/runtime/widgets.d.ts +48 -0
- package/runtime/widgets.d.ts.map +1 -0
- package/runtime/widgets.js +219 -0
- package/session/context/turn/message/message.d.ts.map +1 -1
- package/session/context/turn/message/message.js +7 -2
- package/session/session.d.ts +11 -5
- package/session/session.d.ts.map +1 -1
- package/src/hotkeys.ts +51 -0
- package/src/installer.ts +8 -4
- package/src/jobs/check.ts +4 -3
- package/src/jobs/context.ts +3 -2
- package/src/jobs/permissions.ts +4 -3
- package/src/jobs/program.ts +1 -1
- package/src/jobs/prompt.ts +23 -14
- package/src/jobs/schedule.ts +16 -2
- package/src/jobs/slash-command.ts +10 -7
- package/src/jobs/tool.ts +7 -5
- package/src/mod.ts +59 -47
- package/src/records.ts +50 -31
- package/src/register.ts +2 -3
- package/src/runtime/announce.ts +6 -7
- package/src/runtime/before.ts +4 -4
- package/src/runtime/claude.ts +0 -1
- package/src/runtime/conversations.ts +66 -20
- package/src/runtime/dependencies.ts +2 -1
- package/src/runtime/engine.ts +5 -0
- package/src/runtime/grants.ts +2 -2
- package/src/runtime/hooks.ts +1 -0
- package/src/runtime/hotkeys.ts +80 -0
- package/src/runtime/installer.ts +24 -12
- package/src/runtime/lifecycle.ts +189 -136
- package/src/runtime/options.ts +2 -2
- package/src/runtime/pages.ts +127 -0
- package/src/runtime/parts.ts +72 -0
- package/src/runtime/permission-check.ts +13 -5
- package/src/runtime/programs.ts +1 -1
- package/src/runtime/router.ts +3 -3
- package/src/runtime/sessions.ts +24 -15
- package/src/runtime/state.ts +3 -1
- package/src/runtime/toaster.ts +10 -4
- package/src/runtime/ui.ts +405 -115
- package/src/runtime/watches.ts +75 -0
- package/src/runtime/widgets.ts +287 -0
- package/src/session/context/turn/message/message.ts +7 -2
- package/src/session/session.ts +10 -6
- package/src/testing/fake-claude.ts +9 -6
- package/src/testing/fake-elements.ts +7 -4
- package/src/testing/fake-sessions.ts +6 -4
- package/src/testing.ts +203 -46
- package/src/ui/areas.ts +27 -0
- package/src/ui/elements.ts +35 -0
- package/src/ui/markdown.ts +18 -18
- package/src/ui/panes.ts +73 -0
- package/src/ui/styles.ts +53 -0
- package/src/utils/subscription.ts +1 -0
- package/testing/fake-claude.d.ts +0 -1
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +9 -5
- package/testing/fake-elements.js +7 -4
- package/testing/fake-sessions.d.ts +2 -1
- package/testing/fake-sessions.d.ts.map +1 -1
- package/testing/fake-sessions.js +1 -0
- package/testing.d.ts +21 -6
- package/testing.d.ts.map +1 -1
- package/testing.js +206 -45
- package/ui/areas.d.ts +29 -0
- package/ui/areas.d.ts.map +1 -0
- package/ui/areas.js +6 -0
- package/ui/elements.d.ts +3 -0
- package/ui/elements.d.ts.map +1 -1
- package/ui/elements.js +36 -0
- package/ui/markdown.d.ts +14 -14
- package/ui/markdown.d.ts.map +1 -1
- package/ui/markdown.js +11 -11
- package/ui/panes.d.ts +71 -0
- package/ui/panes.d.ts.map +1 -0
- package/ui/panes.js +16 -0
- package/ui/styles.d.ts +44 -0
- package/ui/styles.d.ts.map +1 -0
- package/ui/styles.js +24 -0
- package/utils/subscription.d.ts +4 -0
- package/utils/subscription.d.ts.map +1 -0
- package/jobs/status-line.d.ts +0 -6
- package/jobs/status-line.d.ts.map +0 -1
- package/jobs/status-line.js +0 -39
- package/src/jobs/status-line.ts +0 -44
- package/src/ui/define-pane.ts +0 -27
- package/src/ui/places.ts +0 -49
- package/src/utils/disposable.ts +0 -3
- package/ui/define-pane.d.ts +0 -15
- package/ui/define-pane.d.ts.map +0 -1
- package/ui/define-pane.js +0 -12
- package/ui/places.d.ts +0 -43
- package/ui/places.d.ts.map +0 -1
- package/ui/places.js +0 -31
- package/utils/disposable.d.ts +0 -4
- package/utils/disposable.d.ts.map +0 -1
- /package/utils/{disposable.js → subscription.js} +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RenderElement } from 'claude-code';
|
|
2
|
+
import type { Claude } from './claude.js';
|
|
3
|
+
import type { DrawnParts } from './parts.js';
|
|
4
|
+
import type { Router } from './router.js';
|
|
5
|
+
import { type PageDeclaration, type PageRequest, type PartPress, type PartsUpdate, type ShownPages } from './ui.js';
|
|
6
|
+
import type { Widgets } from './widgets.js';
|
|
7
|
+
export type ModPages = {
|
|
8
|
+
readonly mod: string;
|
|
9
|
+
readonly pages: readonly PageDeclaration[];
|
|
10
|
+
};
|
|
11
|
+
export type PageApply = (mod: string, requests: readonly PageRequest[]) => Promise<void>;
|
|
12
|
+
export type Pages = {
|
|
13
|
+
declared(): readonly ModPages[];
|
|
14
|
+
element(mod: string, page: string, params: unknown, columns: number, isFocused: boolean): RenderElement | undefined;
|
|
15
|
+
press(mod: string, press: PartPress): void;
|
|
16
|
+
update(mod: string, update: PartsUpdate): boolean;
|
|
17
|
+
tell(mod: string, shown: ShownPages): void;
|
|
18
|
+
apply(listener: PageApply): void;
|
|
19
|
+
};
|
|
20
|
+
export declare function pagesOf(input: unknown): PageDeclaration[];
|
|
21
|
+
export declare function servePages({ claude, router, report, widgets, parts }: {
|
|
22
|
+
readonly claude: Claude;
|
|
23
|
+
readonly router: Router;
|
|
24
|
+
readonly report: (id: string, message: string, error: unknown) => void;
|
|
25
|
+
readonly widgets: Pick<Widgets, 'update'>;
|
|
26
|
+
readonly parts: DrawnParts;
|
|
27
|
+
}): Pages;
|
|
28
|
+
//# sourceMappingURL=pages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../src/runtime/pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAe,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAChI,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAI3C,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAA;CAAE,CAAA;AAE3F,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,WAAW,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAExF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,IAAI,SAAS,QAAQ,EAAE,CAAA;IAC/B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAAA;IACnH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAC1C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAA;IACjD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1C,KAAK,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAA;CACjC,CAAA;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,EAAE,CAGzD;AAED,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAAG,KAAK,CAiGjR"}
|
package/runtime/pages.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { isObject } from '../records.js';
|
|
2
|
+
import { messageOf } from '../utils/text.js';
|
|
3
|
+
import { partMethods } from './ui.js';
|
|
4
|
+
const askedWaitMs = 1000;
|
|
5
|
+
export function pagesOf(input) {
|
|
6
|
+
const listed = isObject(input) && Array.isArray(input['pages']) ? input['pages'] : [];
|
|
7
|
+
return listed.filter(isObject).flatMap((each) => (typeof each['id'] === 'string' && typeof each['title'] === 'string' && (each['place'] === 'sidebar' || each['place'] === 'settings') ? [{ id: each['id'], title: each['title'], place: each['place'] }] : []));
|
|
8
|
+
}
|
|
9
|
+
export function servePages({ claude, router, report, widgets, parts }) {
|
|
10
|
+
const declared = new Map();
|
|
11
|
+
const asking = new Map();
|
|
12
|
+
const pressing = new Set();
|
|
13
|
+
let waiting = [];
|
|
14
|
+
let inputDepth = 0;
|
|
15
|
+
let applyTo = async () => undefined;
|
|
16
|
+
const run = (mod, requests) => applyTo(mod, requests).catch((error) => report(`pages:${mod}`, `Could not show the page ${mod} asked for`, error));
|
|
17
|
+
const takeWaiting = async () => {
|
|
18
|
+
const taken = waiting;
|
|
19
|
+
waiting = [];
|
|
20
|
+
for (const { mod, requests } of taken)
|
|
21
|
+
await run(mod, requests);
|
|
22
|
+
};
|
|
23
|
+
const settle = async () => {
|
|
24
|
+
while (pressing.size > 0)
|
|
25
|
+
await Promise.allSettled(pressing);
|
|
26
|
+
await takeWaiting();
|
|
27
|
+
};
|
|
28
|
+
const wrapped = async (next) => {
|
|
29
|
+
inputDepth += 1;
|
|
30
|
+
try {
|
|
31
|
+
const answer = await next();
|
|
32
|
+
await settle();
|
|
33
|
+
return answer;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
inputDepth -= 1;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
router.add('command.run', (e, next) => wrapped(async () => (waiting.length > 0 ? {} : next(e))));
|
|
40
|
+
router.add('ui.press', (e, next) => wrapped(() => next(e)));
|
|
41
|
+
const ask = (mod) => {
|
|
42
|
+
const pending = asking.get(mod) ??
|
|
43
|
+
claude.cmod
|
|
44
|
+
.call({ to: mod, method: partMethods.list, input: null })
|
|
45
|
+
.then((parts) => void declared.set(mod, pagesOf(parts)), (error) => claude.ui.log(`cmod: ${mod} did not list its pages: ${messageOf(error)}`, { to: 'debug' }))
|
|
46
|
+
.finally(() => asking.delete(mod));
|
|
47
|
+
asking.set(mod, pending);
|
|
48
|
+
return pending;
|
|
49
|
+
};
|
|
50
|
+
const update = (mod, { parts: listing, redraw, requests, isAsked }) => {
|
|
51
|
+
if (listing !== undefined)
|
|
52
|
+
declared.set(mod, pagesOf(listing));
|
|
53
|
+
if (listing !== undefined || redraw === true)
|
|
54
|
+
widgets.update(mod, { ...(listing === undefined ? {} : { parts: listing }), ...(redraw === undefined ? {} : { redraw }) });
|
|
55
|
+
if (requests === undefined || requests.length === 0)
|
|
56
|
+
return false;
|
|
57
|
+
if (isAsked !== true)
|
|
58
|
+
return (void run(mod, requests), false);
|
|
59
|
+
waiting.push({ mod, requests });
|
|
60
|
+
if (inputDepth > 0)
|
|
61
|
+
return true;
|
|
62
|
+
claude.clock.after(askedWaitMs, () => void takeWaiting());
|
|
63
|
+
return false;
|
|
64
|
+
};
|
|
65
|
+
const press = (mod, input) => {
|
|
66
|
+
const pending = claude.cmod
|
|
67
|
+
.call({ to: mod, method: partMethods.press, input })
|
|
68
|
+
.then((answer) => void update(mod, (isObject(answer) ? answer : {})), (error) => {
|
|
69
|
+
parts.forget(mod);
|
|
70
|
+
claude.ui.invalidate('ui.render');
|
|
71
|
+
report(`press:${mod}`, `${mod} did not take the press`, error);
|
|
72
|
+
})
|
|
73
|
+
.finally(() => pressing.delete(pending));
|
|
74
|
+
pressing.add(pending);
|
|
75
|
+
if (inputDepth === 0)
|
|
76
|
+
void pending.then(takeWaiting);
|
|
77
|
+
};
|
|
78
|
+
const cacheKey = (page, params, columns, isFocused) => `${page}\u0000${JSON.stringify(params ?? null)}\u0000${columns}\u0000${isFocused}`;
|
|
79
|
+
return {
|
|
80
|
+
declared: () => [...declared].map(([mod, pages]) => ({ mod, pages })),
|
|
81
|
+
element(mod, page, params, columns, isFocused) {
|
|
82
|
+
if (!declared.has(mod))
|
|
83
|
+
void ask(mod);
|
|
84
|
+
const cached = cacheKey(page, params, columns, isFocused);
|
|
85
|
+
const name = `The ${page} page of ${mod}`;
|
|
86
|
+
void parts.fill(mod, cached, { page, params: params ?? null, columns, isFocused }, name)?.then(() => claude.ui.invalidate('ui.render'));
|
|
87
|
+
return parts.element(mod, cached, `${mod}/${page}:`, name, `page:${mod}/${page}`);
|
|
88
|
+
},
|
|
89
|
+
press,
|
|
90
|
+
update,
|
|
91
|
+
tell(mod, shown) {
|
|
92
|
+
void claude.cmod.call({ to: mod, method: partMethods.shown, input: shown }).catch((error) => claude.ui.log(`cmod: ${mod} did not hear which of its pages show: ${messageOf(error)}`, { to: 'debug' }));
|
|
93
|
+
},
|
|
94
|
+
apply(listener) {
|
|
95
|
+
applyTo = listener;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RenderElement } from 'claude-code';
|
|
2
|
+
import type { Claude } from './claude.js';
|
|
3
|
+
import { type PartPress } from './ui.js';
|
|
4
|
+
export type DrawnParts = {
|
|
5
|
+
fill(mod: string, cached: string, input: Readonly<Record<string, unknown>>, name: string): Promise<void> | undefined;
|
|
6
|
+
element(mod: string, cached: string, keyPrefix: string, name: string, reportId: string): RenderElement | undefined;
|
|
7
|
+
forget(mod: string): void;
|
|
8
|
+
};
|
|
9
|
+
export declare function drawnParts({ claude, report, press }: {
|
|
10
|
+
readonly claude: Claude;
|
|
11
|
+
readonly report: (id: string, message: string, error: unknown) => void;
|
|
12
|
+
readonly press: (mod: string, press: PartPress) => void;
|
|
13
|
+
}): DrawnParts;
|
|
14
|
+
//# sourceMappingURL=parts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../src/runtime/parts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,SAAS,CAAA;AAErE,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAA;IACpH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAA;IAClH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B,CAAA;AAMD,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;CAAE,GAAG,UAAU,CAuD9N"}
|
package/runtime/parts.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { elementOf } from '../ui/elements.js';
|
|
2
|
+
import { messageOf } from '../utils/text.js';
|
|
3
|
+
import { partMethods } from './ui.js';
|
|
4
|
+
const keptDrawings = 200;
|
|
5
|
+
export function drawnParts({ claude, report, press }) {
|
|
6
|
+
const drawn = new Map();
|
|
7
|
+
const drawing = new Map();
|
|
8
|
+
const generations = new Map();
|
|
9
|
+
const keyOf = (mod, cached) => `${mod}\u0000${cached}`;
|
|
10
|
+
const generationOf = (mod) => generations.get(mod) ?? 0;
|
|
11
|
+
return {
|
|
12
|
+
fill(mod, cached, input, name) {
|
|
13
|
+
const key = keyOf(mod, cached);
|
|
14
|
+
const generation = generationOf(mod);
|
|
15
|
+
if (drawn.get(key)?.generation === generation)
|
|
16
|
+
return undefined;
|
|
17
|
+
const keep = (data) => {
|
|
18
|
+
drawn.delete(key);
|
|
19
|
+
drawn.set(key, { data, generation });
|
|
20
|
+
const [oldest] = drawn.keys();
|
|
21
|
+
if (drawn.size > keptDrawings && oldest !== undefined)
|
|
22
|
+
drawn.delete(oldest);
|
|
23
|
+
if (generationOf(mod) !== generation)
|
|
24
|
+
claude.ui.invalidate('ui.render');
|
|
25
|
+
};
|
|
26
|
+
const pending = drawing.get(key) ??
|
|
27
|
+
claude.cmod
|
|
28
|
+
.call({ to: mod, method: partMethods.draw, input })
|
|
29
|
+
.then((data) => keep((data ?? null)), (error) => {
|
|
30
|
+
claude.ui.log(`cmod: ${name} drew nothing: ${messageOf(error)}`, { to: 'debug' });
|
|
31
|
+
keep(null);
|
|
32
|
+
})
|
|
33
|
+
.finally(() => drawing.delete(key));
|
|
34
|
+
drawing.set(key, pending);
|
|
35
|
+
return pending;
|
|
36
|
+
},
|
|
37
|
+
element(mod, cached, keyPrefix, name, reportId) {
|
|
38
|
+
const key = keyOf(mod, cached);
|
|
39
|
+
const entry = drawn.get(key);
|
|
40
|
+
if (entry === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
drawn.delete(key);
|
|
43
|
+
drawn.set(key, entry);
|
|
44
|
+
const { data } = entry;
|
|
45
|
+
if (data === null || data.tree === null)
|
|
46
|
+
return undefined;
|
|
47
|
+
try {
|
|
48
|
+
return elementOf(data.tree, keyPrefix, (handler, args) => press(mod, { draw: data.draw, handler, args }));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
report(reportId, `${name} could not draw`, error);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
forget(mod) {
|
|
56
|
+
const superseded = generationOf(mod);
|
|
57
|
+
generations.set(mod, superseded + 1);
|
|
58
|
+
for (const [key, { generation }] of drawn)
|
|
59
|
+
if (key.startsWith(`${mod}\u0000`) && generation < superseded)
|
|
60
|
+
drawn.delete(key);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Subscription } from '../utils/subscription.js';
|
|
2
2
|
import type { HookFields } from './hooks.js';
|
|
3
3
|
import { type HookOn, type RouteOn } from './sessions.js';
|
|
4
4
|
export type PermissionUse = {
|
|
@@ -13,6 +13,6 @@ export type PermissionUse = {
|
|
|
13
13
|
readonly cwd: string;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
-
export type PermissionRoutes = (method: string, use: PermissionUse) =>
|
|
16
|
+
export type PermissionRoutes = (method: string, use: PermissionUse) => Subscription;
|
|
17
17
|
export declare const permissionRoutes: PermissionRoutes;
|
|
18
18
|
//# sourceMappingURL=permission-check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission-check.d.ts","sourceRoot":"","sources":["../src/runtime/permission-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"permission-check.d.ts","sourceRoot":"","sources":["../src/runtime/permission-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAuC,KAAK,MAAM,EAAE,KAAK,OAAO,EAAkB,MAAM,eAAe,CAAA;AAE9G,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IACxF,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IACnH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,YAAY,CAAA;AAQnF,eAAO,MAAM,gBAAgB,EAAE,gBAwD9B,CAAA"}
|
|
@@ -23,9 +23,13 @@ export const permissionRoutes = (method, { raise, refusalFor, hookOn, routeOn, c
|
|
|
23
23
|
return below;
|
|
24
24
|
if (typeof answer['refuse'] === 'string')
|
|
25
25
|
return { decision: 'deny', reason: answer['refuse'] };
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
if (!globalThis.cmodWithoutApprove) {
|
|
27
|
+
if (typeof answer['ask'] === 'string')
|
|
28
|
+
return { decision: 'ask', reason: answer['ask'] };
|
|
29
|
+
if (answer['allow'] === true)
|
|
30
|
+
return { decision: 'allow' };
|
|
31
|
+
}
|
|
32
|
+
return below;
|
|
29
33
|
}, isBefore ? failed : undefined);
|
|
30
34
|
}
|
|
31
35
|
const refused = (refuse, interrupt) => ({ decision: defined({ behavior: 'deny', message: refuse, interrupt }) });
|
|
@@ -40,7 +44,11 @@ export const permissionRoutes = (method, { raise, refusalFor, hookOn, routeOn, c
|
|
|
40
44
|
return undefined;
|
|
41
45
|
if (typeof answer['refuse'] === 'string')
|
|
42
46
|
return refused(answer['refuse'], answer['interrupt']);
|
|
43
|
-
|
|
47
|
+
if (!globalThis.cmodWithoutApprove) {
|
|
48
|
+
if (answer['allow'] === true)
|
|
49
|
+
return { decision: defined({ behavior: 'allow', updatedInput: answer['input'], updatedPermissions: answer['updates'] }) };
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
44
52
|
}, isBefore
|
|
45
53
|
? (input, error) => {
|
|
46
54
|
const refusal = refusalFor(method, processPayloadOf('PermissionRequest', input), error);
|
package/runtime/programs.js
CHANGED
|
@@ -42,7 +42,7 @@ export function locatingPrograms(claude) {
|
|
|
42
42
|
let names = new Set();
|
|
43
43
|
const located = (argv) => {
|
|
44
44
|
const [name, ...rest] = argv;
|
|
45
|
-
return folder !== undefined && name !== undefined && names.has(name) ? [`${folder}/${name}`, ...rest] : argv;
|
|
45
|
+
return folder !== undefined && name !== undefined && (name === 'cmod' || names.has(name)) ? [`${folder}/${name}`, ...rest] : argv;
|
|
46
46
|
};
|
|
47
47
|
return {
|
|
48
48
|
claude: {
|
package/runtime/router.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Args, EventResult, Frozen } from 'claude-code';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Subscription } from '../utils/subscription.js';
|
|
3
3
|
import type { RoutedEvent } from './hooks.js';
|
|
4
4
|
export type RouterNext<N extends RoutedEvent> = (e: Frozen<Args<N>>) => Promise<EventResult<N>>;
|
|
5
5
|
export type RoutedHook<N extends RoutedEvent> = (e: Frozen<Args<N>>, next: RouterNext<N>) => EventResult<N> | Promise<EventResult<N>>;
|
|
6
6
|
export type RoutedFailure<N extends RoutedEvent> = (e: Frozen<Args<N>>, error: Error, next: RouterNext<N>) => EventResult<N> | undefined | Promise<EventResult<N> | undefined>;
|
|
7
7
|
export type Router = {
|
|
8
|
-
add<N extends RoutedEvent>(event: N, hook: RoutedHook<N>, failed?: RoutedFailure<N>):
|
|
8
|
+
add<N extends RoutedEvent>(event: N, hook: RoutedHook<N>, failed?: RoutedFailure<N>): Subscription;
|
|
9
9
|
dispatch<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>): Promise<EventResult<N>>;
|
|
10
10
|
dispatchFailure<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, error: Error, next: RouterNext<N>): Promise<EventResult<N>>;
|
|
11
11
|
};
|
package/runtime/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/runtime/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/runtime/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAE/F,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAErI,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;AAE9K,MAAM,MAAM,MAAM,GAAG;IACnB,GAAG,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,YAAY,CAAA;IAClG,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3G,eAAe,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;CACjI,CAAA;AAID,wBAAgB,YAAY,IAAI,MAAM,CAgCrC"}
|
package/runtime/router.js
CHANGED
|
@@ -5,7 +5,7 @@ export function createRouter() {
|
|
|
5
5
|
const route = { hook, ...(failed === undefined ? {} : { failed }) };
|
|
6
6
|
routes.set(event, [...(routes.get(event) ?? []), route]);
|
|
7
7
|
return {
|
|
8
|
-
|
|
8
|
+
remove() {
|
|
9
9
|
const chain = (routes.get(event) ?? []).filter((each) => each !== route);
|
|
10
10
|
if (chain.length === 0)
|
|
11
11
|
routes.delete(event);
|
package/runtime/sessions.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Args, CommandRunResult, SessionCompactResult } from 'claude-code';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Subscription } from '../utils/subscription.js';
|
|
3
3
|
import { ToolResult } from '../session/context/turn/message/tool-result.js';
|
|
4
|
-
import { type
|
|
4
|
+
import { type Turn } from '../session/context/turn/turn.js';
|
|
5
|
+
import { type SessionChange, type SessionData, type TaskData, type TurnData } from '../session/conversation.js';
|
|
5
6
|
import { type BeforeEvent, type ProcessName, type SessionEvent, type Sessions, type TaskStartArgs, type ToolCallArgs, type Usage } from '../session/session.js';
|
|
6
7
|
import { type SentMatcher } from '../utils/matcher.js';
|
|
7
8
|
import { type Place } from './before.js';
|
|
8
9
|
import type { Claude } from './claude.js';
|
|
9
10
|
import { type HookFields } from './hooks.js';
|
|
10
11
|
import type { PermissionRoutes } from './permission-check.js';
|
|
11
|
-
export type
|
|
12
|
+
export type Listened = {
|
|
12
13
|
readonly event: SessionEvent;
|
|
13
14
|
readonly matcher: SentMatcher | undefined;
|
|
14
15
|
readonly onFailure?: 'refuse';
|
|
@@ -24,7 +25,6 @@ export declare const conversationMethods: {
|
|
|
24
25
|
readonly tasks: 'cmod:tasks';
|
|
25
26
|
readonly goal: 'cmod:goal';
|
|
26
27
|
readonly updateGoal: 'cmod:updateGoal';
|
|
27
|
-
readonly usage: 'cmod:usage';
|
|
28
28
|
readonly subscribe: 'cmod:subscribe';
|
|
29
29
|
readonly watchBefore: 'cmod:watchBefore';
|
|
30
30
|
readonly act: 'cmod:act';
|
|
@@ -52,7 +52,8 @@ export type SessionsClient = {
|
|
|
52
52
|
readonly refuse: string;
|
|
53
53
|
} | undefined;
|
|
54
54
|
raise(method: string, payload: Readonly<Record<string, unknown>>): Promise<unknown>;
|
|
55
|
-
listen(method: string, args: readonly unknown[]):
|
|
55
|
+
listen(method: string, args: readonly unknown[]): Subscription;
|
|
56
|
+
turn(data: TurnData): Turn;
|
|
56
57
|
/** An empty title keeps the title the session already has. */
|
|
57
58
|
follow(current: Omit<SessionData, 'isRunning' | 'lastAt'>): void;
|
|
58
59
|
};
|
|
@@ -61,7 +62,7 @@ export declare function payloadOf(change: SessionChange): unknown;
|
|
|
61
62
|
export declare function isHeardBy(event: SessionEvent, matcher: unknown, change: SessionChange): boolean;
|
|
62
63
|
export declare function isInScope(scope: Scope, session: string, change: SessionChange, isUnder: (task: string, ancestor: string) => boolean): boolean;
|
|
63
64
|
export declare function withoutPermissionCheck(name: string, hearer: string): string;
|
|
64
|
-
export type HookOn = (hook: string, listener: (input: unknown) => HookFields | undefined | Promise<HookFields | undefined>, failed?: (input: unknown, error: Error) => HookFields | undefined) =>
|
|
65
|
+
export type HookOn = (hook: string, listener: (input: unknown) => HookFields | undefined | Promise<HookFields | undefined>, failed?: (input: unknown, error: Error) => HookFields | undefined) => Subscription;
|
|
65
66
|
export declare function createSessionsClient({ name, claude, report, isGranted, hookOn, routeOn, permissionRoutes }: {
|
|
66
67
|
readonly name: string;
|
|
67
68
|
readonly claude: Claude;
|
|
@@ -82,9 +83,9 @@ export type RouteOn = {
|
|
|
82
83
|
(event: 'tool.check', hook: (e: ToolCheck, next: (e: ToolCheck) => Promise<unknown>) => Promise<unknown>, failed?: (e: ToolCheck, error: Error, next: (e: ToolCheck) => Promise<unknown>) => Promise<{
|
|
83
84
|
readonly decision: 'deny';
|
|
84
85
|
readonly reason: string;
|
|
85
|
-
} | undefined>):
|
|
86
|
-
(event: 'command.run', hook: (e: Args<'command.run'>, next: (e: Args<'command.run'>) => Promise<CommandRunResult>) => Promise<CommandRunResult>, failed?: (e: Args<'command.run'>, error: Error) => Promise<CommandRunResult | undefined>):
|
|
87
|
-
(event: 'session.compact', hook: (e: Args<'session.compact'>, next: (e: Args<'session.compact'>) => Promise<SessionCompactResult>) => Promise<SessionCompactResult>):
|
|
86
|
+
} | undefined>): Subscription;
|
|
87
|
+
(event: 'command.run', hook: (e: Args<'command.run'>, next: (e: Args<'command.run'>) => Promise<CommandRunResult>) => Promise<CommandRunResult>, failed?: (e: Args<'command.run'>, error: Error) => Promise<CommandRunResult | undefined>): Subscription;
|
|
88
|
+
(event: 'session.compact', hook: (e: Args<'session.compact'>, next: (e: Args<'session.compact'>) => Promise<SessionCompactResult>) => Promise<SessionCompactResult>): Subscription;
|
|
88
89
|
};
|
|
89
90
|
export declare const recordOf: (value: unknown) => Readonly<Record<string, unknown>>;
|
|
90
91
|
export declare const defined: (fields: HookFields) => HookFields;
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/runtime/sessions.ts"],"names":[],"mappings":"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"}
|
package/runtime/sessions.js
CHANGED
|
@@ -13,6 +13,7 @@ import { matches, sentMatcher } from '../utils/matcher.js';
|
|
|
13
13
|
import { beforeAnswerKeys, foldAnswers, foldBefore, methodOf, takenAnswer } from './before.js';
|
|
14
14
|
import { cmodPluginName } from './dependencies.js';
|
|
15
15
|
import { messageOf } from '../utils/text.js';
|
|
16
|
+
import { grantFix, permissionWords } from '../records.js';
|
|
16
17
|
import { listenerOf, PassedTimeout, withinTime } from './deadline.js';
|
|
17
18
|
import { callFiles } from './hooks.js';
|
|
18
19
|
export const everySession = '*';
|
|
@@ -25,7 +26,6 @@ export const conversationMethods = {
|
|
|
25
26
|
tasks: 'cmod:tasks',
|
|
26
27
|
goal: 'cmod:goal',
|
|
27
28
|
updateGoal: 'cmod:updateGoal',
|
|
28
|
-
usage: 'cmod:usage',
|
|
29
29
|
subscribe: 'cmod:subscribe',
|
|
30
30
|
watchBefore: 'cmod:watchBefore',
|
|
31
31
|
act: 'cmod:act',
|
|
@@ -166,7 +166,7 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
166
166
|
void learnTasks(scope.session ?? current.id).catch((error) => report(`tasks:${key}`, 'Could not read the tasks it listens under', error));
|
|
167
167
|
onChange(key);
|
|
168
168
|
return {
|
|
169
|
-
|
|
169
|
+
remove() {
|
|
170
170
|
for (const [at, held] of into) {
|
|
171
171
|
if (!held.delete(entry))
|
|
172
172
|
continue;
|
|
@@ -197,7 +197,7 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
197
197
|
const answer = await invoke(entry.method, entry.options, async (time) => takenAnswer(entry.method, beforeAnswerKeys[event], await entry.listener(payload, time)), beforeAnswerKeys[event]);
|
|
198
198
|
if (answer === undefined || answer === null || (typeof answer === 'object' && 'refuse' in answer) || isGranted(beforePermission(event)))
|
|
199
199
|
return answer;
|
|
200
|
-
throw new Error(`Its ${entry.method} answer changes nothing until ${beforePermission(event)}
|
|
200
|
+
throw new Error(`Its ${entry.method} answer changes nothing until you grant ${name} "${permissionWords(beforePermission(event))}". ${grantFix}`);
|
|
201
201
|
});
|
|
202
202
|
const answer = await foldBefore(event, change, askers, (error) => report(`session:${methodOf('before', event)}`, `The ${methodOf('before', event)} listener failed`, error));
|
|
203
203
|
return answer?.note === undefined ? answer : { ...answer, note: modNote(name, answer.note) };
|
|
@@ -510,11 +510,19 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
510
510
|
processListeners.set(method, held);
|
|
511
511
|
}
|
|
512
512
|
held.add(entry);
|
|
513
|
-
return {
|
|
513
|
+
return { remove: () => void held.delete(entry) };
|
|
514
514
|
};
|
|
515
515
|
const processMethods = () => Object.fromEntries(Object.entries(processEvents).flatMap(([named, event]) => [`on${named}`, ...('before' in event ? [`before${named}`] : [])]).map((method) => [method, (...args) => listen(method, args)]));
|
|
516
516
|
const here = sessionOf(() => current);
|
|
517
|
-
const currentSession = Object.assign(here, processMethods(), {
|
|
517
|
+
const currentSession = Object.assign(here, processMethods(), {
|
|
518
|
+
goal: Object.assign(here.goal, { beforeSessionStart: (...args) => listen('beforeSessionStart', args, true) }),
|
|
519
|
+
async scrollTo(message, options) {
|
|
520
|
+
const { deny } = await claude.ui.scroll({ to: { requestId: message.id }, ...(options?.block === undefined ? {} : { block: options.block }) });
|
|
521
|
+
if (deny !== undefined)
|
|
522
|
+
throw new Error(`${name}: Claude Code did not scroll to the message: ${deny}`);
|
|
523
|
+
},
|
|
524
|
+
caption: (toolCall, text) => claude.ui.notice(toolCall.callId, text),
|
|
525
|
+
});
|
|
518
526
|
const every = eventMethods(() => ({}), false);
|
|
519
527
|
const answerBefore = async (session, event, change, isInProject) => (mayDecide(session) ? combined(session, event, change, isInProject) : undefined);
|
|
520
528
|
const failedBefore = (session, event, change, isInProject, error) => {
|
|
@@ -556,6 +564,7 @@ export function createSessionsClient({ name, claude, report, isGranted, hookOn,
|
|
|
556
564
|
failedBefore,
|
|
557
565
|
raise,
|
|
558
566
|
listen,
|
|
567
|
+
turn: (data) => turnOf({ session: current.id }, data),
|
|
559
568
|
follow(next) {
|
|
560
569
|
const moved = next.id !== current.id && current.id !== '';
|
|
561
570
|
const previous = current.id;
|
package/runtime/state.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ClassicHookInputs } from 'claude-code';
|
|
2
|
+
import type { Subscription } from '../utils/subscription.js';
|
|
2
3
|
import type { Claude } from './claude.js';
|
|
3
4
|
import type { Failure } from './toaster.js';
|
|
4
5
|
export type StateOptions = {
|
|
@@ -19,7 +20,7 @@ export type ModState<State extends object> = {
|
|
|
19
20
|
moveTo(root: string): Promise<void>;
|
|
20
21
|
switchSession(session: string, source: ClassicHookInputs['SessionStart']['source'], transcript: string): Promise<void>;
|
|
21
22
|
};
|
|
22
|
-
export declare function onStateChange(state: object, listener: () => void):
|
|
23
|
+
export declare function onStateChange(state: object, listener: () => void): Subscription;
|
|
23
24
|
export declare function sessionsWith(claude: Pick<Claude, 'store'>, name: string, key: string, value: unknown): Promise<string[]>;
|
|
24
25
|
export declare function createState<State extends object>({ name, initial, session, root, claude, report, changed: redraw, forkParent }: StateOptions): ModState<State>;
|
|
25
26
|
//# sourceMappingURL=state.d.ts.map
|
package/runtime/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/runtime/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAQ3C,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CACvD,CAAA;AAED,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,MAAM,IAAI;IAC3C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,OAAO,IAAI,IAAI,CAAA;IACf,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACvH,CAAA;AAQD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/runtime/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAQ3C,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CACvD,CAAA;AAED,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,MAAM,IAAI;IAC3C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,OAAO,IAAI,IAAI,CAAA;IACf,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACvH,CAAA;AAQD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,YAAY,CAK/E;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAO9H;AAED,wBAAgB,WAAW,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,CAoH9J"}
|
package/runtime/state.js
CHANGED
|
@@ -5,6 +5,7 @@ export function onStateChange(state, listener) {
|
|
|
5
5
|
const own = listeners.get(state) ?? new Set();
|
|
6
6
|
own.add(listener);
|
|
7
7
|
listeners.set(state, own);
|
|
8
|
+
return { remove: () => void own.delete(listener) };
|
|
8
9
|
}
|
|
9
10
|
export async function sessionsWith(claude, name, key, value) {
|
|
10
11
|
const prefix = `${name}.${key}.sessions.`;
|
package/runtime/toaster.d.ts
CHANGED
|
@@ -20,5 +20,5 @@ export type Toaster = {
|
|
|
20
20
|
readonly shown: readonly ShownToast[];
|
|
21
21
|
draw(drawn: RenderElement, table: ElementTable, band: RenderPropsOf['AbovePrompt'], bandId: string): RenderElement;
|
|
22
22
|
};
|
|
23
|
-
export declare function createToaster(claude: Claude, name: string, version: () => string | undefined): Toaster;
|
|
23
|
+
export declare function createToaster(claude: Claude, name: string, version: () => string | undefined, openPermissions: () => unknown): Toaster;
|
|
24
24
|
//# sourceMappingURL=toaster.d.ts.map
|
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;AAuCD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,OAAO,
|
|
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;AAuCD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,SAAS,EAAE,eAAe,EAAE,MAAM,OAAO,GAAG,OAAO,CAqQtI"}
|
package/runtime/toaster.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Box, Button, drawWith, Link, Text } from '../ui/elements.js';
|
|
2
|
-
import { coreVersion, isObject } from '../records.js';
|
|
2
|
+
import { coreVersion, grantFix, installFix, isObject, secretFix } from '../records.js';
|
|
3
3
|
import { firstLine, messageOf } from '../utils/text.js';
|
|
4
4
|
const githubRepository = /^https:\/\/github\.com\/([^/]+\/[^/#?]+?)(?:\.git)?(?:\/issues)?\/?$/;
|
|
5
5
|
const linkLimit = 2048;
|
|
@@ -15,7 +15,7 @@ const icons = {
|
|
|
15
15
|
warning: { glyph: '⚠', color: 'warning' },
|
|
16
16
|
error: { glyph: '✗', color: 'error' },
|
|
17
17
|
};
|
|
18
|
-
export function createToaster(claude, name, version) {
|
|
18
|
+
export function createToaster(claude, name, version, openPermissions) {
|
|
19
19
|
const entries = new Map();
|
|
20
20
|
const hidden = new Map();
|
|
21
21
|
void claude.store.get(hiddenKey).then((saved) => {
|
|
@@ -128,7 +128,7 @@ export function createToaster(claude, name, version) {
|
|
|
128
128
|
const press = (entry, run) => () => void Promise.resolve()
|
|
129
129
|
.then(run)
|
|
130
130
|
.catch((error) => fail({ id: `press:${entry.id}`, message: `${entry.message}: the press failed`, error }));
|
|
131
|
-
const fail = ({ id, message, error, description = error === undefined ? undefined : describe(error), retry }) => {
|
|
131
|
+
const fail = ({ id, message, error, description = error === undefined || describe(error) === message ? undefined : describe(error), retry }) => {
|
|
132
132
|
const hides = `${version() ?? ''}\n${message}\n${error === undefined ? '' : describe(error)}`;
|
|
133
133
|
if (hidden.get(id) === hides)
|
|
134
134
|
return id;
|
|
@@ -173,7 +173,13 @@ export function createToaster(claude, name, version) {
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
};
|
|
176
|
-
const
|
|
176
|
+
const text = `${message}\n${description ?? ''}`;
|
|
177
|
+
const fixes = [
|
|
178
|
+
{ sentence: grantFix, label: 'Settings', onClick: openPermissions },
|
|
179
|
+
{ sentence: installFix, label: 'Plugins', onClick: () => claude.command.run({ command: 'plugin' }) },
|
|
180
|
+
{ sentence: secretFix, label: 'Open /config', onClick: () => claude.command.run({ command: 'config' }) },
|
|
181
|
+
].filter(({ sentence }) => text.includes(sentence));
|
|
182
|
+
const actions = [...fixes, ...(retry === undefined ? [] : [{ label: 'Retry', onClick: tryAgain }]), { label: 'Report', onClick: startReporting }];
|
|
177
183
|
return put('error', message, { id, ...(description === undefined ? {} : { description }), duration: Infinity }, actions, hides);
|
|
178
184
|
};
|
|
179
185
|
const toggle = (entry) => () => {
|