@cmodjs/core 0.1.5 → 0.1.6
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/connect.d.ts.map +1 -1
- package/connect.js +7 -9
- package/docs/commands.md +3 -2
- package/docs/index.md +2 -2
- package/docs/jobs.md +20 -20
- package/docs/mod.md +1 -1
- package/docs/testing.md +1 -1
- package/jobs/check.d.ts +2 -2
- package/jobs/check.d.ts.map +1 -1
- package/jobs/check.js +5 -5
- package/jobs/context.d.ts +14 -0
- package/jobs/context.d.ts.map +1 -0
- package/jobs/{part-context.js → context.js} +6 -6
- package/jobs/permissions.d.ts +2 -2
- package/jobs/permissions.d.ts.map +1 -1
- package/jobs/permissions.js +7 -7
- package/jobs/program.d.ts +2 -2
- package/jobs/program.d.ts.map +1 -1
- package/jobs/prompt.d.ts +2 -2
- package/jobs/prompt.d.ts.map +1 -1
- package/jobs/prompt.js +17 -17
- package/jobs/slash-command.d.ts +2 -2
- package/jobs/slash-command.d.ts.map +1 -1
- package/jobs/slash-command.js +5 -5
- package/jobs/status-line.d.ts +2 -2
- package/jobs/status-line.d.ts.map +1 -1
- package/jobs/status-line.js +5 -5
- package/jobs/tool.d.ts +2 -2
- package/jobs/tool.d.ts.map +1 -1
- package/jobs/tool.js +5 -5
- package/mod.d.ts +3 -3
- package/mod.d.ts.map +1 -1
- package/package.json +1 -1
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +8 -9
- package/runtime/tool-calls.d.ts +3 -2
- package/runtime/tool-calls.d.ts.map +1 -1
- package/runtime/tool-calls.js +6 -6
- package/src/connect.ts +8 -11
- package/src/jobs/check.ts +7 -7
- package/src/jobs/{part-context.ts → context.ts} +10 -10
- package/src/jobs/permissions.ts +9 -9
- package/src/jobs/program.ts +2 -2
- package/src/jobs/prompt.ts +19 -19
- package/src/jobs/slash-command.ts +7 -7
- package/src/jobs/status-line.ts +7 -7
- package/src/jobs/tool.ts +7 -7
- package/src/mod.ts +3 -3
- package/src/runtime/lifecycle.ts +9 -10
- package/src/runtime/tool-calls.ts +8 -7
- package/jobs/part-context.d.ts +0 -14
- package/jobs/part-context.d.ts.map +0 -1
package/jobs/tool.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Job, Mod } from '../mod.js';
|
|
3
3
|
export declare function tool<const Schema extends object = {
|
|
4
4
|
type: 'object';
|
|
5
5
|
}, State extends object = Record<never, never>>(options: {
|
|
@@ -7,7 +7,7 @@ export declare function tool<const Schema extends object = {
|
|
|
7
7
|
readonly description: string;
|
|
8
8
|
readonly inputSchema?: Schema;
|
|
9
9
|
readonly execute: (input: Schema extends JSONSchema ? FromSchema<Schema> : never, mod: Mod<State>) => unknown;
|
|
10
|
-
}):
|
|
10
|
+
}): Job<{
|
|
11
11
|
readonly name: string;
|
|
12
12
|
}, State>;
|
|
13
13
|
//# sourceMappingURL=tool.d.ts.map
|
package/jobs/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/jobs/tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC/D,OAAO,KAAK,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/jobs/tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC/D,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AASzC,wBAAgB,IAAI,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,EAAE,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IAC3H,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,SAAS,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,OAAO,CAAA;CAC9G,GAAG,GAAG,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,CAAC,CAoCxC"}
|
package/jobs/tool.js
CHANGED
|
@@ -2,12 +2,12 @@ import { Validator } from '../vendor.js';
|
|
|
2
2
|
import { toolDeadline } from '../runtime/deadline.js';
|
|
3
3
|
import { reservedKeys, toolInputOf } from '../runtime/tool-calls.js';
|
|
4
4
|
import { messageOf } from '../utils/text.js';
|
|
5
|
-
import { modWithin } from './
|
|
5
|
+
import { modWithin } from './context.js';
|
|
6
6
|
const toolName = /^[A-Za-z0-9_-]{1,64}$/;
|
|
7
7
|
export function tool(options) {
|
|
8
8
|
const { name, description, inputSchema, execute } = options;
|
|
9
|
-
return (
|
|
10
|
-
const { mod, claude,
|
|
9
|
+
return (job) => {
|
|
10
|
+
const { mod, claude, announce, reserveName } = job;
|
|
11
11
|
if (!toolName.test(name))
|
|
12
12
|
throw new Error(`${mod.name}: "${name}" is not a tool name. Use 1 to 64 letters, digits, "_", or "-".`);
|
|
13
13
|
const properties = inputSchema?.properties ?? {};
|
|
@@ -23,8 +23,8 @@ export function tool(options) {
|
|
|
23
23
|
claude.ui.log(`${mod.name}: the ${name} tool is not added: ${messageOf(error)}`);
|
|
24
24
|
});
|
|
25
25
|
announce(`the ${name} tool`);
|
|
26
|
-
const executeMod = modWithin(
|
|
27
|
-
on('tool.call', async (e, next) => {
|
|
26
|
+
const executeMod = modWithin(job, toolDeadline);
|
|
27
|
+
job.on('tool.call', async (e, next) => {
|
|
28
28
|
if (e.tool !== registered)
|
|
29
29
|
return next(e);
|
|
30
30
|
const input = toolInputOf(e);
|
package/mod.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export type Mod<State extends object = Record<never, never>> = {
|
|
|
75
75
|
readonly state: Readonly<State>;
|
|
76
76
|
readonly dataFolder: string;
|
|
77
77
|
on<E extends ModEvent>(event: E, hook: ModHook<E>): void;
|
|
78
|
-
use<Handle>(
|
|
78
|
+
use<Handle>(job: Job<Handle, State>): Handle;
|
|
79
79
|
readonly ui: {
|
|
80
80
|
pane(pane: Pane<State>): PaneHandle;
|
|
81
81
|
render<S extends Slot>(slot: S, Component: (props: SlotProps<S>) => RenderElement): void;
|
|
@@ -119,7 +119,7 @@ export type ModDefinition<State extends StateGroups = Record<never, never>, Name
|
|
|
119
119
|
};
|
|
120
120
|
setup(mod: Mod<State>): void | Promise<void>;
|
|
121
121
|
};
|
|
122
|
-
export type
|
|
122
|
+
export type JobContext<State extends object = Record<never, never>> = {
|
|
123
123
|
readonly mod: Mod<State>;
|
|
124
124
|
readonly claude: Claude;
|
|
125
125
|
on<N extends RoutedEvent>(event: N, hook: RoutedHook<N>): void;
|
|
@@ -127,6 +127,6 @@ export type PartContext<State extends object = Record<never, never>> = {
|
|
|
127
127
|
reserveName(kind: string, name: string, taken: string): void;
|
|
128
128
|
readonly toolCalls: ToolCalls;
|
|
129
129
|
};
|
|
130
|
-
export type
|
|
130
|
+
export type Job<Handle, State extends object = Record<never, never>> = (context: JobContext<State>) => Handle;
|
|
131
131
|
export declare function defineMod<State extends StateGroups = Record<never, never>, Name extends string = string>(definition: ModDefinition<State, Name>): ModDefinition<State, Name>;
|
|
132
132
|
//# sourceMappingURL=mod.d.ts.map
|
package/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["src/mod.ts"],"names":[],"mappings":"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
|
|
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,EACjB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAEpD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,MAAM,MAAM,QAAQ,GAChB,cAAc,GACd,YAAY,GACZ,kBAAkB,GAClB,oBAAoB,GACpB,YAAY,GACZ,mBAAmB,GACnB,kBAAkB,GAClB,aAAa,GACb,oBAAoB,GACpB,eAAe,GACf,eAAe,GACf,cAAc,GACd,cAAc,GACd,YAAY,GACZ,MAAM,GACN,aAAa,GACb,YAAY,CAAA;AAEhB,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kBAAkB,CAAC,EAAE;QACnB,aAAa,CAAC,EAAE,QAAQ,CAAA;QACxB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;QAC7C,wBAAwB,CAAC,EAAE,MAAM,CAAA;QACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACtC,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,sBAAsB,CAAC,EAAE,OAAO,CAAA;QAChC,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;QACrB,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,QAAQ,CAAC,EAAE,yBAAyB,CAAA;QACpC,iBAAiB,CAAC,EAAE,OAAO,CAAA;QAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAA;QAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB,CAAA;CACF,CAAA;AAED,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAEtD,KAAK,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,YAAY,GAAG,aAAa,GAAG,oBAAoB,GAAG,YAAY,CAAC,GAAG;IAC9G,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,CAAA;QAClB,GAAG,EAAE,MAAM,CAAA;QACX,eAAe,EAAE,YAAY,CAAA;QAC7B,SAAS,EAAE,MAAM,CAAA;QACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,WAAW,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,KAAK,EAAE,SAAS,CAAA;KACjB,CAAA;IACD,WAAW,EAAE,iBAAiB,CAAC,aAAa,CAAC,GAAG;QAAE,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IACpE,kBAAkB,EAAE,iBAAiB,CAAC,oBAAoB,CAAC,GAAG;QAAE,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAClF,UAAU,EAAE,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,iBAAiB,CAAC,CAAA;CACrE,CAAA;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;AAElH,MAAM,MAAM,GAAG,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,EAAE,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IACxD,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,CAAA;IAC5C,QAAQ,CAAC,EAAE,EAAE;QACX,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,UAAU,CAAA;QACnC,MAAM,CAAC,CAAC,SAAS,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,aAAa,GAAG,IAAI,CAAA;QACxF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;QACzB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QAClG,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;KACjF,CAAA;IACD,QAAQ,CAAC,OAAO,EAAE;QAChB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAC9E,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GAAG,UAAU,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAA;KAC5H,CAAA;IACD,QAAQ,CAAC,EAAE,EAAE;QACX,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QACnC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAChD,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;KACxC,CAAA;IACD,QAAQ,CAAC,IAAI,EAAE;QACb,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;KAC3D,CAAA;IACD,QAAQ,CAAC,QAAQ,EAAE;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;KACjD,CAAA;IACD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAA;CACxC,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,KAAK,GAAG,CAAC,QAAQ,EAAE,KAAK,SAAS,MAAM,IAAI;IACzC,QAAQ,EAAE,MAAM,IAAI,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK;CACzK,CAAA;AAED,MAAM,MAAM,aAAa,CAAC,KAAK,SAAS,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI;IAC1G,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAA;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,SAAS,MAAM,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,GAAG;QAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,OAAO,CAAA;KAAE,CAAA;IACnK,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI;IACpE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,EAAE,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,MAAM,CAAA;AAE7G,wBAAgB,SAAS,CAAC,KAAK,SAAS,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAG5K"}
|
package/package.json
CHANGED
|
@@ -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,EAAE,GAAG,EAAE,aAAa,
|
|
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,EAAE,GAAG,EAAE,aAAa,EAAqB,MAAM,WAAW,CAAA;AAItE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AACzE,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;AAgCD,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,GAAG,SAAS,CAAC,KAAK,CAAC,CAkOxG"}
|
package/runtime/lifecycle.js
CHANGED
|
@@ -326,7 +326,6 @@ async function createMod(definition, runtime) {
|
|
|
326
326
|
const announce = (feature) => {
|
|
327
327
|
added.push(feature);
|
|
328
328
|
};
|
|
329
|
-
const on = (event, hook) => router.add(event, hook);
|
|
330
329
|
const [session, root, startCwd] = await Promise.all([claude.session.id(), claude.session.root(), claude.session.cwd()]);
|
|
331
330
|
let cwd = startCwd;
|
|
332
331
|
let loadedCwd = startCwd;
|
|
@@ -342,7 +341,7 @@ async function createMod(definition, runtime) {
|
|
|
342
341
|
hookEvents.push(event);
|
|
343
342
|
router.add(`classic.${event}`, classicHook(definition.name, event, hook, claude, agents));
|
|
344
343
|
},
|
|
345
|
-
use: (
|
|
344
|
+
use: (job) => job({ mod, claude, on: (event, hook) => router.add(event, hook), announce, reserveName, toolCalls: agents }),
|
|
346
345
|
ui: area.ui,
|
|
347
346
|
process: {
|
|
348
347
|
run: (argv, init) => claude.process.run(argv, init),
|
|
@@ -393,34 +392,34 @@ async function createMod(definition, runtime) {
|
|
|
393
392
|
claude.ui.log(`${definition.name} keeps the state of ${modState.root} until the next prompt or folder move: ${messageOf(error)}`);
|
|
394
393
|
}
|
|
395
394
|
};
|
|
396
|
-
|
|
395
|
+
router.add('classic.SessionStart', async (e, next) => {
|
|
397
396
|
await modState.switchSession(e.session_id, e.source).catch((error) => {
|
|
398
397
|
claude.ui.log(`${definition.name} kept its session values from before the ${e.source}: ${messageOf(error)}`);
|
|
399
398
|
});
|
|
400
399
|
return next(e);
|
|
401
400
|
});
|
|
402
|
-
|
|
401
|
+
router.add('classic.UserPromptSubmit', async (e, next) => {
|
|
403
402
|
staleCwd = undefined;
|
|
404
403
|
await followSession();
|
|
405
404
|
return next(e);
|
|
406
405
|
});
|
|
407
406
|
for (const event of ['classic.PostToolUse', 'classic.PostToolUseFailure']) {
|
|
408
|
-
|
|
407
|
+
router.add(event, async (e, next) => {
|
|
409
408
|
if (shellTools.includes(e.tool_name))
|
|
410
409
|
await followSession();
|
|
411
410
|
return next(e);
|
|
412
411
|
});
|
|
413
412
|
}
|
|
414
|
-
|
|
413
|
+
router.add('command.run', async (e, next) => {
|
|
415
414
|
const answer = await next(e);
|
|
416
415
|
if (e.command === 'cd')
|
|
417
416
|
await followSession(true);
|
|
418
417
|
return answer;
|
|
419
418
|
});
|
|
420
|
-
|
|
419
|
+
router.add('skill.prompt', userSkillHook(claude));
|
|
421
420
|
const api = Object.fromEntries(Object.entries(definition.api ?? {}).map(([method, run]) => [method, (input) => run(input, mod)]));
|
|
422
|
-
|
|
423
|
-
const agents = toolCalls(
|
|
421
|
+
router.add('cmod.call', (e, next) => (e.to === definition.name ? answerCall(definition.name, api, e) : next(e)));
|
|
422
|
+
const agents = toolCalls(claude, router);
|
|
424
423
|
const names = new Set();
|
|
425
424
|
const reserveName = (kind, name, taken) => {
|
|
426
425
|
const key = `${kind}:${name}`;
|
package/runtime/tool-calls.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Claude } from './claude.js';
|
|
2
|
+
import type { Router } from './router.js';
|
|
2
3
|
export type Agent = {
|
|
3
4
|
agentId?: string;
|
|
4
5
|
agentType?: string;
|
|
@@ -9,5 +10,5 @@ export type ToolCalls = {
|
|
|
9
10
|
};
|
|
10
11
|
export declare const reservedKeys: readonly string[];
|
|
11
12
|
export declare function toolInputOf(envelope: object): Record<string, unknown>;
|
|
12
|
-
export declare function toolCalls(
|
|
13
|
+
export declare function toolCalls(claude: Claude, router: Router): ToolCalls;
|
|
13
14
|
//# sourceMappingURL=tool-calls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-calls.d.ts","sourceRoot":"","sources":["../src/runtime/tool-calls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"tool-calls.d.ts","sourceRoot":"","sources":["../src/runtime/tool-calls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,MAAM,KAAK,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5D,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAC7C,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAAkD,CAAA;AAE5F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErE;AAMD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAiDnE"}
|
package/runtime/tool-calls.js
CHANGED
|
@@ -3,7 +3,7 @@ export function toolInputOf(envelope) {
|
|
|
3
3
|
return Object.fromEntries(Object.entries(envelope).filter(([key]) => !reservedKeys.includes(key)));
|
|
4
4
|
}
|
|
5
5
|
const keptCalls = 100;
|
|
6
|
-
export function toolCalls(
|
|
6
|
+
export function toolCalls(claude, router) {
|
|
7
7
|
let mainAgentType;
|
|
8
8
|
const agentIds = new Map();
|
|
9
9
|
const cwds = new Map();
|
|
@@ -11,15 +11,15 @@ export function toolCalls({ claude, on }) {
|
|
|
11
11
|
if (e.agent_id === undefined)
|
|
12
12
|
mainAgentType = e.agent_type;
|
|
13
13
|
};
|
|
14
|
-
|
|
14
|
+
router.add('classic.SessionStart', (e, next) => {
|
|
15
15
|
noteAgent(e);
|
|
16
16
|
return next(e);
|
|
17
17
|
});
|
|
18
|
-
|
|
18
|
+
router.add('classic.UserPromptSubmit', (e, next) => {
|
|
19
19
|
noteAgent(e);
|
|
20
20
|
return next(e);
|
|
21
21
|
});
|
|
22
|
-
|
|
22
|
+
router.add('tool.call', async (e, next) => {
|
|
23
23
|
if (e.agentId === undefined)
|
|
24
24
|
return next(e);
|
|
25
25
|
agentIds.set(e.tool_use_id, e.agentId);
|
|
@@ -30,7 +30,7 @@ export function toolCalls({ claude, on }) {
|
|
|
30
30
|
agentIds.delete(e.tool_use_id);
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
-
|
|
33
|
+
router.add('classic.PreToolUse', async (e, next) => {
|
|
34
34
|
cwds.set(e.tool_use_id, await claude.session.cwd());
|
|
35
35
|
for (const oldest of cwds.keys()) {
|
|
36
36
|
if (cwds.size <= keptCalls)
|
|
@@ -40,7 +40,7 @@ export function toolCalls({ claude, on }) {
|
|
|
40
40
|
return next(e);
|
|
41
41
|
});
|
|
42
42
|
for (const event of ['classic.PostToolUse', 'classic.PostToolUseFailure']) {
|
|
43
|
-
|
|
43
|
+
router.add(event, async (e, next) => {
|
|
44
44
|
try {
|
|
45
45
|
return await next(e);
|
|
46
46
|
}
|
package/src/connect.ts
CHANGED
|
@@ -6,17 +6,8 @@ import { createLifecycle, readPlugin, type Lifecycle } from './runtime/lifecycle
|
|
|
6
6
|
|
|
7
7
|
let lifecycle: Lifecycle<object>
|
|
8
8
|
|
|
9
|
-
async function startMod($: EngineInterface,
|
|
10
|
-
|
|
11
|
-
return next(e)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function routeToMod<N extends RoutedEvent>(_$: EngineInterface, e: Frozen<Args<N>>, next: Next<N>): Promise<EventResult<N>> {
|
|
15
|
-
return lifecycle.route(next.event, e, (passed: unknown) => next(passed as Args<N>) as Promise<EventResult<N>>)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function claudeOf($: EngineInterface): Claude {
|
|
19
|
-
return {
|
|
9
|
+
async function startMod($: EngineInterface, eventInput: Frozen<Args<'session.start'>>, passOn: Next<'session.start'>): Promise<EventResult<'session.start'>> {
|
|
10
|
+
const claude: Claude = {
|
|
20
11
|
plugin: { name: $.plugin.name, root: $.plugin.root },
|
|
21
12
|
ui: {
|
|
22
13
|
toast: (text, options) => $.ui.toast(text, options),
|
|
@@ -72,6 +63,12 @@ function claudeOf($: EngineInterface): Claude {
|
|
|
72
63
|
},
|
|
73
64
|
cmod: { call: (input) => $.cmod.call(input) },
|
|
74
65
|
}
|
|
66
|
+
await lifecycle.start(claude, readPlugin)
|
|
67
|
+
return passOn(eventInput)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function routeToMod<N extends RoutedEvent>(_$: EngineInterface, eventInput: Frozen<Args<N>>, passOn: Next<N>): Promise<EventResult<N>> {
|
|
71
|
+
return lifecycle.route(passOn.event, eventInput, (passed: unknown) => passOn(passed as Args<N>) as Promise<EventResult<N>>)
|
|
75
72
|
}
|
|
76
73
|
|
|
77
74
|
export function connect<State extends object>(on: On, definition: ModDefinition<State>): void {
|
package/src/jobs/check.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type {
|
|
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
4
|
import { parentOf } from '../utils/paths.js'
|
|
5
5
|
import { listed, messageOf } from '../utils/text.js'
|
|
6
|
-
import { afterCall, modOf, targetWords } from './
|
|
6
|
+
import { afterCall, modOf, targetWords } from './context.js'
|
|
7
7
|
import type { Workspace } from './permissions/find-project-scope.js'
|
|
8
8
|
import { matchTarget, targetOf, type Target } from './permissions/match-target.js'
|
|
9
9
|
|
|
10
10
|
const defaultMs = 60_000
|
|
11
11
|
|
|
12
|
-
export function check<State extends object = Record<never, never>>(options: { readonly after: Target | Target[]; readonly run: readonly string[]; readonly timeoutMs?: number }):
|
|
12
|
+
export function check<State extends object = Record<never, never>>(options: { readonly after: Target | Target[]; readonly run: readonly string[]; readonly timeoutMs?: number }): Job<void, State> {
|
|
13
13
|
const { after, run, timeoutMs = defaultMs } = options
|
|
14
14
|
const targets = Array.isArray(after) ? after : [after]
|
|
15
15
|
if (targets.length === 0) throw new Error("check: give after a target, such as { write: '**/*.ts' }.")
|
|
@@ -19,15 +19,15 @@ export function check<State extends object = Record<never, never>>(options: { re
|
|
|
19
19
|
if (!(timeoutMs > 0 && timeoutMs <= longestMs)) throw new Error(`check: the ${named} has timeoutMs ${timeoutMs}. Set it above 0 and at most ${longestMs} (${longestMs / 60_000} minutes).`)
|
|
20
20
|
const deadline: Deadline = { ms: timeoutMs, job: 'check' }
|
|
21
21
|
|
|
22
|
-
return (
|
|
22
|
+
return (job) => {
|
|
23
23
|
afterCall(
|
|
24
|
-
|
|
24
|
+
job,
|
|
25
25
|
async (use, workspace) => {
|
|
26
26
|
const triggered = await triggeredRun(targets, run, use, workspace)
|
|
27
27
|
if (triggered === undefined) return []
|
|
28
28
|
try {
|
|
29
29
|
const { command, folder } = triggered
|
|
30
|
-
const { exitCode, stdout, stderr } = await modOf(
|
|
30
|
+
const { exitCode, stdout, stderr } = await modOf(job, { folder }, workspace, deadline).process.run(command)
|
|
31
31
|
return exitCode === 0 ? [] : [`${command.join(' ')} exited with ${exitCode}:\n${`${stdout}${stderr}`.trim()}`]
|
|
32
32
|
} catch (error) {
|
|
33
33
|
return [`The ${named} failed: ${messageOf(error)}`]
|
|
@@ -35,7 +35,7 @@ export function check<State extends object = Record<never, never>>(options: { re
|
|
|
35
35
|
},
|
|
36
36
|
(error) => [`The check job failed, so the ${named} did not run: ${messageOf(error)}`],
|
|
37
37
|
)
|
|
38
|
-
|
|
38
|
+
job.announce(`a ${named}`)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Args, Frozen, HookStream, ProcessSpawnChunk, ProcessSpawnResult } from 'claude-code'
|
|
2
|
-
import type {
|
|
2
|
+
import type { JobContext, Mod } from '../mod.js'
|
|
3
3
|
import type { Claude } from '../runtime/claude.js'
|
|
4
4
|
import { beforeDeadline, type Deadline } from '../runtime/deadline.js'
|
|
5
5
|
import { dependencyCalls } from '../runtime/dependencies.js'
|
|
@@ -14,7 +14,7 @@ type Session = Omit<Workspace, 'projectRoot' | 'cwd'>
|
|
|
14
14
|
|
|
15
15
|
type Stream = HookStream<ProcessSpawnChunk, ProcessSpawnResult>
|
|
16
16
|
|
|
17
|
-
export function workspaceReader({ claude }:
|
|
17
|
+
export function workspaceReader({ claude }: JobContext): () => Promise<Workspace> {
|
|
18
18
|
let session: Promise<Session> | undefined
|
|
19
19
|
return async () => {
|
|
20
20
|
session ??= readSession(claude)
|
|
@@ -35,13 +35,13 @@ async function readSession(claude: Claude): Promise<Session> {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export function afterCall<State extends object>(
|
|
38
|
-
|
|
38
|
+
job: JobContext<State>,
|
|
39
39
|
contextAfter: (use: ToolUse, workspace: Workspace) => Promise<readonly string[]>,
|
|
40
40
|
failed: (error: unknown) => readonly string[],
|
|
41
41
|
): void {
|
|
42
|
-
const readWorkspace = workspaceReader(
|
|
43
|
-
|
|
44
|
-
const before = Promise.all([useOf(
|
|
42
|
+
const readWorkspace = workspaceReader(job)
|
|
43
|
+
job.on('tool.call', async (e, next) => {
|
|
44
|
+
const before = Promise.all([useOf(job, e), readWorkspace()])
|
|
45
45
|
await before.catch(() => undefined)
|
|
46
46
|
const result = await next(e)
|
|
47
47
|
if (result.deny !== undefined || result.isError === true) return result
|
|
@@ -50,15 +50,15 @@ export function afterCall<State extends object>(
|
|
|
50
50
|
})
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
async function useOf({ toolCalls }:
|
|
53
|
+
async function useOf({ toolCalls }: JobContext, e: Frozen<Args<'tool.call'>>): Promise<ToolUse> {
|
|
54
54
|
return { tool: e.tool, input: toolInputOf(e), ...(await toolCalls.agentOf(e.tool_use_id)) }
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function modOf<State extends object>(
|
|
58
|
-
return modWithin(
|
|
57
|
+
export function modOf<State extends object>(job: JobContext<State>, { call, folder }: { readonly call?: ToolCall; readonly folder: string }, workspace: Workspace, deadline: Deadline): Mod<State> {
|
|
58
|
+
return modWithin(job, deadline, async () => workspace.scope?.workTreeOf(call !== undefined && 'path' in call ? call.path : folder))
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export function modWithin<State extends object>({ mod, claude }:
|
|
61
|
+
export function modWithin<State extends object>({ mod, claude }: JobContext<State>, deadline: Deadline, workTree: () => Promise<string | undefined> = async () => undefined): Mod<State> {
|
|
62
62
|
const within = <Value>(call: string, task: Promise<Value>) => beforeDeadline(claude, deadline, call, task)
|
|
63
63
|
const folderOf = async (cwd: string | undefined) => {
|
|
64
64
|
const folder = cwd ?? (await workTree())
|
package/src/jobs/permissions.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Args, Frozen } from 'claude-code'
|
|
2
|
-
import type {
|
|
2
|
+
import type { Job, Mod } from '../mod.js'
|
|
3
3
|
import type { Deadline } from '../runtime/deadline.js'
|
|
4
4
|
import type { ToolUse } from '../utils/call-effects.js'
|
|
5
5
|
import { decidePermission, stricterVerdict, type PermissionRules as RulesFor, type Rule as RuleFor, type Verdict } from './permissions/decide-permission.js'
|
|
6
6
|
import { targetOf } from './permissions/match-target.js'
|
|
7
7
|
import { messageOf } from '../utils/text.js'
|
|
8
|
-
import { modOf, workspaceReader } from './
|
|
8
|
+
import { modOf, workspaceReader } from './context.js'
|
|
9
9
|
|
|
10
10
|
export type { CommandCall, FetchCall, FileCall, ToolCall } from '../utils/call-effects.js'
|
|
11
11
|
export type { Target } from './permissions/match-target.js'
|
|
@@ -14,28 +14,28 @@ export type PermissionRules<State extends object = Record<never, never>> = Rules
|
|
|
14
14
|
|
|
15
15
|
const deadline: Deadline = { ms: 2000, job: 'permissions' }
|
|
16
16
|
|
|
17
|
-
export function permissions<State extends object = Record<never, never>>(rules: PermissionRules<State>):
|
|
17
|
+
export function permissions<State extends object = Record<never, never>>(rules: PermissionRules<State>): Job<void, State> {
|
|
18
18
|
const count = (rules.deny?.length ?? 0) + (rules.ask?.length ?? 0)
|
|
19
19
|
if (count === 0) throw new Error('permissions: give it a deny or an ask rule, or remove it from setup.')
|
|
20
20
|
for (const rule of [...(rules.deny ?? []), ...(rules.ask ?? [])]) targetOf(rule)
|
|
21
21
|
|
|
22
|
-
return (
|
|
23
|
-
const readWorkspace = workspaceReader(
|
|
22
|
+
return (job) => {
|
|
23
|
+
const readWorkspace = workspaceReader(job)
|
|
24
24
|
|
|
25
25
|
const verdictOf = async (e: Frozen<Args<'tool.check'>>): Promise<Verdict | undefined> => {
|
|
26
26
|
try {
|
|
27
|
-
const [agent, workspace] = await Promise.all([
|
|
27
|
+
const [agent, workspace] = await Promise.all([job.toolCalls.agentOf(e.tool_use_id), readWorkspace()])
|
|
28
28
|
const use: ToolUse = { tool: e.tool, input: e.input, ...agent }
|
|
29
|
-
return await decidePermission(rules, use, workspace, (call, folder) => modOf(
|
|
29
|
+
return await decidePermission(rules, use, workspace, (call, folder) => modOf(job, { call, folder }, workspace, deadline))
|
|
30
30
|
} catch (error) {
|
|
31
31
|
return { decision: 'deny', reason: `The permissions job could not read the session, so it denies the call: ${messageOf(error)}` }
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
job.on('tool.check', async (e, next) => {
|
|
36
36
|
const [below, ours] = await Promise.all([next(e), verdictOf(e)])
|
|
37
37
|
return ours === undefined ? below : stricterVerdict<Verdict>(below, ours)
|
|
38
38
|
})
|
|
39
|
-
|
|
39
|
+
job.announce(`${count} permission rule${count === 1 ? '' : 's'}`)
|
|
40
40
|
}
|
|
41
41
|
}
|
package/src/jobs/program.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Job } from '../mod.js'
|
|
2
2
|
import { messageOf } from '../utils/text.js'
|
|
3
3
|
|
|
4
4
|
export type Program = {
|
|
@@ -10,7 +10,7 @@ type Address = Awaited<ReturnType<Program['ready']>>
|
|
|
10
10
|
|
|
11
11
|
const backoffSeconds = [1, 2, 4, 8, 16] as const
|
|
12
12
|
|
|
13
|
-
export function program(options: { readonly command: readonly string[]; readonly environment?: Record<string, string> }):
|
|
13
|
+
export function program(options: { readonly command: readonly string[]; readonly environment?: Record<string, string> }): Job<Program> {
|
|
14
14
|
const { command, environment } = options
|
|
15
15
|
return ({ mod, claude, announce }) => {
|
|
16
16
|
const [executable] = command
|
package/src/jobs/prompt.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Job, JobContext, Mod } from '../mod.js'
|
|
2
2
|
import { longestMs, type Deadline } from '../runtime/deadline.js'
|
|
3
3
|
import { listed, messageOf } from '../utils/text.js'
|
|
4
4
|
import { callEffects, type ToolCall } from '../utils/call-effects.js'
|
|
5
5
|
import { matchTarget, targetOf, type Target } from './permissions/match-target.js'
|
|
6
|
-
import { afterCall, modOf, modWithin, targetWords } from './
|
|
6
|
+
import { afterCall, modOf, modWithin, targetWords } from './context.js'
|
|
7
7
|
|
|
8
8
|
type PromptInput = { userPrompt?: string; call?: ToolCall }
|
|
9
9
|
|
|
@@ -16,16 +16,16 @@ type PromptOptions<State extends object> = {
|
|
|
16
16
|
|
|
17
17
|
const deadline: Deadline = { ms: 5000, longestMs, job: 'prompt' }
|
|
18
18
|
|
|
19
|
-
export function prompt<State extends object = Record<never, never>>({ name, prompt: text, when, after }: PromptOptions<State>):
|
|
19
|
+
export function prompt<State extends object = Record<never, never>>({ name, prompt: text, when, after }: PromptOptions<State>): Job<void, State> {
|
|
20
20
|
if (name.trim() === '') throw new Error('prompt: give the block a name. Claude reads the text under it.')
|
|
21
21
|
if (when !== undefined && after !== undefined) throw new Error(`prompt "${name}": use when or after, not both. Add a second prompt for the other trigger.`)
|
|
22
22
|
const targets = after === undefined ? [] : Array.isArray(after) ? after : [after]
|
|
23
23
|
for (const target of targets) targetOf(target)
|
|
24
24
|
|
|
25
|
-
return (
|
|
26
|
-
|
|
25
|
+
return (job) => {
|
|
26
|
+
job.reserveName('prompt', name, `prompt: ${job.mod.name} adds the name "${name}" two times. Give each prompt its own name.`)
|
|
27
27
|
|
|
28
|
-
const log = (reason: string) =>
|
|
28
|
+
const log = (reason: string) => job.claude.ui.log(`prompt "${name}" added nothing: ${reason}`, { to: 'debug' })
|
|
29
29
|
const textFor = async (input: PromptInput, mod: Mod<State>) => {
|
|
30
30
|
try {
|
|
31
31
|
const value = typeof text === 'string' ? text : await text(input, mod)
|
|
@@ -42,20 +42,20 @@ export function prompt<State extends object = Record<never, never>>({ name, prom
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (when !== undefined) {
|
|
45
|
-
addAfterUserPrompts(
|
|
46
|
-
|
|
45
|
+
addAfterUserPrompts(job, when, (userPrompt) => headedText({ userPrompt }, modWithin(job, deadline)), log)
|
|
46
|
+
job.announce(`the ${name} prompt after matching user prompts`)
|
|
47
47
|
} else if (targets.length > 0) {
|
|
48
|
-
addAfterCalls(
|
|
49
|
-
|
|
48
|
+
addAfterCalls(job, targets, headedText, log)
|
|
49
|
+
job.announce(`the ${name} prompt after ${listed(targets.map(targetWords))}`)
|
|
50
50
|
} else {
|
|
51
|
-
addOncePerConversation(
|
|
52
|
-
|
|
51
|
+
addOncePerConversation(job, name, () => textFor({}, modWithin(job, deadline)), log)
|
|
52
|
+
job.announce(`the ${name} prompt`)
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function addOncePerConversation(
|
|
58
|
-
|
|
57
|
+
function addOncePerConversation(job: JobContext, name: string, textFor: () => Promise<string | undefined>, log: (reason: string) => void): void {
|
|
58
|
+
job.on('prompt.context', async (e, next) => {
|
|
59
59
|
const below = await next(e)
|
|
60
60
|
if (below.blocks.some((block) => block.name === name)) {
|
|
61
61
|
log(`a block named "${name}" is already in the context`)
|
|
@@ -66,8 +66,8 @@ function addOncePerConversation(part: PartContext, name: string, textFor: () =>
|
|
|
66
66
|
})
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function addAfterUserPrompts(
|
|
70
|
-
|
|
69
|
+
function addAfterUserPrompts(job: JobContext, when: RegExp | ((userPrompt: string) => boolean), textFor: (userPrompt: string) => Promise<string | undefined>, log: (reason: string) => void): void {
|
|
70
|
+
job.on('prompt.submit', async (e, next) => {
|
|
71
71
|
let value: string | undefined
|
|
72
72
|
try {
|
|
73
73
|
if (typeof when === 'function' ? when(e.text) : e.text.search(when) >= 0) value = await textFor(e.text)
|
|
@@ -79,19 +79,19 @@ function addAfterUserPrompts(part: PartContext, when: RegExp | ((userPrompt: str
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function addAfterCalls<State extends object>(
|
|
82
|
-
|
|
82
|
+
job: JobContext<State>,
|
|
83
83
|
targets: Target[],
|
|
84
84
|
textFor: (input: PromptInput, mod: Mod<State>) => Promise<string | undefined>,
|
|
85
85
|
log: (reason: string) => void,
|
|
86
86
|
): void {
|
|
87
87
|
afterCall(
|
|
88
|
-
|
|
88
|
+
job,
|
|
89
89
|
async (use, workspace) => {
|
|
90
90
|
const effects = callEffects(use, workspace)
|
|
91
91
|
for (const target of targets) {
|
|
92
92
|
const [matched] = await matchTarget(target, use, effects, workspace)
|
|
93
93
|
if (matched === undefined) continue
|
|
94
|
-
const value = await textFor({ call: matched.call }, modOf(
|
|
94
|
+
const value = await textFor({ call: matched.call }, modOf(job, matched, workspace, deadline))
|
|
95
95
|
return value === undefined ? [] : [value]
|
|
96
96
|
}
|
|
97
97
|
return []
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { CommandRunResult } from 'claude-code'
|
|
2
|
-
import type {
|
|
2
|
+
import type { Job, Mod } from '../mod.js'
|
|
3
3
|
import { parse } from '../vendor.js'
|
|
4
4
|
import { longestMs, type Deadline } from '../runtime/deadline.js'
|
|
5
5
|
import { messageOf } from '../utils/text.js'
|
|
6
|
-
import { modWithin } from './
|
|
6
|
+
import { modWithin } from './context.js'
|
|
7
7
|
|
|
8
8
|
export type Reply = string | { text?: string; context?: string } | undefined
|
|
9
9
|
|
|
@@ -17,10 +17,10 @@ export function slashCommand<State extends object = Record<never, never>>(option
|
|
|
17
17
|
readonly argumentHint?: string
|
|
18
18
|
readonly immediate?: true
|
|
19
19
|
readonly reply: (input: { args: string; positionals: string[] }, mod: Mod<State>) => Reply | void | Promise<Reply | void>
|
|
20
|
-
}):
|
|
20
|
+
}): Job<void, State> {
|
|
21
21
|
const { name, description, argumentHint, immediate, reply } = options
|
|
22
|
-
return (
|
|
23
|
-
const { mod, claude,
|
|
22
|
+
return (job) => {
|
|
23
|
+
const { mod, claude, announce, reserveName } = job
|
|
24
24
|
if (!commandName.test(name)) throw new Error(`${mod.name}: "${name}" is not a slash command name. Use 1 to 64 letters, digits, "_", or "-", without the slash.`)
|
|
25
25
|
reserveName('slashCommand', name, `${mod.name}: the slash command /${name} is already added. Give each slashCommand its own name.`)
|
|
26
26
|
|
|
@@ -35,8 +35,8 @@ export function slashCommand<State extends object = Record<never, never>>(option
|
|
|
35
35
|
)
|
|
36
36
|
announce(`/${name}`)
|
|
37
37
|
|
|
38
|
-
const replyMod = modWithin(
|
|
39
|
-
on('command.run', async (e, next) => {
|
|
38
|
+
const replyMod = modWithin(job, deadline)
|
|
39
|
+
job.on('command.run', async (e, next) => {
|
|
40
40
|
if (e.command !== registered) return next(e)
|
|
41
41
|
try {
|
|
42
42
|
return answerOf(await reply({ args: e.args, positionals: splitWords(e.args) }, replyMod))
|
package/src/jobs/status-line.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Job, Mod } from '../mod.js'
|
|
2
2
|
import type { Deadline } from '../runtime/deadline.js'
|
|
3
3
|
import { messageOf } from '../utils/text.js'
|
|
4
|
-
import { modWithin } from './
|
|
4
|
+
import { modWithin } from './context.js'
|
|
5
5
|
|
|
6
6
|
export type Usage = {
|
|
7
7
|
model: string
|
|
@@ -14,14 +14,14 @@ const deadline: Deadline = { ms: 2000, job: 'statusLine' }
|
|
|
14
14
|
export function statusLine<State extends object = Record<never, never>>(options: {
|
|
15
15
|
readonly text: (usage: Usage, mod: Mod<State>) => string | undefined | Promise<string | undefined>
|
|
16
16
|
readonly interval?: number
|
|
17
|
-
}):
|
|
17
|
+
}): Job<void, State> {
|
|
18
18
|
const { text, interval = 10000 } = options
|
|
19
|
-
return (
|
|
20
|
-
const { mod, claude,
|
|
19
|
+
return (job) => {
|
|
20
|
+
const { mod, claude, announce, reserveName } = job
|
|
21
21
|
if (!(interval >= 1)) throw new Error(`${mod.name}: the status line interval is ${interval}. Give it in milliseconds, 1 or more.`)
|
|
22
22
|
reserveName('statusLine', '', `${mod.name}: a status line is already added. A mod has one status line: join the texts in one statusLine.`)
|
|
23
23
|
|
|
24
|
-
const textMod = modWithin(
|
|
24
|
+
const textMod = modWithin(job, deadline)
|
|
25
25
|
let shown: string | undefined
|
|
26
26
|
let queue = Promise.resolve()
|
|
27
27
|
const update = async () => {
|
|
@@ -48,7 +48,7 @@ export function statusLine<State extends object = Record<never, never>>(options:
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
announce('a status line')
|
|
51
|
-
on('session.measure', (e, next) => {
|
|
51
|
+
job.on('session.measure', (e, next) => {
|
|
52
52
|
refresh()
|
|
53
53
|
return next(e)
|
|
54
54
|
})
|