@cmodjs/core 0.3.0 → 1.5.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 +61 -10
- package/docs/dependencies.md +16 -14
- package/docs/hooks.md +64 -29
- package/docs/index.md +29 -25
- package/docs/install-steps.md +13 -9
- package/docs/jobs.md +59 -111
- package/docs/mod.md +227 -175
- package/docs/options.md +2 -2
- package/docs/permissions.md +27 -16
- package/docs/session.md +311 -0
- package/docs/state.md +11 -7
- package/docs/testing.md +68 -23
- package/docs/ui.md +116 -76
- package/jobs/check.d.ts.map +1 -1
- package/jobs/check.js +5 -2
- package/jobs/context.d.ts +7 -8
- package/jobs/context.d.ts.map +1 -1
- package/jobs/context.js +23 -73
- package/jobs/permissions/decide-permission.d.ts +5 -3
- package/jobs/permissions/decide-permission.d.ts.map +1 -1
- package/jobs/permissions/decide-permission.js +6 -4
- package/jobs/permissions/find-project-scope.d.ts +1 -1
- package/jobs/permissions/find-project-scope.d.ts.map +1 -1
- package/jobs/permissions/find-project-scope.js +8 -11
- package/jobs/permissions/match-target.d.ts +2 -2
- package/jobs/permissions/match-target.d.ts.map +1 -1
- package/jobs/permissions.d.ts +1 -1
- package/jobs/permissions.d.ts.map +1 -1
- package/jobs/permissions.js +6 -4
- package/jobs/program.d.ts.map +1 -1
- package/jobs/program.js +14 -4
- package/jobs/prompt.d.ts +4 -2
- package/jobs/prompt.d.ts.map +1 -1
- package/jobs/prompt.js +16 -15
- package/jobs/schedule.d.ts +2 -2
- package/jobs/schedule.d.ts.map +1 -1
- package/jobs/schedule.js +9 -9
- package/jobs/slash-command.d.ts +4 -4
- package/jobs/slash-command.d.ts.map +1 -1
- package/jobs/slash-command.js +14 -9
- package/jobs/status-line.d.ts +1 -11
- package/jobs/status-line.d.ts.map +1 -1
- package/jobs/status-line.js +8 -12
- package/jobs/tool.d.ts +2 -2
- package/jobs/tool.d.ts.map +1 -1
- package/jobs/tool.js +15 -9
- package/mod.d.ts +178 -75
- package/mod.d.ts.map +1 -1
- package/mod.js +127 -3
- package/options.d.ts +2 -2
- package/options.js +19 -19
- package/package.json +3 -3
- package/records.d.ts +13 -8
- package/records.d.ts.map +1 -1
- package/records.js +33 -17
- package/register.d.ts.map +1 -1
- package/register.js +34 -5
- package/runtime/announce.d.ts +18 -0
- package/runtime/announce.d.ts.map +1 -0
- package/runtime/announce.js +68 -0
- package/runtime/before.d.ts +32 -0
- package/runtime/before.d.ts.map +1 -0
- package/runtime/before.js +214 -0
- package/runtime/bound.d.ts +4 -0
- package/runtime/bound.d.ts.map +1 -0
- package/runtime/bound.js +9 -0
- package/runtime/claude.d.ts +4 -2
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/conversations.d.ts +17 -0
- package/runtime/conversations.d.ts.map +1 -0
- package/runtime/conversations.js +563 -0
- package/runtime/deadline.d.ts +0 -1
- package/runtime/deadline.d.ts.map +1 -1
- package/runtime/deadline.js +1 -1
- package/runtime/dependencies.d.ts +2 -0
- package/runtime/dependencies.d.ts.map +1 -1
- package/runtime/dependencies.js +10 -1
- package/runtime/engine.d.ts +13 -0
- package/runtime/engine.d.ts.map +1 -0
- package/runtime/engine.js +10 -0
- package/runtime/grants.d.ts +4 -0
- package/runtime/grants.d.ts.map +1 -1
- package/runtime/grants.js +68 -31
- package/runtime/hooks.d.ts +5 -4
- package/runtime/hooks.d.ts.map +1 -1
- package/runtime/hooks.js +29 -9
- package/runtime/installer.d.ts +1 -1
- package/runtime/installer.d.ts.map +1 -1
- package/runtime/installer.js +17 -14
- package/runtime/lifecycle.d.ts +3 -1
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +414 -212
- package/runtime/metadata.d.ts +3 -1
- package/runtime/metadata.d.ts.map +1 -1
- package/runtime/metadata.js +25 -14
- package/runtime/options.d.ts +3 -1
- package/runtime/options.d.ts.map +1 -1
- package/runtime/options.js +4 -4
- package/runtime/programs.d.ts +8 -0
- package/runtime/programs.d.ts.map +1 -1
- package/runtime/programs.js +39 -1
- package/runtime/router.d.ts +2 -1
- package/runtime/router.d.ts.map +1 -1
- package/runtime/router.js +11 -3
- package/runtime/sessions.d.ts +58 -0
- package/runtime/sessions.d.ts.map +1 -0
- package/runtime/sessions.js +433 -0
- package/runtime/state.d.ts +6 -2
- package/runtime/state.d.ts.map +1 -1
- package/runtime/state.js +46 -13
- package/runtime/toaster.d.ts +24 -0
- package/runtime/toaster.d.ts.map +1 -0
- package/runtime/toaster.js +286 -0
- package/runtime/ui.d.ts +6 -17
- package/runtime/ui.d.ts.map +1 -1
- package/runtime/ui.js +62 -118
- package/session/context/context.d.ts +12 -0
- package/session/context/context.d.ts.map +1 -0
- package/session/context/context.js +2 -0
- package/session/context/turn/message/document.d.ts +7 -0
- package/session/context/turn/message/document.d.ts.map +1 -0
- package/session/context/turn/message/document.js +1 -0
- package/session/context/turn/message/message.d.ts +55 -0
- package/session/context/turn/message/message.d.ts.map +1 -0
- package/session/context/turn/message/message.js +178 -0
- package/session/context/turn/message/note.d.ts +8 -0
- package/session/context/turn/message/note.d.ts.map +1 -0
- package/session/context/turn/message/note.js +1 -0
- package/session/context/turn/message/notice.d.ts +6 -0
- package/session/context/turn/message/notice.d.ts.map +1 -0
- package/session/context/turn/message/notice.js +1 -0
- package/session/context/turn/message/prompt.d.ts +8 -0
- package/session/context/turn/message/prompt.d.ts.map +1 -0
- package/session/context/turn/message/prompt.js +1 -0
- package/session/context/turn/message/reply.d.ts +6 -0
- package/session/context/turn/message/reply.d.ts.map +1 -0
- package/session/context/turn/message/reply.js +1 -0
- package/session/context/turn/message/sender.d.ts +14 -0
- package/session/context/turn/message/sender.d.ts.map +1 -0
- package/session/context/turn/message/sender.js +30 -0
- package/session/context/turn/message/skill.d.ts +7 -0
- package/session/context/turn/message/skill.d.ts.map +1 -0
- package/session/context/turn/message/skill.js +1 -0
- package/session/context/turn/message/tool-call.d.ts +9 -0
- package/session/context/turn/message/tool-call.d.ts.map +1 -0
- package/session/context/turn/message/tool-call.js +1 -0
- package/session/context/turn/message/tool-result.d.ts +8 -0
- package/session/context/turn/message/tool-result.d.ts.map +1 -0
- package/session/context/turn/message/tool-result.js +1 -0
- package/session/context/turn/turn.d.ts +13 -0
- package/session/context/turn/turn.d.ts.map +1 -0
- package/session/context/turn/turn.js +2 -0
- package/session/conversation.d.ts +73 -0
- package/session/conversation.d.ts.map +1 -0
- package/session/conversation.js +146 -0
- package/session/goal/goal.d.ts +11 -0
- package/session/goal/goal.d.ts.map +1 -0
- package/session/goal/goal.js +1 -0
- package/session/goal/task.d.ts +16 -0
- package/session/goal/task.d.ts.map +1 -0
- package/session/goal/task.js +3 -0
- package/session/session.d.ts +158 -0
- package/session/session.d.ts.map +1 -0
- package/session/session.js +2 -0
- package/src/jobs/check.ts +7 -4
- package/src/jobs/context.ts +24 -82
- package/src/jobs/permissions/decide-permission.ts +10 -8
- package/src/jobs/permissions/find-project-scope.ts +8 -14
- package/src/jobs/permissions/match-target.ts +3 -3
- package/src/jobs/permissions.ts +8 -6
- package/src/jobs/program.ts +13 -4
- package/src/jobs/prompt.ts +21 -24
- package/src/jobs/schedule.ts +14 -14
- package/src/jobs/slash-command.ts +20 -14
- package/src/jobs/status-line.ts +9 -21
- package/src/jobs/tool.ts +17 -11
- package/src/mod.ts +252 -97
- package/src/options.ts +22 -22
- package/src/records.ts +40 -23
- package/src/register.ts +34 -5
- package/src/runtime/announce.ts +76 -0
- package/src/runtime/before.ts +200 -0
- package/src/runtime/bound.ts +12 -0
- package/src/runtime/claude.ts +7 -2
- package/src/runtime/conversations.ts +579 -0
- package/src/runtime/deadline.ts +2 -2
- package/src/runtime/dependencies.ts +13 -1
- package/src/runtime/engine.ts +23 -0
- package/src/runtime/grants.ts +69 -29
- package/src/runtime/hooks.ts +39 -14
- package/src/runtime/installer.ts +16 -14
- package/src/runtime/lifecycle.ts +413 -201
- package/src/runtime/metadata.ts +37 -14
- package/src/runtime/options.ts +19 -4
- package/src/runtime/programs.ts +40 -1
- package/src/runtime/router.ts +11 -4
- package/src/runtime/sessions.ts +447 -0
- package/src/runtime/state.ts +50 -14
- package/src/runtime/toaster.ts +334 -0
- package/src/runtime/ui.ts +65 -143
- package/src/session/context/context.ts +14 -0
- package/src/session/context/turn/message/document.ts +8 -0
- package/src/session/context/turn/message/message.ts +203 -0
- package/src/session/context/turn/message/note.ts +9 -0
- package/src/session/context/turn/message/notice.ts +7 -0
- package/src/session/context/turn/message/prompt.ts +9 -0
- package/src/session/context/turn/message/reply.ts +7 -0
- package/src/session/context/turn/message/sender.ts +38 -0
- package/src/session/context/turn/message/skill.ts +8 -0
- package/src/session/context/turn/message/tool-call.ts +10 -0
- package/src/session/context/turn/message/tool-result.ts +9 -0
- package/src/session/context/turn/turn.ts +15 -0
- package/src/session/conversation.ts +194 -0
- package/src/session/goal/goal.ts +10 -0
- package/src/session/goal/task.ts +19 -0
- package/src/session/session.ts +141 -0
- package/src/testing/fake-claude.ts +25 -17
- package/src/testing/fake-elements.ts +3 -2
- package/src/testing/fake-files.ts +1 -1
- package/src/testing/fake-sessions.ts +277 -0
- package/src/testing.ts +138 -35
- package/src/ui/components.ts +3 -3
- package/src/ui/elements.ts +22 -8
- package/src/ui/markdown.ts +22 -26
- package/src/ui/places.ts +49 -0
- package/src/utils/call-effects.ts +5 -5
- package/src/utils/changelog.ts +32 -0
- package/src/utils/disposable.ts +3 -0
- package/src/utils/matcher.ts +37 -0
- package/src/utils/metadata.ts +17 -15
- package/src/utils/parse-shell.ts +9 -8
- package/src/utils/paths.ts +21 -4
- package/src/utils/text.ts +4 -0
- package/testing/fake-claude.d.ts +5 -1
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +21 -12
- package/testing/fake-elements.js +4 -2
- package/testing/fake-files.js +1 -1
- package/testing/fake-sessions.d.ts +81 -0
- package/testing/fake-sessions.d.ts.map +1 -0
- package/testing/fake-sessions.js +249 -0
- package/testing.d.ts +34 -13
- package/testing.d.ts.map +1 -1
- package/testing.js +115 -23
- package/ui/components.d.ts +2 -3
- package/ui/components.d.ts.map +1 -1
- package/ui/components.js +3 -3
- package/ui/elements.d.ts.map +1 -1
- package/ui/elements.js +19 -9
- package/ui/markdown.d.ts +35 -33
- package/ui/markdown.d.ts.map +1 -1
- package/ui/markdown.js +14 -16
- package/ui/places.d.ts +43 -0
- package/ui/places.d.ts.map +1 -0
- package/ui/places.js +31 -0
- package/utils/call-effects.d.ts +2 -1
- package/utils/call-effects.d.ts.map +1 -1
- package/utils/call-effects.js +3 -3
- package/utils/changelog.d.ts +9 -0
- package/utils/changelog.d.ts.map +1 -0
- package/utils/changelog.js +29 -0
- package/utils/disposable.d.ts +4 -0
- package/utils/disposable.d.ts.map +1 -0
- package/utils/disposable.js +1 -0
- package/utils/matcher.d.ts +13 -0
- package/utils/matcher.d.ts.map +1 -0
- package/utils/matcher.js +32 -0
- package/utils/metadata.d.ts +3 -3
- package/utils/metadata.js +18 -14
- package/utils/parse-shell.js +9 -7
- package/utils/paths.d.ts +4 -1
- package/utils/paths.d.ts.map +1 -1
- package/utils/paths.js +19 -4
- package/utils/text.d.ts +1 -0
- package/utils/text.d.ts.map +1 -1
- package/utils/text.js +3 -0
- package/src/ui/slots.ts +0 -36
- package/ui/slots.d.ts +0 -208
- package/ui/slots.d.ts.map +0 -1
- package/ui/slots.js +0 -19
package/runtime/grants.d.ts
CHANGED
|
@@ -9,10 +9,14 @@ export type Grants = {
|
|
|
9
9
|
readonly configRoot: string | undefined;
|
|
10
10
|
readonly projectRoot: () => string;
|
|
11
11
|
readonly freeFolders: () => readonly string[];
|
|
12
|
+
readonly freeAddresses: () => ReadonlySet<string>;
|
|
12
13
|
};
|
|
13
14
|
export declare class PermissionRefused extends Error {
|
|
14
15
|
}
|
|
16
|
+
export declare function programAddresses(mod: object): Set<string>;
|
|
17
|
+
export declare function checkGrant(grants: Grants, call: string, item: string | undefined): Promise<void>;
|
|
15
18
|
export declare function checkWrite(grants: Grants, call: string, path: string): Promise<void>;
|
|
19
|
+
export declare function checkSettings(grants: Grants, source: 'user' | 'project' | 'local', keys: readonly string[]): Promise<void>;
|
|
16
20
|
export declare function checkingGrants(claude: Claude, grants: Grants): Claude;
|
|
17
21
|
export declare function itemOf(name: string, value?: string): string;
|
|
18
22
|
export declare function isCovered(granted: ReadonlySet<string>, item: string, home: string | undefined): boolean;
|
package/runtime/grants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/runtime/grants.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/runtime/grants.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE,CAAA;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;CAClD,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAI/C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAIzD;AAkBD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAItG;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1F;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhI;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAkFrE;AAmBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUvG;AAiBD,wBAAgB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9G;AA4BD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAa9G;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CA+BxJ"}
|
package/runtime/grants.js
CHANGED
|
@@ -1,19 +1,42 @@
|
|
|
1
|
-
import { permissionWords } from '../records.js';
|
|
1
|
+
import { isObject, permissionWords } from '../records.js';
|
|
2
2
|
import { relativePath } from '../utils/paths.js';
|
|
3
|
+
import { cmodPluginName } from './dependencies.js';
|
|
4
|
+
import { actPermission, conversationMethods, isAct, toolPermission } from './sessions.js';
|
|
3
5
|
export class PermissionRefused extends Error {
|
|
4
6
|
}
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const addressesOfPrograms = new WeakMap();
|
|
8
|
+
export function programAddresses(mod) {
|
|
9
|
+
const known = addressesOfPrograms.get(mod) ?? new Set();
|
|
10
|
+
addressesOfPrograms.set(mod, known);
|
|
11
|
+
return known;
|
|
12
|
+
}
|
|
13
|
+
const projectSettingsFiles = ['.claude/settings.json', '.claude/settings.local.json', '.mcp.json'];
|
|
14
|
+
const conversationCalls = {
|
|
15
|
+
[conversationMethods.sessions]: 'sessions.list',
|
|
16
|
+
[conversationMethods.search]: 'sessions.search',
|
|
17
|
+
[conversationMethods.messages]: 'messages',
|
|
18
|
+
[conversationMethods.turns]: 'turns',
|
|
19
|
+
[conversationMethods.contexts]: 'contexts',
|
|
20
|
+
[conversationMethods.tasks]: 'tasks',
|
|
21
|
+
[conversationMethods.goal]: 'goal',
|
|
22
|
+
[conversationMethods.updateGoal]: 'goal.update',
|
|
23
|
+
[conversationMethods.subscribe]: 'on',
|
|
24
|
+
[conversationMethods.watchBefore]: 'before',
|
|
25
|
+
[conversationMethods.act]: 'act',
|
|
26
|
+
};
|
|
27
|
+
export async function checkGrant(grants, call, item) {
|
|
9
28
|
if (item === undefined)
|
|
10
29
|
return;
|
|
11
30
|
await grants.refresh();
|
|
12
31
|
if (!isCovered(grants.granted(), item, grants.home))
|
|
13
32
|
throw new PermissionRefused(refusal(grants, call, item));
|
|
14
33
|
}
|
|
15
|
-
export function checkWrite(grants, call, path) {
|
|
16
|
-
|
|
34
|
+
export async function checkWrite(grants, call, path) {
|
|
35
|
+
await checkGrant(grants, call, writeItem(grants, path));
|
|
36
|
+
}
|
|
37
|
+
export async function checkSettings(grants, source, keys) {
|
|
38
|
+
for (const key of keys)
|
|
39
|
+
await checkGrant(grants, `settings.${source}.update(${key})`, `config:${key}`);
|
|
17
40
|
}
|
|
18
41
|
export function checkingGrants(claude, grants) {
|
|
19
42
|
const gate = (call, item) => checkGrant(grants, call, item);
|
|
@@ -42,7 +65,8 @@ export function checkingGrants(claude, grants) {
|
|
|
42
65
|
},
|
|
43
66
|
http: {
|
|
44
67
|
async fetch(url, init) {
|
|
45
|
-
|
|
68
|
+
if (!grants.freeAddresses().has(init?.socketPath ?? addressOf(url)))
|
|
69
|
+
await gate(`http.fetch(${url})`, `network:${init?.socketPath ?? hostOf(url)}`);
|
|
46
70
|
return claude.http.fetch(url, init);
|
|
47
71
|
},
|
|
48
72
|
},
|
|
@@ -52,37 +76,50 @@ export function checkingGrants(claude, grants) {
|
|
|
52
76
|
await gate('session.messages', 'conversation');
|
|
53
77
|
return claude.session.messages(...args);
|
|
54
78
|
}),
|
|
55
|
-
append:
|
|
56
|
-
await gate('
|
|
79
|
+
append: async (args) => {
|
|
80
|
+
await gate('send', 'prompt');
|
|
57
81
|
return claude.session.append(args);
|
|
58
|
-
}
|
|
82
|
+
},
|
|
83
|
+
send: async (args) => {
|
|
84
|
+
await gate('send', 'prompt');
|
|
85
|
+
return claude.session.send(args);
|
|
86
|
+
},
|
|
59
87
|
},
|
|
60
88
|
prompt: {
|
|
61
|
-
submit:
|
|
62
|
-
await gate('
|
|
89
|
+
submit: async (args) => {
|
|
90
|
+
await gate('send', 'prompt');
|
|
63
91
|
return claude.prompt.submit(args);
|
|
64
|
-
}
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
cmod: {
|
|
95
|
+
async call(args) {
|
|
96
|
+
const named = args.to === cmodPluginName ? conversationCalls[args.method] : undefined;
|
|
97
|
+
const given = args.method === conversationMethods.act && isObject(args.input) ? String(args.input['action']) : undefined;
|
|
98
|
+
const action = given !== undefined && isAct(given) ? given : undefined;
|
|
99
|
+
if (named !== undefined)
|
|
100
|
+
await gate(action ?? named, action === undefined ? 'conversation' : actPermission(action, isObject(args.input) ? args.input['input'] : undefined));
|
|
101
|
+
return claude.cmod.call(args);
|
|
102
|
+
},
|
|
65
103
|
},
|
|
66
104
|
model: {
|
|
67
|
-
complete:
|
|
105
|
+
complete: async (...args) => {
|
|
68
106
|
await gate('model.complete', 'model');
|
|
69
107
|
return claude.model.complete(...args);
|
|
70
|
-
}
|
|
108
|
+
},
|
|
71
109
|
},
|
|
72
110
|
agent: {
|
|
73
111
|
...claude.agent,
|
|
74
112
|
async spawn(args) {
|
|
75
|
-
await gate('
|
|
113
|
+
await gate('startTask', 'tasks');
|
|
76
114
|
return claude.agent.spawn(args);
|
|
77
115
|
},
|
|
78
116
|
},
|
|
79
117
|
tool: {
|
|
80
118
|
...claude.tool,
|
|
81
|
-
call:
|
|
82
|
-
|
|
83
|
-
await gate(`tool.call(${input.tool})`, item);
|
|
119
|
+
call: async (input) => {
|
|
120
|
+
await gate(`tool.call(${input.tool})`, toolPermission(input.tool));
|
|
84
121
|
return claude.tool.call(input);
|
|
85
|
-
}
|
|
122
|
+
},
|
|
86
123
|
},
|
|
87
124
|
};
|
|
88
125
|
}
|
|
@@ -92,8 +129,8 @@ function spawned(started) {
|
|
|
92
129
|
const stream = {
|
|
93
130
|
next: async () => (await started).next(),
|
|
94
131
|
async return(value) {
|
|
95
|
-
const
|
|
96
|
-
return
|
|
132
|
+
const [start] = await Promise.allSettled([started]);
|
|
133
|
+
return start.status === 'fulfilled' ? start.value.return(value) : { done: true, value };
|
|
97
134
|
},
|
|
98
135
|
[Symbol.asyncIterator]: () => stream,
|
|
99
136
|
result,
|
|
@@ -125,8 +162,10 @@ function readItem(grants, path) {
|
|
|
125
162
|
}
|
|
126
163
|
function writeItem(grants, path) {
|
|
127
164
|
const root = grants.projectRoot();
|
|
128
|
-
|
|
129
|
-
|
|
165
|
+
const settingsFiles = [...projectSettingsFiles.map((file) => `${root}/${file}`), ...(grants.configRoot === undefined ? [] : [`${grants.configRoot}/settings.json`])];
|
|
166
|
+
if (settingsFiles.includes(path)) {
|
|
167
|
+
throw new PermissionRefused(`${grants.name} writes ${path} by hand. Change Claude Code's settings with settings.user.update, settings.project.update, or settings.local.update, which keep the person's own edits and take the mod's values out when it is removed.`);
|
|
168
|
+
}
|
|
130
169
|
if (grants.freeFolders().some((folder) => relativePath(folder, path) !== undefined))
|
|
131
170
|
return undefined;
|
|
132
171
|
return `files:${path}`;
|
|
@@ -267,12 +306,10 @@ function programOf(argv) {
|
|
|
267
306
|
return command.slice(command.lastIndexOf('/') + 1);
|
|
268
307
|
}
|
|
269
308
|
function hostOf(url) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return url;
|
|
275
|
-
}
|
|
309
|
+
return URL.canParse(url) ? new URL(url).hostname : url;
|
|
310
|
+
}
|
|
311
|
+
function addressOf(url) {
|
|
312
|
+
return URL.canParse(url) ? new URL(url).host : url;
|
|
276
313
|
}
|
|
277
314
|
function expanded(path, home) {
|
|
278
315
|
return path.startsWith('~/') && home !== undefined ? `${home}${path.slice(1)}` : path;
|
package/runtime/hooks.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Hook, HookListener } from '../mod.js';
|
|
2
2
|
import type { Claude } from './claude.js';
|
|
3
3
|
import type { RoutedHook } from './router.js';
|
|
4
|
+
import type { Failure } from './toaster.js';
|
|
4
5
|
import { type ToolCalls } from './tool-calls.js';
|
|
5
|
-
export type RoutedEvent = `classic.${Exclude<
|
|
6
|
+
export type RoutedEvent = `classic.${Exclude<Hook, 'PreToolUse'>}` | 'tool.check' | 'tool.call' | 'prompt.submit' | 'prompt.context' | 'prompt.attachment' | 'command.run' | 'session.measure' | 'skill.prompt' | 'ui.render' | 'ui.press' | 'ui.scroll' | 'ui.close' | 'cmod.call' | 'session.append' | 'session.compact' | 'session.receive' | 'agent.spawn';
|
|
6
7
|
export declare const permissionEvents: readonly RoutedEvent[];
|
|
7
|
-
export declare function classicHook<E extends Exclude<
|
|
8
|
+
export declare function classicHook<E extends Exclude<Hook, 'PreToolUse'>>(name: string, event: E, hook: HookListener<E>, claude: Claude, calls: ToolCalls, report: (failure: Failure) => void): RoutedHook<RoutedEvent>;
|
|
8
9
|
type HeldDecision = {
|
|
9
10
|
readonly decision: 'allow' | 'ask';
|
|
10
11
|
readonly reason?: string;
|
|
11
12
|
};
|
|
12
13
|
export type HeldDecisions = Map<string, HeldDecision>;
|
|
13
|
-
export declare function preToolUseHook(name: string, hook:
|
|
14
|
+
export declare function preToolUseHook(name: string, hook: HookListener<'PreToolUse'>, claude: Claude, calls: ToolCalls, held: HeldDecisions | undefined): RoutedHook<'tool.call'>;
|
|
14
15
|
export declare function heldDecisionHook(held: HeldDecisions): RoutedHook<'tool.check'>;
|
|
15
16
|
export declare function userSkillHook(claude: Claude): RoutedHook<'skill.prompt'>;
|
|
16
17
|
export declare const strictness: readonly ['allow', 'ask', 'deny'];
|
package/runtime/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/runtime/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/runtime/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAyB,YAAY,EAAE,MAAM,WAAW,CAAA;AAE1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAM3E,MAAM,MAAM,WAAW,GACnB,WAAW,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,GACxC,YAAY,GACZ,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,mBAAmB,GACnB,aAAa,GACb,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,aAAa,CAAA;AAEjB,eAAO,MAAM,gBAAgB,EAAE,SAAS,WAAW,EAAgD,CAAA;AA4CnG,wBAAgB,WAAW,CAAC,CAAC,SAAS,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAuB/M;AAED,KAAK,YAAY,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpF,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;AAErD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CA6BzK;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,CAAC,YAAY,CAAC,CAM9E;AAYD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAexE;AAgED,eAAO,MAAM,UAAU,YAAI,OAAO,EAAE,KAAK,EAAE,MAAM,CAAU,CAAA"}
|
package/runtime/hooks.js
CHANGED
|
@@ -2,30 +2,46 @@ import { configFolders } from '../records.js';
|
|
|
2
2
|
import { reservedKeys, toolInputOf } from './tool-calls.js';
|
|
3
3
|
import { callEffects, inputOf } from '../utils/call-effects.js';
|
|
4
4
|
import { dynamicPattern } from '../utils/parse-shell.js';
|
|
5
|
+
import { isMissing } from '../utils/paths.js';
|
|
5
6
|
import { messageOf } from '../utils/text.js';
|
|
6
7
|
export const permissionEvents = ['tool.check', 'classic.PermissionRequest'];
|
|
7
8
|
const flags = ['suppressOriginalPrompt', 'reloadSkills', 'retry'];
|
|
8
9
|
const readFields = {
|
|
10
|
+
Setup: ['additionalContext'],
|
|
9
11
|
SessionStart: ['additionalContext', 'initialUserMessage', 'sessionTitle', 'watchPaths', 'reloadSkills'],
|
|
10
12
|
SessionEnd: [],
|
|
11
13
|
UserPromptSubmit: ['additionalContext', 'sessionTitle', 'suppressOriginalPrompt'],
|
|
14
|
+
UserPromptExpansion: ['additionalContext', 'suppressOriginalPrompt'],
|
|
12
15
|
InstructionsLoaded: [],
|
|
16
|
+
ConfigChange: [],
|
|
17
|
+
DirectoryAdded: [],
|
|
18
|
+
PreModelSwitch: ['permissionDecision', 'permissionDecisionReason'],
|
|
19
|
+
PostModelSwitch: ['additionalContext'],
|
|
13
20
|
PreToolUse: ['additionalContext', 'permissionDecision', 'permissionDecisionReason', 'updatedInput'],
|
|
14
21
|
PermissionRequest: ['decision'],
|
|
15
22
|
PermissionDenied: ['retry'],
|
|
16
23
|
PostToolUse: ['additionalContext', 'updatedToolOutput', 'updatedMCPToolOutput'],
|
|
17
24
|
PostToolUseFailure: ['additionalContext'],
|
|
18
25
|
PostToolBatch: ['additionalContext'],
|
|
26
|
+
MessageDisplay: ['displayContent'],
|
|
19
27
|
SubagentStart: ['additionalContext'],
|
|
20
28
|
SubagentStop: ['additionalContext'],
|
|
29
|
+
TaskCreated: [],
|
|
30
|
+
TaskCompleted: [],
|
|
31
|
+
TeammateIdle: [],
|
|
32
|
+
Elicitation: [],
|
|
33
|
+
ElicitationResult: [],
|
|
21
34
|
Notification: [],
|
|
22
35
|
PreCompact: [],
|
|
36
|
+
PostCompact: [],
|
|
23
37
|
Stop: ['additionalContext'],
|
|
24
38
|
StopFailure: [],
|
|
25
39
|
CwdChanged: [],
|
|
26
40
|
FileChanged: [],
|
|
41
|
+
WorktreeCreate: ['worktreePath'],
|
|
42
|
+
WorktreeRemove: [],
|
|
27
43
|
};
|
|
28
|
-
export function classicHook(name, event, hook, claude, calls) {
|
|
44
|
+
export function classicHook(name, event, hook, claude, calls, report) {
|
|
29
45
|
const hookInputOf = async (e) => {
|
|
30
46
|
if (event !== 'PostToolUse' && event !== 'PostToolUseFailure')
|
|
31
47
|
return e;
|
|
@@ -43,10 +59,9 @@ export function classicHook(name, event, hook, claude, calls) {
|
|
|
43
59
|
};
|
|
44
60
|
const routed = async (e, next) => {
|
|
45
61
|
const ours = await resultOf(e).catch((error) => {
|
|
46
|
-
const reason = `${name}: the ${event} hook failed: ${messageOf(error)}`;
|
|
47
62
|
if (event === 'PermissionRequest')
|
|
48
|
-
return { decision: { behavior: 'deny', message:
|
|
49
|
-
|
|
63
|
+
return { decision: { behavior: 'deny', message: `${name}: the ${event} hook failed: ${messageOf(error)}` } };
|
|
64
|
+
report({ id: `hook:${event}`, message: `The ${event} hook failed`, error });
|
|
50
65
|
return undefined;
|
|
51
66
|
});
|
|
52
67
|
if (ours === undefined)
|
|
@@ -146,12 +161,17 @@ async function preToolUseInput(name, envelope, claude, agentOf) {
|
|
|
146
161
|
}
|
|
147
162
|
async function callFiles(name, claude, use, cwd) {
|
|
148
163
|
try {
|
|
149
|
-
const home = await claude.env.home();
|
|
164
|
+
const [home, configRoot] = await Promise.all([claude.env.home(), claude.env.configHome()]);
|
|
150
165
|
if (home === undefined)
|
|
151
166
|
throw new Error('HOME is not set, so ~ in a path has no meaning.');
|
|
152
|
-
const { shell, reads, writes } = callEffects(use, { cwd, home, fs: claude.fs });
|
|
167
|
+
const { shell, reads, writes } = callEffects(use, { cwd, home, ...(configRoot === undefined ? {} : { configRoot }), fs: claude.fs });
|
|
153
168
|
const known = (accesses) => accesses.map(({ path }) => path).filter((path) => shell === undefined || !dynamicPattern.test(path));
|
|
154
|
-
const
|
|
169
|
+
const unchecked = (path) => (error) => {
|
|
170
|
+
if (!isMissing(error))
|
|
171
|
+
claude.ui.log(`${name}: the ${use.tool} call reads ${path}, which could not be checked: ${messageOf(error)}`, { to: 'debug' });
|
|
172
|
+
return undefined;
|
|
173
|
+
};
|
|
174
|
+
const read = await Promise.all(known(reads).map(async (path) => ((await claude.fs.stat(path).catch(unchecked(path)))?.kind === 'file' ? [path] : [])));
|
|
155
175
|
return { read: read.flat(), changed: known(writes) };
|
|
156
176
|
}
|
|
157
177
|
catch (error) {
|
|
@@ -187,11 +207,11 @@ function classicResult(event, answer) {
|
|
|
187
207
|
throw unread(`hookSpecificOutput.${field}`);
|
|
188
208
|
if (field === 'additionalContext')
|
|
189
209
|
result['additionalContext'] = [value];
|
|
190
|
-
else if (field === 'permissionDecision') {
|
|
210
|
+
else if (field === 'permissionDecision' && event === 'PreToolUse') {
|
|
191
211
|
const reason = specific.permissionDecisionReason ?? '';
|
|
192
212
|
result[value] = value === 'allow' ? true : reason;
|
|
193
213
|
}
|
|
194
|
-
else if (field !== 'permissionDecisionReason')
|
|
214
|
+
else if (field !== 'permissionDecisionReason' || event !== 'PreToolUse')
|
|
195
215
|
result[field] = value;
|
|
196
216
|
}
|
|
197
217
|
return result;
|
package/runtime/installer.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Step } from '../installer.js';
|
|
|
3
3
|
import type { Mod } from '../mod.js';
|
|
4
4
|
import type { Option } from '../options.js';
|
|
5
5
|
import type { Claude } from './claude.js';
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const installerPaneOf: (name: string) => string;
|
|
7
7
|
export type Consent = {
|
|
8
8
|
readonly install: string;
|
|
9
9
|
readonly uninstall: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAA;AAC7E,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;AAI3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAA;AAC7E,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;AAI3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,MAA0E,CAAA;AAEzH,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,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,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAA;IAC5C,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,aAAa,CAAA;IACjD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,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;CACvB,CAAA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,CAwI7E"}
|
package/runtime/installer.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { permissionWords } from '../records.js';
|
|
2
2
|
import { Box, Button, drawWith, Input, Text } from '../ui/elements.js';
|
|
3
3
|
import { messageOf } from '../utils/text.js';
|
|
4
|
-
export const
|
|
4
|
+
export const installerPaneOf = (name) => `installer-${name.replace(/[^A-Za-z0-9_-]/g, '_')}`.slice(0, 64);
|
|
5
5
|
export function createInstaller(name, claude) {
|
|
6
|
+
const paneId = installerPaneOf(name);
|
|
6
7
|
let page;
|
|
7
8
|
let isOpen = false;
|
|
8
9
|
const show = async (build, cancelled) => {
|
|
@@ -18,7 +19,7 @@ export function createInstaller(name, claude) {
|
|
|
18
19
|
});
|
|
19
20
|
if (!isOpen) {
|
|
20
21
|
isOpen = true;
|
|
21
|
-
await claude().ui.open({ id:
|
|
22
|
+
await claude().ui.open({ id: paneId, title: `Install ${name}`, focus: true, holdToasts: true, closeOnEscape: true });
|
|
22
23
|
}
|
|
23
24
|
claude().ui.invalidate('ui.render');
|
|
24
25
|
return answer;
|
|
@@ -26,12 +27,12 @@ export function createInstaller(name, claude) {
|
|
|
26
27
|
const frame = (title, body, actions) => Box({ flexDirection: 'column', gap: 1, paddingX: 1, children: [Text({ bold: true, children: title }), ...body, Box({ gap: 3, children: actions })] });
|
|
27
28
|
const bullet = (text) => Text({ children: [Text({ color: 'claude', children: '◆ ' }), text] });
|
|
28
29
|
return {
|
|
29
|
-
draws: (e) => e.component === 'Pane' && e.requestId ===
|
|
30
|
+
draws: (e) => e.component === 'Pane' && e.requestId === paneId,
|
|
30
31
|
draw(e) {
|
|
31
32
|
return drawWith(claude().ui.resolve(e), () => page?.draw(e.props) ?? Text({ dimColor: true, children: `${name} is installing.` }));
|
|
32
33
|
},
|
|
33
34
|
closed(id) {
|
|
34
|
-
if (id !==
|
|
35
|
+
if (id !== paneId)
|
|
35
36
|
return;
|
|
36
37
|
isOpen = false;
|
|
37
38
|
page?.cancel();
|
|
@@ -57,13 +58,13 @@ export function createInstaller(name, claude) {
|
|
|
57
58
|
return show((answer) => ({
|
|
58
59
|
draw: () => frame(`${name} needs ${missing.length === 1 ? 'one setting' : `${missing.length} settings`}:`, missing.map(([key, option]) => {
|
|
59
60
|
const label = Text({ children: [Text({ bold: true, children: option.title }), option.description === '' ? '' : Text({ dimColor: true, children: ` ${option.description}` })] });
|
|
60
|
-
if (option.
|
|
61
|
+
if (option.type === 'secret')
|
|
61
62
|
return Box({ flexDirection: 'column', children: [label, Text({ dimColor: true, children: `Set it in /config, where Claude Code keeps it in your keychain, then press Next.` })] });
|
|
62
63
|
const failure = failures.get(key);
|
|
63
64
|
const field = Input({
|
|
64
65
|
key: `option:${key}`,
|
|
65
66
|
label: '› ',
|
|
66
|
-
placeholder: option.
|
|
67
|
+
placeholder: option.type === 'choice' ? (option.choices ?? []).join(', ') : option.type === 'toggle' ? 'true or false' : option.type === 'list' ? 'comma-separated' : '',
|
|
67
68
|
value: saved.get(key) ?? '',
|
|
68
69
|
submitLabel: 'save',
|
|
69
70
|
onSubmit: (value) => void save(key, value)
|
|
@@ -95,15 +96,17 @@ export function createInstaller(name, claude) {
|
|
|
95
96
|
body = Text({ color: 'error', children: `The ${step.title} step could not draw: ${messageOf(error)}` });
|
|
96
97
|
}
|
|
97
98
|
const next = async () => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
notice = `Finish ${step.title} first.`;
|
|
103
|
-
claude().ui.invalidate('ui.render');
|
|
99
|
+
try {
|
|
100
|
+
if (await step.isDone(mod))
|
|
101
|
+
return answer(true);
|
|
102
|
+
notice = { color: 'warning', text: `Finish ${step.title} first.` };
|
|
104
103
|
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
notice = { color: 'error', text: `The ${step.title} step's isDone failed: ${messageOf(error)}` };
|
|
106
|
+
}
|
|
107
|
+
claude().ui.invalidate('ui.render');
|
|
105
108
|
};
|
|
106
|
-
return frame(`${step.title} (${index} of ${total})`, [body, ...(notice === undefined ? [] : [Text({ color:
|
|
109
|
+
return frame(`${step.title} (${index} of ${total})`, [body, ...(notice === undefined ? [] : [Text({ color: notice.color, children: notice.text })])], [Button({ key: 'not-now', hotkey: 'n', label: 'Not now', onPress: () => answer(false) }), Button({ key: 'next', hotkey: 'x', label: index === total ? 'Finish' : 'Next', onPress: () => void next() })]);
|
|
107
110
|
},
|
|
108
111
|
}), false);
|
|
109
112
|
},
|
|
@@ -112,7 +115,7 @@ export function createInstaller(name, claude) {
|
|
|
112
115
|
if (!isOpen)
|
|
113
116
|
return;
|
|
114
117
|
isOpen = false;
|
|
115
|
-
await claude().ui.close({ id:
|
|
118
|
+
await claude().ui.close({ id: paneId });
|
|
116
119
|
},
|
|
117
120
|
};
|
|
118
121
|
}
|
package/runtime/lifecycle.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Args, EventResult, Frozen, PluginOptions } from 'claude-code';
|
|
2
|
-
import type
|
|
2
|
+
import { type Mod, type ModDefinition } from '../mod.js';
|
|
3
3
|
import type { Options } from '../options.js';
|
|
4
4
|
import { type Steps } from '../records.js';
|
|
5
5
|
import type { Claude } from './claude.js';
|
|
6
6
|
import { type RoutedEvent } from './hooks.js';
|
|
7
7
|
import { type RouterNext } from './router.js';
|
|
8
|
+
import { type ShownToast } from './toaster.js';
|
|
8
9
|
export type Plugin = {
|
|
9
10
|
readonly name: string;
|
|
10
11
|
readonly root: string;
|
|
@@ -20,6 +21,7 @@ export type Lifecycle<State extends object> = {
|
|
|
20
21
|
readonly phase: Phase;
|
|
21
22
|
readonly mod: Mod<State> | undefined;
|
|
22
23
|
readonly failure: unknown;
|
|
24
|
+
readonly toasts: readonly ShownToast[];
|
|
23
25
|
start(claude: Claude, read: (claude: Claude) => Promise<Plugin>): Promise<void>;
|
|
24
26
|
route<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>): Promise<EventResult<N>>;
|
|
25
27
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAc,aAAa,EAAwB,MAAM,aAAa,CAAA;AAE7G,OAAO,EAAkI,KAAK,GAAG,EAAE,KAAK,aAAa,EAAkD,MAAM,WAAW,CAAA;AACxO,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,eAAe,CAAA;AAC1D,OAAO,EAA2T,KAAK,KAAK,EAAE,MAAM,eAAe,CAAA;AAGnW,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAOzC,OAAO,EAAsG,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AAOjJ,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAMxE,OAAO,EAA+B,KAAK,UAAU,EAAgB,MAAM,cAAc,CAAA;AAMzF,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtG,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/E,KAAK,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;CACzG,CAAA;AAwCD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBhE;AAkCD,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,OAAO,GAAG,OAAO,EACtF,UAAU,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAClD,iBAAiB,GAAE,MAAM,OAAoB,EAC7C,OAAO,GAAE,aAAkB,EAC3B,UAAU,UAAO,GAChB,SAAS,CAAC,KAAK,CAAC,CAkclB"}
|