@cmodjs/core 0.1.7 → 0.1.9
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/README.md +2 -2
- package/docs/commands.md +14 -14
- package/docs/dependencies.md +1 -1
- package/docs/hooks.md +69 -13
- package/docs/index.md +7 -5
- package/docs/install-steps.md +19 -19
- package/docs/jobs.md +22 -21
- package/docs/mod.md +44 -12
- package/docs/state.md +8 -8
- package/docs/testing.md +25 -9
- package/docs/ui.md +33 -9
- package/jobs/check.js +2 -2
- package/jobs/context.d.ts.map +1 -1
- package/jobs/context.js +2 -0
- package/jobs/permissions/decide-permission.js +2 -2
- 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 +9 -9
- package/jobs/permissions/match-target.d.ts.map +1 -1
- package/jobs/permissions/match-target.js +4 -3
- package/mod.d.ts +15 -5
- package/mod.d.ts.map +1 -1
- package/package.json +2 -1
- package/path.d.ts +2 -0
- package/path.d.ts.map +1 -0
- package/path.js +1 -0
- package/records.js +3 -3
- package/register.d.ts.map +1 -1
- package/register.js +8 -2
- package/runtime/claude.d.ts +4 -1
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/hooks.d.ts +10 -2
- package/runtime/hooks.d.ts.map +1 -1
- package/runtime/hooks.js +56 -18
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +17 -7
- package/runtime/ui.d.ts.map +1 -1
- package/runtime/ui.js +38 -8
- package/shell.d.ts +2 -0
- package/shell.d.ts.map +1 -0
- package/shell.js +1 -0
- package/src/jobs/check.ts +2 -2
- package/src/jobs/context.ts +2 -0
- package/src/jobs/permissions/decide-permission.ts +2 -2
- package/src/jobs/permissions/find-project-scope.ts +11 -10
- package/src/jobs/permissions/match-target.ts +4 -3
- package/src/mod.ts +22 -3
- package/src/path.ts +1 -0
- package/src/records.ts +3 -3
- package/src/register.ts +8 -2
- package/src/runtime/claude.ts +11 -1
- package/src/runtime/hooks.ts +62 -23
- package/src/runtime/lifecycle.ts +16 -9
- package/src/runtime/ui.ts +35 -8
- package/src/shell.ts +1 -0
- package/src/testing/fake-claude.ts +14 -5
- package/src/testing/fake-elements.ts +5 -7
- package/src/testing/fake-files.ts +5 -5
- package/src/testing.ts +83 -11
- package/src/ui/define-pane.ts +5 -1
- package/src/utils/call-effects.ts +12 -11
- package/src/utils/parse-shell.ts +28 -36
- package/src/utils/paths.ts +4 -19
- package/src/vendor.ts +1 -0
- package/testing/fake-claude.d.ts +5 -0
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +13 -3
- package/testing/fake-elements.d.ts +5 -8
- package/testing/fake-elements.d.ts.map +1 -1
- package/testing/fake-elements.js +6 -6
- package/testing/fake-files.js +5 -5
- package/testing.d.ts +4 -2
- package/testing.d.ts.map +1 -1
- package/testing.js +65 -9
- package/ui/define-pane.d.ts +5 -1
- package/ui/define-pane.d.ts.map +1 -1
- package/utils/call-effects.d.ts.map +1 -1
- package/utils/call-effects.js +12 -11
- package/utils/parse-shell.d.ts +5 -9
- package/utils/parse-shell.d.ts.map +1 -1
- package/utils/parse-shell.js +5 -10
- package/utils/paths.d.ts +0 -3
- package/utils/paths.d.ts.map +1 -1
- package/utils/paths.js +3 -18
- package/vendor.d.ts +1 -0
- package/vendor.d.ts.map +1 -1
- package/vendor.js +209 -12
package/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,QAAQ,EACR,gBAAgB,
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["src/mod.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmodjs/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Build Claude Code mods: hooks, panes, permissions, checks, and an install that just works.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"mdast-util-to-string": "^4.0.0",
|
|
44
44
|
"micromark-extension-gfm": "^3.0.0",
|
|
45
45
|
"oxlint": "1.86.0",
|
|
46
|
+
"pathe": "^2.0.3",
|
|
46
47
|
"picomatch": "^4.0.7",
|
|
47
48
|
"shell-quote": "^1.12.0",
|
|
48
49
|
"typescript": "^7.0.2"
|
package/path.d.ts
ADDED
package/path.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA"}
|
package/path.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve } from './vendor.js';
|
package/records.js
CHANGED
|
@@ -6,7 +6,7 @@ export function storeFolder(env) {
|
|
|
6
6
|
if (dataHome)
|
|
7
7
|
return `${dataHome}/cmod`;
|
|
8
8
|
if (!home)
|
|
9
|
-
throw new Error('Neither XDG_DATA_HOME nor HOME is set, so the
|
|
9
|
+
throw new Error('Neither XDG_DATA_HOME nor HOME is set, so the cmod store has no folder. Set HOME.');
|
|
10
10
|
return `${home}/.local/share/cmod`;
|
|
11
11
|
}
|
|
12
12
|
export function recordPath(store, name) {
|
|
@@ -56,7 +56,7 @@ function parseRecord(text, path) {
|
|
|
56
56
|
throw new Error(`${path} is not JSON (${messageOf(error)}). ${fix}`);
|
|
57
57
|
}
|
|
58
58
|
if (!isObject(value))
|
|
59
|
-
throw new Error(`${path} is not a
|
|
59
|
+
throw new Error(`${path} is not a cmod install record. ${fix}`);
|
|
60
60
|
for (const key of ['name', 'version', 'root', 'installedAt', 'scriptsSha256']) {
|
|
61
61
|
if (typeof value[key] !== 'string')
|
|
62
62
|
throw new Error(`${path} has no "${key}" text. ${fix}`);
|
|
@@ -102,7 +102,7 @@ function readCommand(steps, key) {
|
|
|
102
102
|
throw new Error(`package.json "cmod.${key}" holds a line break or a tab. Write one command, such as "./setup/${key}.sh".`);
|
|
103
103
|
const atRoot = scriptPaths(command).find((path) => folderOf(path) === '.');
|
|
104
104
|
if (atRoot !== undefined)
|
|
105
|
-
throw new Error(`package.json "cmod.${key}" names ${atRoot}, a script at the plugin root. Move it into a folder, such as ./setup/${key}.sh:
|
|
105
|
+
throw new Error(`package.json "cmod.${key}" names ${atRoot}, a script at the plugin root. Move it into a folder, such as ./setup/${key}.sh: cmod asks consent for the whole folder of each script.`);
|
|
106
106
|
return { [key]: command };
|
|
107
107
|
}
|
|
108
108
|
export function scriptPaths(command) {
|
package/register.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["src/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoD,EAAE,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["src/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoD,EAAE,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AA+E7C,wBAAgB,WAAW,CAAC,KAAK,SAAS,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CA8BrG;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAIzD"}
|
package/register.js
CHANGED
|
@@ -14,6 +14,7 @@ async function startMod($, eventInput, passOn) {
|
|
|
14
14
|
open: (pane) => $.ui.open(pane),
|
|
15
15
|
close: (pane) => $.ui.close(pane),
|
|
16
16
|
panes: () => $.ui.panes(),
|
|
17
|
+
scroll: (args) => $.ui.scroll(args),
|
|
17
18
|
resolve: (render) => $.ui.resolve(render),
|
|
18
19
|
},
|
|
19
20
|
process: {
|
|
@@ -47,10 +48,14 @@ async function startMod($, eventInput, passOn) {
|
|
|
47
48
|
model: () => $.session.model(),
|
|
48
49
|
usage: () => $.session.usage(),
|
|
49
50
|
surfaces: () => $.session.surfaces(),
|
|
51
|
+
messages: ((args) => (args === undefined ? $.session.messages() : $.session.messages(args))),
|
|
50
52
|
},
|
|
51
53
|
command: { register: (command) => $.command.register(command) },
|
|
52
54
|
tool: { register: (tool) => $.tool.register(tool) },
|
|
53
|
-
agent: {
|
|
55
|
+
agent: {
|
|
56
|
+
list: () => $.agent.list(),
|
|
57
|
+
spawn: (args) => $.agent.spawn(args),
|
|
58
|
+
},
|
|
54
59
|
env: {
|
|
55
60
|
home: () => $.env.get('HOME'),
|
|
56
61
|
dataHome: () => $.env.get('XDG_DATA_HOME'),
|
|
@@ -82,6 +87,7 @@ export function registerMod(addHook, definition) {
|
|
|
82
87
|
addHook('classic.PreCompact', routeToMod);
|
|
83
88
|
addHook('classic.Stop', routeToMod);
|
|
84
89
|
addHook('classic.StopFailure', routeToMod);
|
|
90
|
+
addHook('classic.FileChanged', routeToMod);
|
|
85
91
|
addHook('tool.call', routeToMod);
|
|
86
92
|
addHook('prompt.submit', routeToMod);
|
|
87
93
|
addHook('prompt.context', routeToMod);
|
|
@@ -90,12 +96,12 @@ export function registerMod(addHook, definition) {
|
|
|
90
96
|
addHook('skill.prompt', routeToMod);
|
|
91
97
|
addHook('ui.render', routeToMod);
|
|
92
98
|
addHook('ui.press', routeToMod);
|
|
99
|
+
addHook('ui.scroll', routeToMod);
|
|
93
100
|
addHook('ui.close', routeToMod);
|
|
94
101
|
addHook('cmod.call', routeToMod);
|
|
95
102
|
}
|
|
96
103
|
export function registerPermissionCheck(addHook) {
|
|
97
104
|
checksPermissions = true;
|
|
98
105
|
addHook('tool.check', routeToMod);
|
|
99
|
-
addHook('classic.PreToolUse', routeToMod);
|
|
100
106
|
addHook('classic.PermissionRequest', routeToMod);
|
|
101
107
|
}
|
package/runtime/claude.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentInfo, Args, AskOptions, CommandSpec, ElementTable, FsEntry, FsStat, FsStatOptions, HookStream, HttpInit, HttpResponse, InvalidatableEventName, PaneCloseArgs, PaneOpenArgs, ProcessRunInit, ProcessRunResult, ProcessSpawnChunk, ProcessSpawnRequest, ProcessSpawnResult, RenderSurface, ResolveInput, SessionUsage, Settings, SettingsReadArgs, Timer, ToastOptions, ToolSpec, UiLogOptions, UiOpenResult, UiPane } from 'claude-code';
|
|
1
|
+
import type { AgentInfo, AgentSpawnArgs, AgentSpawnResult, Args, EngineInterface, AskOptions, CommandSpec, ElementTable, FsEntry, FsStat, FsStatOptions, HookStream, HttpInit, HttpResponse, InvalidatableEventName, PaneCloseArgs, PaneOpenArgs, ProcessRunInit, ProcessRunResult, ProcessSpawnChunk, ProcessSpawnRequest, ProcessSpawnResult, RenderSurface, ResolveInput, SessionUsage, Settings, SettingsReadArgs, Timer, ToastOptions, ToolSpec, UiLogOptions, UiOpenResult, UiPane, UiScrollArgs, UiScrollResult } from 'claude-code';
|
|
2
2
|
export type Claude = {
|
|
3
3
|
readonly plugin: {
|
|
4
4
|
readonly name: string;
|
|
@@ -14,6 +14,7 @@ export type Claude = {
|
|
|
14
14
|
open(pane: PaneOpenArgs): Promise<UiOpenResult>;
|
|
15
15
|
close(pane: PaneCloseArgs): Promise<void>;
|
|
16
16
|
panes(): Promise<readonly UiPane[]>;
|
|
17
|
+
scroll(args: UiScrollArgs): Promise<UiScrollResult>;
|
|
17
18
|
resolve(e: ResolveInput): ElementTable<RenderSurface>;
|
|
18
19
|
};
|
|
19
20
|
readonly process: {
|
|
@@ -51,6 +52,7 @@ export type Claude = {
|
|
|
51
52
|
model(): Promise<string>;
|
|
52
53
|
usage(): Promise<SessionUsage>;
|
|
53
54
|
surfaces(): Promise<readonly RenderSurface[]>;
|
|
55
|
+
messages: EngineInterface['session']['messages'];
|
|
54
56
|
};
|
|
55
57
|
readonly command: {
|
|
56
58
|
register(command: CommandSpec): Promise<{
|
|
@@ -64,6 +66,7 @@ export type Claude = {
|
|
|
64
66
|
};
|
|
65
67
|
readonly agent: {
|
|
66
68
|
list(): Promise<AgentInfo[]>;
|
|
69
|
+
spawn(args: AgentSpawnArgs): Promise<AgentSpawnResult>;
|
|
67
70
|
};
|
|
68
71
|
readonly env: {
|
|
69
72
|
home(): Promise<string | undefined>;
|
package/runtime/claude.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,IAAI,EACJ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,OAAO,EACP,MAAM,EACN,aAAa,EACb,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,MAAM,
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"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"}
|
package/runtime/hooks.d.ts
CHANGED
|
@@ -2,9 +2,17 @@ import type { ModEvent, ModHook } from '../mod.js';
|
|
|
2
2
|
import type { Claude } from './claude.js';
|
|
3
3
|
import type { RoutedHook } from './router.js';
|
|
4
4
|
import { type ToolCalls } from './tool-calls.js';
|
|
5
|
-
export type RoutedEvent = `classic.${ModEvent}` | 'tool.check' | 'tool.call' | 'prompt.submit' | 'prompt.context' | 'command.run' | 'session.measure' | 'skill.prompt' | 'ui.render' | 'ui.press' | 'ui.close' | 'cmod.call';
|
|
5
|
+
export type RoutedEvent = `classic.${Exclude<ModEvent, 'PreToolUse'>}` | 'tool.check' | 'tool.call' | 'prompt.submit' | 'prompt.context' | 'command.run' | 'session.measure' | 'skill.prompt' | 'ui.render' | 'ui.press' | 'ui.scroll' | 'ui.close' | 'cmod.call';
|
|
6
6
|
export declare const permissionEvents: readonly RoutedEvent[];
|
|
7
|
-
export declare function classicHook<E extends ModEvent
|
|
7
|
+
export declare function classicHook<E extends Exclude<ModEvent, 'PreToolUse'>>(name: string, event: E, hook: ModHook<E>, claude: Claude, calls: ToolCalls): RoutedHook<RoutedEvent>;
|
|
8
|
+
type HeldDecision = {
|
|
9
|
+
readonly decision: 'allow' | 'ask';
|
|
10
|
+
readonly reason?: string;
|
|
11
|
+
};
|
|
12
|
+
export type HeldDecisions = Map<string, HeldDecision>;
|
|
13
|
+
export declare function preToolUseHook(name: string, hook: ModHook<'PreToolUse'>, claude: Claude, calls: ToolCalls, held: HeldDecisions | undefined): RoutedHook<'tool.call'>;
|
|
14
|
+
export declare function heldDecisionHook(held: HeldDecisions): RoutedHook<'tool.check'>;
|
|
8
15
|
export declare function userSkillHook(claude: Claude): RoutedHook<'skill.prompt'>;
|
|
9
16
|
export declare const strictness: readonly ['allow', 'ask', 'deny'];
|
|
17
|
+
export {};
|
|
10
18
|
//# sourceMappingURL=hooks.d.ts.map
|
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,EAAyB,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAK3E,MAAM,MAAM,WAAW,GACnB,WAAW,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,GAC5C,YAAY,GACZ,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,aAAa,GACb,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,CAAA;AAEf,eAAO,MAAM,gBAAgB,EAAE,SAAS,WAAW,EAAgD,CAAA;AA6BnG,wBAAgB,WAAW,CAAC,CAAC,SAAS,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CAwB1K;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,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CA6BpK;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;AA4DD,eAAO,MAAM,UAAU,YAAI,OAAO,EAAE,KAAK,EAAE,MAAM,CAAU,CAAA"}
|
package/runtime/hooks.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { configFolders } from '../records.js';
|
|
2
|
-
import { toolInputOf } from './tool-calls.js';
|
|
2
|
+
import { reservedKeys, toolInputOf } from './tool-calls.js';
|
|
3
3
|
import { callEffects } from '../utils/call-effects.js';
|
|
4
4
|
import { dynamicPattern } from '../utils/parse-shell.js';
|
|
5
5
|
import { messageOf } from '../utils/text.js';
|
|
6
|
-
export const permissionEvents = ['tool.check', 'classic.
|
|
6
|
+
export const permissionEvents = ['tool.check', 'classic.PermissionRequest'];
|
|
7
7
|
const flags = ['suppressOriginalPrompt', 'reloadSkills', 'retry'];
|
|
8
8
|
const readFields = {
|
|
9
9
|
SessionStart: ['additionalContext', 'initialUserMessage', 'sessionTitle', 'watchPaths', 'reloadSkills'],
|
|
@@ -23,11 +23,10 @@ const readFields = {
|
|
|
23
23
|
Stop: ['additionalContext'],
|
|
24
24
|
StopFailure: [],
|
|
25
25
|
CwdChanged: [],
|
|
26
|
+
FileChanged: [],
|
|
26
27
|
};
|
|
27
28
|
export function classicHook(name, event, hook, claude, calls) {
|
|
28
29
|
const inputOf = async (e) => {
|
|
29
|
-
if (event === 'PreToolUse')
|
|
30
|
-
return preToolUseInput(name, e, claude, calls.agentOf);
|
|
31
30
|
if (event !== 'PostToolUse' && event !== 'PostToolUseFailure')
|
|
32
31
|
return e;
|
|
33
32
|
const input = e;
|
|
@@ -45,8 +44,6 @@ export function classicHook(name, event, hook, claude, calls) {
|
|
|
45
44
|
const routed = async (e, next) => {
|
|
46
45
|
const ours = await resultOf(e).catch((error) => {
|
|
47
46
|
const reason = `${name}: the ${event} hook failed: ${messageOf(error)}`;
|
|
48
|
-
if (event === 'PreToolUse')
|
|
49
|
-
return { deny: reason };
|
|
50
47
|
if (event === 'PermissionRequest')
|
|
51
48
|
return { decision: { behavior: 'deny', message: reason } };
|
|
52
49
|
claude.ui.log(reason);
|
|
@@ -54,10 +51,61 @@ export function classicHook(name, event, hook, claude, calls) {
|
|
|
54
51
|
});
|
|
55
52
|
if (ours === undefined)
|
|
56
53
|
return next(e);
|
|
57
|
-
return mergeClassic(
|
|
54
|
+
return mergeClassic((await next(e)), ours);
|
|
58
55
|
};
|
|
59
56
|
return routed;
|
|
60
57
|
}
|
|
58
|
+
export function preToolUseHook(name, hook, claude, calls, held) {
|
|
59
|
+
return async (e, next) => {
|
|
60
|
+
let ours;
|
|
61
|
+
try {
|
|
62
|
+
const answer = await hook(await preToolUseInput(name, e, claude, calls.agentOf));
|
|
63
|
+
if (answer?.systemMessage !== undefined)
|
|
64
|
+
claude.ui.log(answer.systemMessage);
|
|
65
|
+
ours = answer === undefined ? {} : classicResult('PreToolUse', answer);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return { deny: `${name}: the PreToolUse hook failed: ${messageOf(error)}` };
|
|
69
|
+
}
|
|
70
|
+
if (typeof ours['deny'] === 'string')
|
|
71
|
+
return { deny: ours['deny'] };
|
|
72
|
+
const decided = heldDecisionOf(ours);
|
|
73
|
+
if (decided !== undefined && held === undefined) {
|
|
74
|
+
return { deny: `${name}: the PreToolUse hook answered permissionDecision "${decided.decision}", so hooks/register.ts must call registerPermissionCheck(addHook) after registerMod.` };
|
|
75
|
+
}
|
|
76
|
+
const updated = ours['updatedInput'];
|
|
77
|
+
const reserved = Object.fromEntries(Object.entries(e).filter(([key]) => reservedKeys.includes(key)));
|
|
78
|
+
const earlier = held?.get(e.tool_use_id);
|
|
79
|
+
if (decided !== undefined)
|
|
80
|
+
held?.set(e.tool_use_id, earlier !== undefined && strictness.indexOf(earlier.decision) >= strictness.indexOf(decided.decision) ? earlier : decided);
|
|
81
|
+
let result;
|
|
82
|
+
try {
|
|
83
|
+
result = await next(updated === undefined ? e : { ...reserved, ...updated });
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
if (decided !== undefined)
|
|
87
|
+
held?.delete(e.tool_use_id);
|
|
88
|
+
}
|
|
89
|
+
const context = ours['additionalContext'];
|
|
90
|
+
if (context === undefined || result.deny !== undefined)
|
|
91
|
+
return result;
|
|
92
|
+
return { ...result, context: [...(result.context ?? []), ...context] };
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function heldDecisionHook(held) {
|
|
96
|
+
return async (e, next) => {
|
|
97
|
+
const below = await next(e);
|
|
98
|
+
const ours = e.tool_use_id === undefined ? undefined : held.get(e.tool_use_id);
|
|
99
|
+
return ours === undefined || below.decision === 'deny' ? below : ours;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function heldDecisionOf(ours) {
|
|
103
|
+
if (ours['allow'] !== undefined)
|
|
104
|
+
return { decision: 'allow' };
|
|
105
|
+
if (typeof ours['ask'] !== 'string')
|
|
106
|
+
return undefined;
|
|
107
|
+
return ours['ask'] === '' ? { decision: 'ask' } : { decision: 'ask', reason: ours['ask'] };
|
|
108
|
+
}
|
|
61
109
|
const frontmatter = /^---\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/;
|
|
62
110
|
const baseDirectoryLine = /^Base directory for this skill: [^\n]*\n\n/;
|
|
63
111
|
export function userSkillHook(claude) {
|
|
@@ -149,20 +197,10 @@ function classicResult(event, answer) {
|
|
|
149
197
|
return result;
|
|
150
198
|
}
|
|
151
199
|
export const strictness = ['allow', 'ask', 'deny'];
|
|
152
|
-
function
|
|
153
|
-
return strictness.findLastIndex((decision) => result[decision] !== undefined);
|
|
154
|
-
}
|
|
155
|
-
function mergeClassic(event, below, ours) {
|
|
200
|
+
function mergeClassic(below, ours) {
|
|
156
201
|
const merged = { ...below, ...ours };
|
|
157
202
|
const context = [...(below['additionalContext'] ?? []), ...(ours['additionalContext'] ?? [])];
|
|
158
203
|
if (context.length > 0)
|
|
159
204
|
merged['additionalContext'] = context;
|
|
160
|
-
if (event !== 'PreToolUse')
|
|
161
|
-
return merged;
|
|
162
|
-
const strictest = strictness[Math.max(strictnessOf(below), strictnessOf(ours))];
|
|
163
|
-
for (const decision of strictness)
|
|
164
|
-
delete merged[decision];
|
|
165
|
-
if (strictest !== undefined)
|
|
166
|
-
merged[strictest] = ours[strictest] ?? below[strictest];
|
|
167
205
|
return merged;
|
|
168
206
|
}
|
|
@@ -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,EAAiE,MAAM,aAAa,CAAA;AAC3H,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAiE,MAAM,aAAa,CAAA;AAC3H,OAAO,KAAK,EAAa,GAAG,EAAE,aAAa,EAAqB,MAAM,WAAW,CAAA;AAIjF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,EAAsG,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AACjJ,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAKxE,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;CAC/B,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,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;AAiCD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBhE;AAkCD,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,EAAE,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,iBAAiB,GAAE,MAAM,OAAoB,GAAG,SAAS,CAAC,KAAK,CAAC,CAkOvJ"}
|
package/runtime/lifecycle.js
CHANGED
|
@@ -3,7 +3,7 @@ import { relativePath } from '../utils/paths.js';
|
|
|
3
3
|
import { formatExit, listed, messageOf } from '../utils/text.js';
|
|
4
4
|
import { beforeDeadline } from './deadline.js';
|
|
5
5
|
import { answerCall, dependencyCalls, notInstalled } from './dependencies.js';
|
|
6
|
-
import { classicHook, permissionEvents, userSkillHook } from './hooks.js';
|
|
6
|
+
import { classicHook, heldDecisionHook, permissionEvents, preToolUseHook, userSkillHook } from './hooks.js';
|
|
7
7
|
import { createRouter } from './router.js';
|
|
8
8
|
import { createState } from './state.js';
|
|
9
9
|
import { toolCalls } from './tool-calls.js';
|
|
@@ -127,7 +127,7 @@ export function createLifecycle(definition, checksPermissions = () => true) {
|
|
|
127
127
|
};
|
|
128
128
|
const record = () => {
|
|
129
129
|
recording ??= recordThroughCmod()
|
|
130
|
-
.catch((error) => claude().ui.log(`${definition.name} has no
|
|
130
|
+
.catch((error) => claude().ui.log(`${definition.name} has no cmod record yet: ${messageOf(error)}`, { to: 'debug' }))
|
|
131
131
|
.finally(() => {
|
|
132
132
|
recording = undefined;
|
|
133
133
|
});
|
|
@@ -186,7 +186,7 @@ export function createLifecycle(definition, checksPermissions = () => true) {
|
|
|
186
186
|
return bootstrap(plugin.root);
|
|
187
187
|
phase = 'installing';
|
|
188
188
|
if ((await cmodVersion(claude())) === undefined)
|
|
189
|
-
return
|
|
189
|
+
return waitForcmod();
|
|
190
190
|
endLine();
|
|
191
191
|
const progress = showLine();
|
|
192
192
|
let outcome;
|
|
@@ -205,9 +205,9 @@ export function createLifecycle(definition, checksPermissions = () => true) {
|
|
|
205
205
|
const reason = outcome?.kind === 'failed' ? outcome.message : `cmod setup ${formatExit(code, lastError)}`;
|
|
206
206
|
fail(reason, `Fix the cause, then run: cmod install ${definition.name}`);
|
|
207
207
|
};
|
|
208
|
-
const
|
|
208
|
+
const waitForcmod = () => {
|
|
209
209
|
phase = 'waiting';
|
|
210
|
-
showLine().wait('Waiting for
|
|
210
|
+
showLine().wait('Waiting for cmod');
|
|
211
211
|
let check;
|
|
212
212
|
const stop = () => {
|
|
213
213
|
timer.cancel();
|
|
@@ -227,7 +227,7 @@ export function createLifecycle(definition, checksPermissions = () => true) {
|
|
|
227
227
|
report(error);
|
|
228
228
|
});
|
|
229
229
|
});
|
|
230
|
-
const longWait = claude().clock.after(cmodWaitMs, () => showLine().wait("Still waiting for
|
|
230
|
+
const longWait = claude().clock.after(cmodWaitMs, () => showLine().wait("Still waiting for cmod to download cmod. See cmod's own line."));
|
|
231
231
|
};
|
|
232
232
|
const bootstrap = async (root) => {
|
|
233
233
|
const progress = showLine();
|
|
@@ -332,6 +332,7 @@ async function createMod(definition, runtime) {
|
|
|
332
332
|
let staleCwd;
|
|
333
333
|
const area = createUi({ name: definition.name, claude, router, progress, announce, mod: () => mod });
|
|
334
334
|
const modState = createState({ name: definition.name, initial: definition.state ?? {}, session, root, claude, changed: area.changed });
|
|
335
|
+
const held = runtime.checksPermissions() ? new Map() : undefined;
|
|
335
336
|
const mod = {
|
|
336
337
|
name: definition.name,
|
|
337
338
|
state: modState.state,
|
|
@@ -339,7 +340,10 @@ async function createMod(definition, runtime) {
|
|
|
339
340
|
on(event, hook) {
|
|
340
341
|
if (!hookEvents.includes(event))
|
|
341
342
|
hookEvents.push(event);
|
|
342
|
-
|
|
343
|
+
if (event === 'PreToolUse')
|
|
344
|
+
router.add('tool.call', preToolUseHook(definition.name, hook, claude, agents, held));
|
|
345
|
+
else
|
|
346
|
+
router.add(`classic.${event}`, classicHook(definition.name, event, hook, claude, agents));
|
|
343
347
|
},
|
|
344
348
|
use: (job) => job({ mod, claude, on: (event, hook) => router.add(event, hook), announce, reserveName, toolCalls: agents }),
|
|
345
349
|
ui: area.ui,
|
|
@@ -351,9 +355,13 @@ async function createMod(definition, runtime) {
|
|
|
351
355
|
read: (path) => claude.fs.read(path),
|
|
352
356
|
write: (path, text) => claude.fs.write(path, text),
|
|
353
357
|
list: (path) => claude.fs.list(path),
|
|
358
|
+
exists: (path) => claude.fs.exists(path),
|
|
359
|
+
stat: (path, options) => claude.fs.stat(path, options),
|
|
354
360
|
},
|
|
355
361
|
http: { fetch: (url, init) => claude.http.fetch(url, init) },
|
|
356
362
|
settings: { read: (args) => claude.settings.read(args) },
|
|
363
|
+
session: { messages: claude.session.messages },
|
|
364
|
+
agent: { spawn: (args) => claude.agent.spawn(args) },
|
|
357
365
|
get projectRoot() {
|
|
358
366
|
return modState.root;
|
|
359
367
|
},
|
|
@@ -433,6 +441,8 @@ async function createMod(definition, runtime) {
|
|
|
433
441
|
if (permissionHooks.length > 0 && !runtime.checksPermissions()) {
|
|
434
442
|
throw new Error(`it decides permissions on ${listed(permissionHooks)}, so hooks/register.ts must call registerPermissionCheck(addHook) after registerMod`);
|
|
435
443
|
}
|
|
444
|
+
if (held !== undefined && hookEvents.includes('PreToolUse'))
|
|
445
|
+
router.add('tool.check', heldDecisionHook(held));
|
|
436
446
|
await failsAs('its open panes did not load', () => area.restorePanes());
|
|
437
447
|
if (hookEvents.length > 0)
|
|
438
448
|
added.push(`${hookEvents.length === 1 ? 'a hook' : 'hooks'} on ${listed(hookEvents)}`);
|
package/runtime/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/runtime/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA+B,aAAa,EAAS,MAAM,aAAa,CAAA;AAClG,OAAO,KAAK,EAAE,GAAG,EAAc,YAAY,EAAE,MAAM,WAAW,CAAA;AAM9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAA;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,GAAG,IAAI,IAAI,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAAA;IAClC,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAA;CAC5F,CAAA;AAkBD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAqDvD;AAqHD,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,CAAC,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,MAAM,CAAC,KAAK,SAAS,MAAM,IAAI;IACzC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAA;IAC7B,OAAO,IAAI,IAAI,CAAA;IACf,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9B,CAAA;AAED,wBAAgB,QAAQ,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/runtime/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA+B,aAAa,EAAS,MAAM,aAAa,CAAA;AAClG,OAAO,KAAK,EAAE,GAAG,EAAc,YAAY,EAAE,MAAM,WAAW,CAAA;AAM9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAA;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,GAAG,IAAI,IAAI,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAAA;IAClC,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAA;CAC5F,CAAA;AAkBD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAqDvD;AAqHD,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,CAAC,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,MAAM,CAAC,KAAK,SAAS,MAAM,IAAI;IACzC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAA;IAC7B,OAAO,IAAI,IAAI,CAAA;IACf,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9B,CAAA;AAED,wBAAgB,QAAQ,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAmNjI"}
|
package/runtime/ui.js
CHANGED
|
@@ -165,6 +165,7 @@ function drawPieces(pieces, place) {
|
|
|
165
165
|
}
|
|
166
166
|
export function createUi({ name, claude, router, progress, announce, mod }) {
|
|
167
167
|
const panes = new Map();
|
|
168
|
+
const paneLogs = new Map();
|
|
168
169
|
const openPanes = new Set();
|
|
169
170
|
const requestedSizes = new Map();
|
|
170
171
|
const renders = new Set();
|
|
@@ -231,9 +232,10 @@ export function createUi({ name, claude, router, progress, announce, mod }) {
|
|
|
231
232
|
return drawWith(table, () => drawPieces(drawn, e.props.isFirstOfReply ? 'opensReply' : 'inReply'));
|
|
232
233
|
});
|
|
233
234
|
};
|
|
234
|
-
const openAt = (pane, size) => {
|
|
235
|
+
const openAt = (pane, size, focus) => {
|
|
235
236
|
requestedSizes.set(pane.id, size);
|
|
236
|
-
|
|
237
|
+
const { id, title, closeOnEscape, holdToasts } = pane;
|
|
238
|
+
return claude.ui.open({ id, title, ...size, ...(closeOnEscape === true ? { closeOnEscape } : {}), ...(holdToasts === true ? { holdToasts } : {}), ...(focus === true ? { focus } : {}) });
|
|
237
239
|
};
|
|
238
240
|
const resize = async (pane) => {
|
|
239
241
|
try {
|
|
@@ -257,27 +259,54 @@ export function createUi({ name, claude, router, progress, announce, mod }) {
|
|
|
257
259
|
return next(e);
|
|
258
260
|
openPanes.add(pane.id);
|
|
259
261
|
const table = claude.ui.resolve(e);
|
|
260
|
-
|
|
262
|
+
try {
|
|
263
|
+
return drawWith(table, () => pane.render(mod(), e.props), markdownIn(table));
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
paneLogs.get(pane.id)?.(`threw: ${messageOf(error)}`);
|
|
267
|
+
return drawWith(table, () => Text({ color: 'error', children: `The ${pane.title} pane could not draw: ${messageOf(error)}` }));
|
|
268
|
+
}
|
|
261
269
|
});
|
|
262
|
-
router.add('ui.
|
|
270
|
+
router.add('ui.scroll', async (e, next) => {
|
|
271
|
+
const pane = panes.get(e.requestId);
|
|
272
|
+
const moved = await next(e);
|
|
273
|
+
if (pane?.onScroll === undefined || e.component !== 'Pane' || moved.deny !== undefined)
|
|
274
|
+
return moved;
|
|
275
|
+
await handle(pane, 'onScroll', () => pane.onScroll?.(mod(), e));
|
|
276
|
+
return moved;
|
|
277
|
+
});
|
|
278
|
+
router.add('ui.close', async (e, next) => {
|
|
263
279
|
openPanes.delete(e.id);
|
|
264
|
-
|
|
280
|
+
const closed = await next(e);
|
|
281
|
+
const pane = panes.get(e.id);
|
|
282
|
+
if (pane?.onClose !== undefined)
|
|
283
|
+
await handle(pane, 'onClose', () => pane.onClose?.(mod(), e));
|
|
284
|
+
return closed;
|
|
265
285
|
});
|
|
266
286
|
};
|
|
287
|
+
const handle = async (pane, handler, run) => {
|
|
288
|
+
try {
|
|
289
|
+
await run();
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
claude.ui.log(`${name}: the ${pane.title} pane's ${handler} threw: ${messageOf(error)}`);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
267
295
|
return {
|
|
268
296
|
ui: {
|
|
269
297
|
pane(pane) {
|
|
270
298
|
if (panes.has(pane.id))
|
|
271
299
|
throw new Error(`${name}: the pane "${pane.id}" is already added. Give each pane its own id.`);
|
|
272
300
|
panes.set(pane.id, pane);
|
|
301
|
+
paneLogs.set(pane.id, logOnce(`${pane.title} pane`));
|
|
273
302
|
announce(`the ${pane.title} pane`);
|
|
274
303
|
route();
|
|
275
304
|
const handle = {
|
|
276
305
|
get isOpen() {
|
|
277
306
|
return openPanes.has(pane.id);
|
|
278
307
|
},
|
|
279
|
-
async open() {
|
|
280
|
-
const { isPlaced } = await openAt(pane, paneSize(pane, mod().state));
|
|
308
|
+
async open(options) {
|
|
309
|
+
const { isPlaced } = await openAt(pane, paneSize(pane, mod().state), options?.focus);
|
|
281
310
|
if (isPlaced)
|
|
282
311
|
openPanes.add(pane.id);
|
|
283
312
|
},
|
|
@@ -285,7 +314,7 @@ export function createUi({ name, claude, router, progress, announce, mod }) {
|
|
|
285
314
|
await claude.ui.close({ id: pane.id });
|
|
286
315
|
openPanes.delete(pane.id);
|
|
287
316
|
},
|
|
288
|
-
toggle: () => (openPanes.has(pane.id) ? handle.close() : handle.open()),
|
|
317
|
+
toggle: (options) => (openPanes.has(pane.id) ? handle.close() : handle.open(options)),
|
|
289
318
|
};
|
|
290
319
|
return handle;
|
|
291
320
|
},
|
|
@@ -329,6 +358,7 @@ export function createUi({ name, claude, router, progress, announce, mod }) {
|
|
|
329
358
|
}
|
|
330
359
|
},
|
|
331
360
|
ask: (question, options) => claude.ui.ask(question, options),
|
|
361
|
+
scroll: (args) => claude.ui.scroll(args),
|
|
332
362
|
},
|
|
333
363
|
changed() {
|
|
334
364
|
if (panes.size === 0 && renders.size === 0)
|
package/shell.d.ts
ADDED
package/shell.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["src/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAA"}
|
package/shell.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseShell } from './utils/parse-shell.js';
|
package/src/jobs/check.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Job } from '../mod.js'
|
|
2
2
|
import { longestMs, type Deadline } from '../runtime/deadline.js'
|
|
3
3
|
import { callEffects, type ToolUse } from '../utils/call-effects.js'
|
|
4
|
-
import {
|
|
4
|
+
import { dirname } from '../vendor.js'
|
|
5
5
|
import { listed, messageOf } from '../utils/text.js'
|
|
6
6
|
import { afterCall, modOf, targetWords } from './context.js'
|
|
7
7
|
import type { Workspace } from './permissions/find-project-scope.js'
|
|
@@ -52,6 +52,6 @@ async function triggeredRun(after: readonly Target[], run: readonly string[], us
|
|
|
52
52
|
const existing: string[] = []
|
|
53
53
|
for (const path of paths) if (await workspace.fs.exists(path)) existing.push(path)
|
|
54
54
|
const last = existing.at(-1)
|
|
55
|
-
if (last !== undefined) return { command: [...run, ...existing], folder:
|
|
55
|
+
if (last !== undefined) return { command: [...run, ...existing], folder: dirname(last) }
|
|
56
56
|
return commandFolder === undefined ? undefined : { command: [...run], folder: commandFolder }
|
|
57
57
|
}
|
package/src/jobs/context.ts
CHANGED
|
@@ -77,6 +77,8 @@ export function modWithin<State extends object>({ mod, claude }: JobContext<Stat
|
|
|
77
77
|
read: (path) => within('mod.fs.read', mod.fs.read(path)),
|
|
78
78
|
write: (path, text) => within('mod.fs.write', mod.fs.write(path, text)),
|
|
79
79
|
list: (path) => within('mod.fs.list', mod.fs.list(path)),
|
|
80
|
+
exists: (path) => within('mod.fs.exists', mod.fs.exists(path)),
|
|
81
|
+
stat: (path, options) => within('mod.fs.stat', mod.fs.stat(path, options)),
|
|
80
82
|
},
|
|
81
83
|
http: { fetch: (url, init) => within('mod.http.fetch', mod.http.fetch(url, init)) },
|
|
82
84
|
dependencies: dependencyCalls(claude, within),
|
|
@@ -3,7 +3,7 @@ import { messageOf } from '../../utils/text.js'
|
|
|
3
3
|
import { callBaseOf, callEffects, type CallEffects, type ToolCall, type ToolUse } from '../../utils/call-effects.js'
|
|
4
4
|
import type { Workspace } from './find-project-scope.js'
|
|
5
5
|
import { folderInScope, matchTarget, targetOf, type MatchedCall, type Target, type TargetCalls, type TargetKey, type TargetOf } from './match-target.js'
|
|
6
|
-
import {
|
|
6
|
+
import { resolve } from '../../vendor.js'
|
|
7
7
|
|
|
8
8
|
export type Rule<Mod> = {
|
|
9
9
|
[Key in TargetKey]: TargetOf<Key> & {
|
|
@@ -71,7 +71,7 @@ async function unparsedMatches(target: Target, use: ToolUse, effects: CallEffect
|
|
|
71
71
|
const named = patterns.map((pattern) => pattern.slice(pattern.lastIndexOf('/') + 1)).filter((segment) => segment !== '' && !/[*?[\]{}]/.test(segment) && line.includes(segment.toLowerCase()))
|
|
72
72
|
const folder = named.length === 0 ? undefined : await folderInScope(shell, workspace)
|
|
73
73
|
if (folder === undefined) return []
|
|
74
|
-
return named.map((segment) => ({ call: { ...base, path:
|
|
74
|
+
return named.map((segment) => ({ call: { ...base, path: resolve(folder, segment) }, access: undefined, folder }))
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function containsWord(line: string, word: string): boolean {
|