@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/runtime/hotkeys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hotkeys.d.ts","sourceRoot":"","sources":["../src/runtime/hotkeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAIpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"hotkeys.d.ts","sourceRoot":"","sources":["../src/runtime/hotkeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAIpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAS7G;AAED,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,MAAM,EACN,MAAM,EACN,WAAW,EACX,MAAM,GACP,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7G,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CA8C5C"}
|
package/runtime/hotkeys.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { boundCombos, hotkeyCommand } from '../records.js';
|
|
2
2
|
import { ifMissing } from '../utils/paths.js';
|
|
3
3
|
import { messageOf } from '../utils/text.js';
|
|
4
|
+
import { cmodPluginName } from './dependencies.js';
|
|
4
5
|
export async function readCombos(claude, configRoot) {
|
|
5
6
|
if (configRoot === undefined)
|
|
6
7
|
return new Map();
|
|
@@ -14,6 +15,12 @@ export async function readCombos(claude, configRoot) {
|
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
export async function createHotkeys({ name, declared, configRoot, claude, router, answerInput, report, }) {
|
|
18
|
+
if (name === cmodPluginName) {
|
|
19
|
+
router.add('command.describe', async (e, next) => {
|
|
20
|
+
const described = await next(e);
|
|
21
|
+
return e.command.startsWith(hotkeyCommand(e.provider.plugin.replace(/@[^@]*$/, ''), '')) ? { ...described, isHidden: true } : described;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
17
24
|
const entries = Object.entries(declared);
|
|
18
25
|
if (entries.length === 0)
|
|
19
26
|
return {};
|
|
@@ -24,10 +31,6 @@ export async function createHotkeys({ name, declared, configRoot, claude, router
|
|
|
24
31
|
listeners.set(hotkey, new Set());
|
|
25
32
|
claude.command.register({ name: hotkeyCommand(name, hotkey), description: title, immediate: true }).then(({ command }) => void commands.set(command, hotkey), (error) => report({ id: `hotkey:${hotkey}`, message: `The ${title} hotkey is not added`, error }));
|
|
26
33
|
}
|
|
27
|
-
router.add('command.describe', async (e, next) => {
|
|
28
|
-
const described = await next(e);
|
|
29
|
-
return commands.has(e.command) ? { ...described, isHidden: true } : described;
|
|
30
|
-
});
|
|
31
34
|
router.add('command.run', async (e, next) => {
|
|
32
35
|
const hotkey = commands.get(e.command);
|
|
33
36
|
if (hotkey === undefined)
|
package/runtime/installer.d.ts
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import type { Args, Frozen, RenderElement } from 'claude-code';
|
|
2
1
|
import type { Step } from '../installer.js';
|
|
3
2
|
import type { Mod } from '../mod.js';
|
|
4
3
|
import type { Option } from '../options.js';
|
|
5
4
|
import type { Claude } from './claude.js';
|
|
6
|
-
|
|
5
|
+
import { type PartsUpdate, type ShownPages } from './ui.js';
|
|
6
|
+
export declare const installPage = "cmod:install";
|
|
7
7
|
export type Consent = {
|
|
8
8
|
readonly install: string;
|
|
9
9
|
readonly uninstall: string;
|
|
10
|
+
readonly program: string;
|
|
10
11
|
readonly hotkeys: string;
|
|
11
12
|
readonly permissions: readonly string[];
|
|
12
13
|
readonly updates?: string | undefined;
|
|
13
14
|
};
|
|
14
15
|
export type Installer = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
answer(method: string, input: unknown): Promise<{
|
|
17
|
+
readonly value: unknown;
|
|
18
|
+
}> | undefined;
|
|
19
|
+
hear(shown: ShownPages): void;
|
|
18
20
|
consent(consent: Consent): Promise<boolean>;
|
|
19
21
|
options(missing: readonly (readonly [string, Option])[], save: (key: string, value: string) => Promise<string | undefined>): Promise<boolean>;
|
|
20
22
|
step<State extends object>(mod: Mod<State>, step: Step<State>, index: number, total: number): Promise<boolean>;
|
|
21
23
|
close(): Promise<void>;
|
|
24
|
+
shown(): Promise<void>;
|
|
25
|
+
collect(run: () => Promise<unknown>): Promise<PartsUpdate>;
|
|
22
26
|
};
|
|
23
27
|
export declare function createInstaller(name: string, claude: () => Claude, waiting: {
|
|
24
28
|
show(open: () => Promise<void>): void;
|
|
25
29
|
hide(): void;
|
|
26
|
-
}): Installer;
|
|
30
|
+
}, nextDraw: () => number): Installer;
|
|
27
31
|
//# sourceMappingURL=installer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAM3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAmE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAE5H,eAAO,MAAM,WAAW,iBAAiB,CAAA;AAEzC,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA;AAOD,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,SAAS,CAAA;IACxF,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7B,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7I,IAAI,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9G,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,OAAO,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CAC3D,CAAA;AAID,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,OAAO,EAAE;IAAE,IAAI,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,EAAE,QAAQ,EAAE,MAAM,MAAM,GAAG,SAAS,CA4MvK"}
|
package/runtime/installer.js
CHANGED
|
@@ -1,75 +1,129 @@
|
|
|
1
|
-
import { permissionWords, secretFix } from '../records.js';
|
|
2
|
-
import { Box,
|
|
1
|
+
import { isObject, permissionWords, secretFix } from '../records.js';
|
|
2
|
+
import { Box, elementData, Input, Text } from '../ui/elements.js';
|
|
3
|
+
import { filledButton } from './buttons.js';
|
|
3
4
|
import { messageOf } from '../utils/text.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { cmodPluginName, withBareRefusals } from './dependencies.js';
|
|
6
|
+
import { merged, partMethods, stalePress } from './ui.js';
|
|
7
|
+
export const installPage = 'cmod:install';
|
|
8
|
+
const keptDraws = 8;
|
|
9
|
+
export function createInstaller(name, claude, waiting, nextDraw) {
|
|
10
|
+
let question;
|
|
8
11
|
let isOpen = false;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
let isSeen = false;
|
|
13
|
+
let waitingForShow = [];
|
|
14
|
+
let collected;
|
|
15
|
+
const draws = new Map();
|
|
16
|
+
const send = async (update) => {
|
|
17
|
+
if (collected !== undefined)
|
|
18
|
+
return void collected.push(update);
|
|
19
|
+
await withBareRefusals(claude()).cmod.call({ to: cmodPluginName, method: partMethods.changed, input: update });
|
|
12
20
|
};
|
|
21
|
+
const log = (what) => (error) => claude().ui.log(`${name}: ${what}: ${messageOf(error)}`, { to: 'debug' });
|
|
22
|
+
const open = (isAsked) => send({ requests: [{ open: installPage, focus: true }], ...(isAsked ? { isAsked: true } : {}) });
|
|
13
23
|
const show = async (build, cancelled) => {
|
|
14
|
-
|
|
24
|
+
question?.cancel();
|
|
15
25
|
const answer = new Promise((resolve) => {
|
|
26
|
+
let isAnswered = false;
|
|
16
27
|
const done = (value) => {
|
|
17
|
-
if (
|
|
18
|
-
|
|
28
|
+
if (isAnswered)
|
|
29
|
+
return;
|
|
30
|
+
isAnswered = true;
|
|
19
31
|
waiting.hide();
|
|
20
|
-
resolve(value);
|
|
32
|
+
claude().clock.after(0, () => resolve(value));
|
|
21
33
|
};
|
|
22
|
-
|
|
23
|
-
page = shown;
|
|
34
|
+
question = { ...build(done), cancel: () => done(cancelled) };
|
|
24
35
|
});
|
|
25
|
-
waiting.show(open);
|
|
26
|
-
if (
|
|
27
|
-
await
|
|
36
|
+
waiting.show(() => open(true));
|
|
37
|
+
if (isOpen) {
|
|
38
|
+
await send({ redraw: true }).catch(log('the installer did not redraw'));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
isOpen = true;
|
|
42
|
+
await open(false).catch((error) => {
|
|
43
|
+
isOpen = false;
|
|
28
44
|
waiting.hide();
|
|
29
45
|
throw error;
|
|
30
46
|
});
|
|
31
|
-
|
|
47
|
+
}
|
|
48
|
+
for (const resolve of waitingForShow)
|
|
49
|
+
resolve();
|
|
50
|
+
waitingForShow = [];
|
|
32
51
|
return answer;
|
|
33
52
|
};
|
|
34
|
-
const
|
|
35
|
-
const
|
|
53
|
+
const redraw = () => void send({ redraw: true }).catch(log('the installer did not redraw'));
|
|
54
|
+
const actions = (...buttons) => Box({ gap: 2, flexShrink: 0, children: buttons });
|
|
55
|
+
const dialog = (title, ...children) => Box({ flexDirection: 'column', gap: 1, children: [title, ...children] });
|
|
56
|
+
const bullet = (text) => Box({ gap: 1, children: [Text({ dimColor: true, children: '•' }), Text({ wrap: 'wrap', children: text })] });
|
|
57
|
+
const group = (heading, items) => Box({ flexDirection: 'column', children: [Text({ bold: true, children: heading }), ...items.map(bullet)] });
|
|
58
|
+
const draw = (columns, isFocused) => {
|
|
59
|
+
if (question === undefined && !isOpen)
|
|
60
|
+
claude().clock.after(0, () => void send({ requests: [{ close: installPage }] }).catch(log('a leftover install page stayed open')));
|
|
61
|
+
const handlers = [];
|
|
62
|
+
const tree = elementData(question?.draw({ params: undefined, isFocused, columns }) ?? Text({ dimColor: true, children: `${name} needs nothing from you now.` }), handlers);
|
|
63
|
+
const drawn = nextDraw();
|
|
64
|
+
draws.set(drawn, handlers);
|
|
65
|
+
for (const kept of draws.keys())
|
|
66
|
+
if (draws.size > keptDraws)
|
|
67
|
+
draws.delete(kept);
|
|
68
|
+
return { draw: drawn, tree };
|
|
69
|
+
};
|
|
70
|
+
const collect = async (run) => {
|
|
71
|
+
const outer = collected;
|
|
72
|
+
const mine = [];
|
|
73
|
+
collected = mine;
|
|
74
|
+
try {
|
|
75
|
+
await run();
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
collected = outer;
|
|
79
|
+
}
|
|
80
|
+
return merged(mine);
|
|
81
|
+
};
|
|
82
|
+
const press = async ({ draw: drawn, handler, args }) => {
|
|
83
|
+
const run = draws.get(drawn)?.[handler];
|
|
84
|
+
if (run === undefined)
|
|
85
|
+
throw new Error(`${name}: ${stalePress}`);
|
|
86
|
+
return collect(() => run(...args));
|
|
87
|
+
};
|
|
36
88
|
return {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
89
|
+
answer(method, input) {
|
|
90
|
+
if (method === partMethods.draw && isObject(input) && input['page'] === installPage)
|
|
91
|
+
return Promise.resolve({ value: draw(Number(input['columns']), input['isFocused'] === true) });
|
|
92
|
+
if (method === partMethods.press && isObject(input) && typeof input['draw'] === 'number' && draws.has(input['draw']))
|
|
93
|
+
return press(input).then((value) => ({ value }));
|
|
94
|
+
return undefined;
|
|
40
95
|
},
|
|
41
|
-
|
|
42
|
-
if (id
|
|
96
|
+
hear(shown) {
|
|
97
|
+
if (shown.open.some((each) => each.id === installPage)) {
|
|
98
|
+
isSeen = isOpen;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!isSeen)
|
|
43
102
|
return;
|
|
44
103
|
isOpen = false;
|
|
45
|
-
|
|
104
|
+
isSeen = false;
|
|
105
|
+
question?.cancel();
|
|
46
106
|
},
|
|
47
|
-
consent({ install, uninstall, hotkeys, permissions, updates }) {
|
|
107
|
+
consent({ install, uninstall, program, hotkeys, permissions, updates }) {
|
|
48
108
|
const changes = [
|
|
49
109
|
...(install === '' ? [] : [`Run ${install} now${uninstall === '' ? '' : `, and ${uninstall} when you remove it`}`]),
|
|
50
110
|
...(install === '' && uninstall !== '' ? [`Run ${uninstall} when you remove it`] : []),
|
|
111
|
+
...(program === '' ? [] : [`Install ${program}, which Claude runs by its name`]),
|
|
51
112
|
...(hotkeys === '' ? [] : [`Bind ${hotkeys}`]),
|
|
52
113
|
...(updates === undefined ? [] : [`Update ${name} automatically from the ${updates} marketplace`]),
|
|
53
114
|
];
|
|
54
115
|
return show((answer) => ({
|
|
55
|
-
draw: () =>
|
|
56
|
-
...(permissions.length === 0 ? [] : [Box({ flexDirection: 'column', children: permissions.map((item) => bullet(permissionWords(item))) })]),
|
|
57
|
-
...(changes.length === 0 ? [] : [Text({ children: permissions.length === 0 ? 'Change your computer:' : 'and change your computer:' }), Box({ flexDirection: 'column', children: changes.map(bullet) })]),
|
|
58
|
-
Text({ dimColor: true, children: 'You can turn each permission off later in Settings.' }),
|
|
59
|
-
], [Button({ key: 'not-now', hotkey: 'n', label: 'Not now', onPress: () => answer(false) }), Button({ key: 'accept', hotkey: 'a', label: 'Accept', onPress: () => answer(true) })]),
|
|
116
|
+
draw: () => dialog(Text({ bold: true, children: `Install ${name}?` }), ...(permissions.length === 0 ? [] : [group(`${name} wants to:`, permissions.map(permissionWords))]), ...(changes.length === 0 ? [] : [group(permissions.length === 0 ? `${name} wants to change your computer:` : 'and change your computer:', changes)]), Text({ dimColor: true, wrap: 'wrap', children: 'You can turn each permission off later in Settings.' }), actions(filledButton({ key: 'accept', hotkey: 'a', variant: 'primary', label: 'Accept', onPress: () => answer(true) }), filledButton({ key: 'not-now', hotkey: 'n', label: 'Not now', onPress: () => answer(false) }))),
|
|
60
117
|
}), false);
|
|
61
118
|
},
|
|
62
119
|
options(missing, save) {
|
|
63
120
|
const saved = new Map();
|
|
64
121
|
const failures = new Map();
|
|
65
122
|
return show((answer) => ({
|
|
66
|
-
draw: () =>
|
|
67
|
-
const label =
|
|
123
|
+
draw: () => dialog(Text({ bold: true, children: `Set up ${name}` }), Text({ children: `${name} needs ${missing.length === 1 ? 'one setting' : `${missing.length} settings`}:` }), ...missing.map(([key, option]) => {
|
|
124
|
+
const label = Box({ flexDirection: 'column', children: [Text({ bold: true, children: option.title }), ...(option.description === '' ? [] : [Text({ dimColor: true, wrap: 'wrap', children: option.description })])] });
|
|
68
125
|
if (option.type === 'secret') {
|
|
69
|
-
return Box({
|
|
70
|
-
flexDirection: 'column',
|
|
71
|
-
children: [label, Text({ dimColor: true, children: `${secretFix} Then press Next.` }), Button({ key: `secret:${key}`, label: 'Open /config', onPress: () => void claude().command.run({ command: 'config' }) })],
|
|
72
|
-
});
|
|
126
|
+
return Box({ flexDirection: 'column', children: [label, Text({ dimColor: true, wrap: 'wrap', children: `${secretFix} Then press Next.` }), filledButton({ key: `secret:${key}`, label: 'Open /config', onPress: () => void claude().command.run({ command: 'config' }) })] });
|
|
73
127
|
}
|
|
74
128
|
const failure = failures.get(key);
|
|
75
129
|
const field = Input({
|
|
@@ -88,11 +142,11 @@ export function createInstaller(name, claude, waiting) {
|
|
|
88
142
|
failures.set(key, refused);
|
|
89
143
|
})
|
|
90
144
|
.catch((error) => failures.set(key, messageOf(error)))
|
|
91
|
-
.finally(
|
|
145
|
+
.finally(redraw),
|
|
92
146
|
});
|
|
93
|
-
const status = failure !== undefined ? Text({ color: 'error', children: failure }) : saved.has(key) ? Text({ color: 'success', children: '
|
|
94
|
-
return Box({ flexDirection: 'column', children: [label, field, status] });
|
|
95
|
-
}),
|
|
147
|
+
const status = failure !== undefined ? [Text({ color: 'error', wrap: 'wrap', children: failure })] : saved.has(key) ? [Text({ color: 'success', children: '✓ saved' })] : [];
|
|
148
|
+
return Box({ flexDirection: 'column', children: [label, field, ...status] });
|
|
149
|
+
}), actions(filledButton({ key: 'next', hotkey: 'x', variant: 'primary', label: 'Next', onPress: () => answer(true) }), filledButton({ key: 'not-now', hotkey: 'n', label: 'Not now', onPress: () => answer(false) }))),
|
|
96
150
|
}), false);
|
|
97
151
|
},
|
|
98
152
|
step(mod, step, index, total) {
|
|
@@ -104,7 +158,7 @@ export function createInstaller(name, claude, waiting) {
|
|
|
104
158
|
body = step.render(mod, props);
|
|
105
159
|
}
|
|
106
160
|
catch (error) {
|
|
107
|
-
body = Text({ color: 'error', children: `The ${step.title} step could not draw: ${messageOf(error)}` });
|
|
161
|
+
body = Text({ color: 'error', wrap: 'wrap', children: `The ${step.title} step could not draw: ${messageOf(error)}` });
|
|
108
162
|
}
|
|
109
163
|
const next = async () => {
|
|
110
164
|
try {
|
|
@@ -115,18 +169,22 @@ export function createInstaller(name, claude, waiting) {
|
|
|
115
169
|
catch (error) {
|
|
116
170
|
notice = { color: 'error', text: `The ${step.title} step's isDone failed: ${messageOf(error)}` };
|
|
117
171
|
}
|
|
118
|
-
|
|
172
|
+
await send({ redraw: true });
|
|
119
173
|
};
|
|
120
|
-
return
|
|
174
|
+
return dialog(Text({ children: [Text({ bold: true, children: step.title }), Text({ dimColor: true, children: ` (${index} of ${total})` })] }), body, ...(notice === undefined ? [] : [Text({ color: notice.color, wrap: 'wrap', children: notice.text })]), actions(filledButton({ key: 'next', hotkey: 'x', variant: 'primary', label: index === total ? 'Finish' : 'Next', onPress: () => void next() }), filledButton({ key: 'not-now', hotkey: 'n', label: 'Not now', onPress: () => answer(false) })));
|
|
121
175
|
},
|
|
122
176
|
}), false);
|
|
123
177
|
},
|
|
124
178
|
async close() {
|
|
125
|
-
|
|
179
|
+
question?.cancel();
|
|
180
|
+
question = undefined;
|
|
126
181
|
if (!isOpen)
|
|
127
182
|
return;
|
|
128
183
|
isOpen = false;
|
|
129
|
-
|
|
184
|
+
isSeen = false;
|
|
185
|
+
await send({ requests: [{ close: installPage }] }).catch(log('the install page stayed open'));
|
|
130
186
|
},
|
|
187
|
+
shown: () => new Promise((resolve) => void waitingForShow.push(resolve)),
|
|
188
|
+
collect,
|
|
131
189
|
};
|
|
132
190
|
}
|
package/runtime/lifecycle.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Args, EventResult, Frozen,
|
|
1
|
+
import type { Args, Caught, EventResult, Frozen, PluginOptions } from 'claude-code';
|
|
2
2
|
import type { Mod, ModDefinition } from '../mod.js';
|
|
3
3
|
import type { Options } from '../options.js';
|
|
4
4
|
import { type Steps } from '../records.js';
|
|
@@ -25,7 +25,7 @@ export type Lifecycle<State extends object> = {
|
|
|
25
25
|
readonly toasts: readonly ShownToast[];
|
|
26
26
|
start(claude: Claude, read: (claude: Claude) => Promise<Plugin>): Promise<void>;
|
|
27
27
|
route<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>): Promise<EventResult<N>>;
|
|
28
|
-
caught<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>, failure:
|
|
28
|
+
caught<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>, failure: Caught): Promise<EventResult<N>>;
|
|
29
29
|
raise(method: string, payload: Readonly<Record<string, unknown>>): Promise<unknown>;
|
|
30
30
|
};
|
|
31
31
|
export declare function readPlugin(claude: Claude): Promise<Plugin>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAqB,WAAW,EAAE,MAAM,EAAc,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"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"}
|