@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.
Files changed (52) hide show
  1. package/connect.d.ts.map +1 -1
  2. package/connect.js +7 -9
  3. package/docs/commands.md +3 -2
  4. package/docs/index.md +2 -2
  5. package/docs/jobs.md +20 -20
  6. package/docs/mod.md +1 -1
  7. package/docs/testing.md +1 -1
  8. package/jobs/check.d.ts +2 -2
  9. package/jobs/check.d.ts.map +1 -1
  10. package/jobs/check.js +5 -5
  11. package/jobs/context.d.ts +14 -0
  12. package/jobs/context.d.ts.map +1 -0
  13. package/jobs/{part-context.js → context.js} +6 -6
  14. package/jobs/permissions.d.ts +2 -2
  15. package/jobs/permissions.d.ts.map +1 -1
  16. package/jobs/permissions.js +7 -7
  17. package/jobs/program.d.ts +2 -2
  18. package/jobs/program.d.ts.map +1 -1
  19. package/jobs/prompt.d.ts +2 -2
  20. package/jobs/prompt.d.ts.map +1 -1
  21. package/jobs/prompt.js +17 -17
  22. package/jobs/slash-command.d.ts +2 -2
  23. package/jobs/slash-command.d.ts.map +1 -1
  24. package/jobs/slash-command.js +5 -5
  25. package/jobs/status-line.d.ts +2 -2
  26. package/jobs/status-line.d.ts.map +1 -1
  27. package/jobs/status-line.js +5 -5
  28. package/jobs/tool.d.ts +2 -2
  29. package/jobs/tool.d.ts.map +1 -1
  30. package/jobs/tool.js +5 -5
  31. package/mod.d.ts +3 -3
  32. package/mod.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/runtime/lifecycle.d.ts.map +1 -1
  35. package/runtime/lifecycle.js +8 -9
  36. package/runtime/tool-calls.d.ts +3 -2
  37. package/runtime/tool-calls.d.ts.map +1 -1
  38. package/runtime/tool-calls.js +6 -6
  39. package/src/connect.ts +8 -11
  40. package/src/jobs/check.ts +7 -7
  41. package/src/jobs/{part-context.ts → context.ts} +10 -10
  42. package/src/jobs/permissions.ts +9 -9
  43. package/src/jobs/program.ts +2 -2
  44. package/src/jobs/prompt.ts +19 -19
  45. package/src/jobs/slash-command.ts +7 -7
  46. package/src/jobs/status-line.ts +7 -7
  47. package/src/jobs/tool.ts +7 -7
  48. package/src/mod.ts +3 -3
  49. package/src/runtime/lifecycle.ts +9 -10
  50. package/src/runtime/tool-calls.ts +8 -7
  51. package/jobs/part-context.d.ts +0 -14
  52. package/jobs/part-context.d.ts.map +0 -1
package/connect.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["src/connect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoD,EAAE,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AA2E7C,wBAAgB,OAAO,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CA8B5F"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["src/connect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoD,EAAE,EAAE,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAwE7C,wBAAgB,OAAO,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CA8B5F"}
package/connect.js CHANGED
@@ -1,14 +1,7 @@
1
1
  import { createLifecycle, readPlugin } from './runtime/lifecycle.js';
2
2
  let lifecycle;
3
- async function startMod($, e, next) {
4
- await lifecycle.start(claudeOf($), readPlugin);
5
- return next(e);
6
- }
7
- function routeToMod(_$, e, next) {
8
- return lifecycle.route(next.event, e, (passed) => next(passed));
9
- }
10
- function claudeOf($) {
11
- return {
3
+ async function startMod($, eventInput, passOn) {
4
+ const claude = {
12
5
  plugin: { name: $.plugin.name, root: $.plugin.root },
13
6
  ui: {
14
7
  toast: (text, options) => $.ui.toast(text, options),
@@ -64,6 +57,11 @@ function claudeOf($) {
64
57
  },
65
58
  cmod: { call: (input) => $.cmod.call(input) },
66
59
  };
60
+ await lifecycle.start(claude, readPlugin);
61
+ return passOn(eventInput);
62
+ }
63
+ function routeToMod(_$, eventInput, passOn) {
64
+ return lifecycle.route(passOn.event, eventInput, (passed) => passOn(passed));
67
65
  }
68
66
  export function connect(on, definition) {
69
67
  lifecycle = createLifecycle(definition);
package/docs/commands.md CHANGED
@@ -82,7 +82,7 @@ cmod publish [path] [--dry-run]
82
82
 
83
83
  Releases the mod at `path` (default: the current folder) at the version in its `plugin.json`:
84
84
 
85
- 1. Builds the release from the committed files, leaving out `cli/`, `.github/`, and `.claude/`.
85
+ 1. Builds the release from the committed files, leaving out `cli/`, `.github/`, and `.claude/`. A `"files"` list in `package.json` limits the release to the paths it lists, plus `.claude-plugin/`, `package.json`, the README, and the license, the way `npm publish` reads it. List every folder the hooks module imports from, such as `"files": ["hooks", "src", "skills"]`, because the bundle in step 2 is built from the release.
86
86
  2. Bundles the hooks module that `hooks/hooks.json` names, with the mod's source and packages, into one readable `.js` file, and points `hooks/hooks.json` at it. Anthropic's plugin directory reads a repository without installing its packages, so it can follow a mod only when all its code is in one file.
87
87
  3. Checks the release with `claude plugin validate --strict`, and stops with the validator's message when it fails.
88
88
  4. Commits the release as the `release` branch, and builds the release archive from that commit.
@@ -91,7 +91,7 @@ Releases the mod at `path` (default: the current folder) at the version in its `
91
91
  7. Commits that file, tags `v<version>`, pushes the tag and the `release` branch, and creates the GitHub release.
92
92
  8. Prints the link to paste as the Repository when you submit the mod at [claude.ai/directory/manage](https://claude.ai/directory/manage), such as `https://github.com/owner/greeter/tree/release`. The portal reads the branch from the link, so the directory follows `release`.
93
93
 
94
- The release keeps `package.json` and `bun.lock`, so Claude Code still installs the mod's packages for its install and uninstall steps. `main` keeps the source only.
94
+ The release keeps `package.json`, so Claude Code still installs the mod's packages for its install and uninstall steps. It keeps `bun.lock` too, unless a `"files"` list leaves it out. `main` keeps the source only.
95
95
 
96
96
  It needs, and refuses to start without:
97
97
 
@@ -101,6 +101,7 @@ It needs, and refuses to start without:
101
101
  - the `claude` command, which validates the release
102
102
  - an `origin` remote on GitHub
103
103
  - a `package.json` with no dependency on a `file:` or `link:` path, which no user has
104
+ - a `"files"` list, when `package.json` has one, whose every path matches a committed file
104
105
  - a `"program"` in the `cmod` key of `package.json` that names the program `cli/` declares, when `cli/` declares one
105
106
  - the network, to hash the CMod plugin release it lists, unless the mod is CMod itself
106
107
  - for a real publish, a working tree with no uncommitted changes, a `v<version>` tag that does not exist yet, a `git push` to `origin` that succeeds, and the `gh` command, which creates the GitHub release
package/docs/index.md CHANGED
@@ -70,7 +70,7 @@ A mod imports from the files below, and every other file in this package is inte
70
70
 
71
71
  | Import | Exports | Docs |
72
72
  | --- | --- | --- |
73
- | `mod.js` | `defineMod`, `ModDefinition`, `Mod`, `PartContext`, `Part`, `ProgressStep`, `PaneHandle`, `longestMs`, `messageOf` | [mod.md](mod.md), [jobs.md](jobs.md), [ui.md](ui.md) |
73
+ | `mod.js` | `defineMod`, `ModDefinition`, `Mod`, `JobContext`, `Job`, `ProgressStep`, `PaneHandle`, `longestMs`, `messageOf` | [mod.md](mod.md), [jobs.md](jobs.md), [ui.md](ui.md) |
74
74
  | `mod.js` | `Claude`, `RoutedEvent`, `RoutedHook`, `ToolCalls` | [jobs.md](jobs.md) |
75
75
  | `mod.js` | `ModEvent`, `ModHook`, `HookAnswer` | [hooks.md](hooks.md) |
76
76
  | `mod.js` | `notInstalled` | [dependencies.md](dependencies.md) |
@@ -87,7 +87,7 @@ A mod imports from the files below, and every other file in this package is inte
87
87
  | `jobs/prompt.js` | `prompt` | [jobs.md](jobs.md) |
88
88
  | `jobs/status-line.js` | `statusLine`, `Usage` | [jobs.md](jobs.md) |
89
89
  | `jobs/program.js` | `program`, `Program` | [jobs.md](jobs.md) |
90
- | `jobs/part-context.js` | `afterCall`, `modWithin`, `modOf`, `workspaceReader` | [jobs.md](jobs.md) |
90
+ | `jobs/context.js` | `afterCall`, `modWithin`, `modOf`, `workspaceReader` | [jobs.md](jobs.md) |
91
91
  | `jobs/permissions/decide-permission.js` | `decidePermission`, `stricterVerdict`, `Rule`, `PermissionRules`, `Decision`, `Verdict` | [jobs.md](jobs.md) |
92
92
  | `jobs/permissions/find-project-scope.js` | `findProjectScope`, `ProjectScope`, `Workspace` | [jobs.md](jobs.md) |
93
93
 
package/docs/jobs.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # Jobs
2
2
 
3
- A job is a ready-made part of a mod: a slash command, a tool, permission rules, a check, a prompt, a status line, or a background program. Add each in `setup` with `mod.use`.
3
+ A job is a ready-made feature of a mod: a slash command, a tool, permission rules, a check, a prompt, a status line, or a background program. Add each in `setup` with `mod.use`.
4
4
 
5
5
  ```ts
6
- mod.use<Handle>(part: Part<Handle, State>): Handle
6
+ mod.use<Handle>(job: Job<Handle, State>): Handle
7
7
 
8
- type Part<Handle, State> = (context: PartContext<State>) => Handle
8
+ type Job<Handle, State> = (context: JobContext<State>) => Handle
9
9
  ```
10
10
 
11
- Each job function, such as `slashCommand(options)`, returns a `Part`. `mod.use` runs the part and returns its handle. A job that has nothing to hand back returns `void`.
11
+ Each job function, such as `slashCommand(options)`, returns a `Job`. `mod.use` runs the job and returns its handle. A job that has nothing to hand back returns `void`.
12
12
 
13
- A job's bad options throw at one of two times. `check`, `permissions`, and `prompt` check their options when the job function is called. `slashCommand`, `tool`, `statusLine`, and `program` check theirs inside the part, at `mod.use`, so the error surfaces as `its setup function threw: …`.
13
+ A job's bad options throw at one of two times. `check`, `permissions`, and `prompt` check their options when the job function is called. `slashCommand`, `tool`, `statusLine`, and `program` check theirs when the job runs, at `mod.use`, so the error surfaces as `its setup function threw: …`.
14
14
 
15
15
  | Job | Import | Adds |
16
16
  | --- | --- | --- |
@@ -48,7 +48,7 @@ slashCommand<State>(options: {
48
48
  readonly argumentHint?: string
49
49
  readonly immediate?: true
50
50
  readonly reply: (input: { args: string; positionals: string[] }, mod: Mod<State>) => Reply | void | Promise<Reply | void>
51
- }): Part<void, State>
51
+ }): Job<void, State>
52
52
 
53
53
  type Reply = string | { text?: string; context?: string } | undefined
54
54
  ```
@@ -94,7 +94,7 @@ tool<Schema, State>(options: {
94
94
  readonly description: string
95
95
  readonly inputSchema?: Schema
96
96
  readonly execute: (input: FromSchema<Schema>, mod: Mod<State>) => unknown
97
- }): Part<{ readonly name: string }, State>
97
+ }): Job<{ readonly name: string }, State>
98
98
  ```
99
99
 
100
100
  - `name` is 1 to 64 letters, digits, `_`, or `-`. Claude sees the tool as `mcp__<plugin name>__<name>`, and the handle's `name` is that full name.
@@ -160,7 +160,7 @@ A `command` pattern is not a glob. CMod splits it into words the way it splits a
160
160
  ## permissions
161
161
 
162
162
  ```ts
163
- permissions<State>(rules: { deny?: Rule<State>[]; ask?: Rule<State>[] }): Part<void, State>
163
+ permissions<State>(rules: { deny?: Rule<State>[]; ask?: Rule<State>[] }): Job<void, State>
164
164
 
165
165
  type Rule<State> = Target & {
166
166
  when?: (call: <the call of the target's key>, mod: Mod<State>) => boolean | Promise<boolean>
@@ -211,7 +211,7 @@ export const guard = defineMod({
211
211
  ## check
212
212
 
213
213
  ```ts
214
- check<State>(options: { readonly after: Target | Target[]; readonly run: readonly string[]; readonly timeoutMs?: number }): Part<void, State>
214
+ check<State>(options: { readonly after: Target | Target[]; readonly run: readonly string[]; readonly timeoutMs?: number }): Job<void, State>
215
215
  ```
216
216
 
217
217
  - After each call that matches `after` and succeeds, CMod runs `run`. A call that was denied or failed runs nothing.
@@ -241,7 +241,7 @@ prompt<State>(options: {
241
241
  prompt: string | ((input: { userPrompt?: string; call?: ToolCall }, mod: Mod<State>) => string | undefined | Promise<string | undefined>)
242
242
  when?: RegExp | ((userPrompt: string) => boolean)
243
243
  after?: Target | Target[]
244
- }): Part<void, State>
244
+ }): Job<void, State>
245
245
  ```
246
246
 
247
247
  `prompt` adds text that Claude reads. `when` and `after` pick when:
@@ -277,7 +277,7 @@ export const conventions = defineMod({
277
277
  statusLine<State>(options: {
278
278
  readonly text: (usage: Usage, mod: Mod<State>) => string | undefined | Promise<string | undefined>
279
279
  readonly interval?: number
280
- }): Part<void, State>
280
+ }): Job<void, State>
281
281
 
282
282
  type Usage = { model: string; context: { tokens?: number; window: number; percent?: number }; cost?: { usd: number } }
283
283
  ```
@@ -303,7 +303,7 @@ export const usage = defineMod({
303
303
  ## program
304
304
 
305
305
  ```ts
306
- program(options: { readonly command: readonly string[]; readonly environment?: Record<string, string> }): Part<Program>
306
+ program(options: { readonly command: readonly string[]; readonly environment?: Record<string, string> }): Job<Program>
307
307
 
308
308
  type Program = {
309
309
  readonly state: 'stopped' | 'starting' | 'running' | 'backoff' | 'fatal'
@@ -345,10 +345,10 @@ export const preview = defineMod({
345
345
 
346
346
  ## Write a job of your own
347
347
 
348
- A `Part` is a function. `mod.use` calls it with a `PartContext` and returns what it returns:
348
+ A `Job` is a function. `mod.use` calls it with a `JobContext` and returns what it returns:
349
349
 
350
350
  ```ts
351
- type PartContext<State> = {
351
+ type JobContext<State> = {
352
352
  readonly mod: Mod<State>
353
353
  readonly claude: Claude
354
354
  on<N extends RoutedEvent>(event: N, hook: RoutedHook<N>): void
@@ -367,9 +367,9 @@ type PartContext<State> = {
367
367
  - `toolCalls.cwdOf(toolUseId)` returns the working folder at the call's `PreToolUse`, or `undefined` once its `PostToolUse` or `PostToolUseFailure` has run. CMod keeps the folders of the last 100 calls.
368
368
 
369
369
  ```ts
370
- import { defineMod, type Part } from '../node_modules/@cmodjs/core/mod.js'
370
+ import { defineMod, type Job } from '../node_modules/@cmodjs/core/mod.js'
371
371
 
372
- const clock: Part<{ now(): Promise<number> }> = ({ claude, announce }) => {
372
+ const clock: Job<{ now(): Promise<number> }> = ({ claude, announce }) => {
373
373
  announce('a clock')
374
374
  return { now: () => claude.clock.now() }
375
375
  }
@@ -436,10 +436,10 @@ The built-in jobs are written from these building blocks, which a job of your ow
436
436
 
437
437
  | Import | Export | What it does |
438
438
  | --- | --- | --- |
439
- | `jobs/part-context.js` | `afterCall(part, contextAfter, failed)` | Runs `contextAfter` after each call that succeeds, and adds the lines it returns to the call's result. |
440
- | `jobs/part-context.js` | `modWithin(part, deadline, workTree?)` | A `mod` whose calls fail at `deadline`, `{ ms, job?, longestMs? }`. |
441
- | `jobs/part-context.js` | `modOf(part, { call?, folder }, workspace, deadline)` | `modWithin`, with `mod.process` calls run in the call's work tree. |
442
- | `jobs/part-context.js` | `workspaceReader(part)` | A function that reads the session's `projectRoot`, `cwd`, `home`, file access, and project scope. |
439
+ | `jobs/context.js` | `afterCall(job, contextAfter, failed)` | Runs `contextAfter` after each call that succeeds, and adds the lines it returns to the call's result. |
440
+ | `jobs/context.js` | `modWithin(job, deadline, workTree?)` | A `mod` whose calls fail at `deadline`, `{ ms, job?, longestMs? }`. |
441
+ | `jobs/context.js` | `modOf(job, { call?, folder }, workspace, deadline)` | `modWithin`, with `mod.process` calls run in the call's work tree. |
442
+ | `jobs/context.js` | `workspaceReader(job)` | A function that reads the session's `projectRoot`, `cwd`, `home`, file access, and project scope. |
443
443
  | `jobs/permissions/decide-permission.js` | `decidePermission`, `stricterVerdict`, and the types `Rule`, `PermissionRules`, `Decision`, `Verdict` | Decides a call against permission rules. |
444
444
  | `jobs/permissions/find-project-scope.js` | `findProjectScope`, and the types `ProjectScope`, `Workspace` | Finds the repository a project plugin belongs to. |
445
445
 
package/docs/mod.md CHANGED
@@ -86,7 +86,7 @@ type Mod<State> = {
86
86
  readonly projectRoot: string
87
87
  readonly cwd: string
88
88
  on(event, hook): void
89
- use(part): Handle
89
+ use(job): Handle
90
90
  readonly ui: { pane, render, toast, progress, ask }
91
91
  readonly process: { run, spawn }
92
92
  readonly fs: { read, write, list }
package/docs/testing.md CHANGED
@@ -69,7 +69,7 @@ type TestedMod<State> = {
69
69
 
70
70
  ### start
71
71
 
72
- Starts the mod: loads its state, runs `setup`, and adds its parts. `fire`, `lines`, `type`, `callTool`, `press`, and `moveTo` start the mod first, so a test calls `start` only before it reads `state` or `shown` with nothing else to run. It rejects with the reason when the mod does not start.
72
+ Starts the mod: loads its state, runs `setup`, and adds its hooks, panes, and jobs. `fire`, `lines`, `type`, `callTool`, `press`, and `moveTo` start the mod first, so a test calls `start` only before it reads `state` or `shown` with nothing else to run. It rejects with the reason when the mod does not start.
73
73
 
74
74
  ### fire
75
75
 
package/jobs/check.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { Part } from '../mod.js';
1
+ import type { Job } from '../mod.js';
2
2
  import { type Target } from './permissions/match-target.js';
3
3
  export declare function check<State extends object = Record<never, never>>(options: {
4
4
  readonly after: Target | Target[];
5
5
  readonly run: readonly string[];
6
6
  readonly timeoutMs?: number;
7
- }): Part<void, State>;
7
+ }): Job<void, State>;
8
8
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/jobs/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAOrC,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAIlF,wBAAgB,KAAK,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CA4BlM"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/jobs/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAOpC,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAIlF,wBAAgB,KAAK,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CA4BjM"}
package/jobs/check.js CHANGED
@@ -2,7 +2,7 @@ import { longestMs } from '../runtime/deadline.js';
2
2
  import { callEffects } from '../utils/call-effects.js';
3
3
  import { parentOf } from '../utils/paths.js';
4
4
  import { listed, messageOf } from '../utils/text.js';
5
- import { afterCall, modOf, targetWords } from './part-context.js';
5
+ import { afterCall, modOf, targetWords } from './context.js';
6
6
  import { matchTarget, targetOf } from './permissions/match-target.js';
7
7
  const defaultMs = 60_000;
8
8
  export function check(options) {
@@ -18,21 +18,21 @@ export function check(options) {
18
18
  if (!(timeoutMs > 0 && timeoutMs <= longestMs))
19
19
  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 = { ms: timeoutMs, job: 'check' };
21
- return (context) => {
22
- afterCall(context, async (use, workspace) => {
21
+ return (job) => {
22
+ afterCall(job, async (use, workspace) => {
23
23
  const triggered = await triggeredRun(targets, run, use, workspace);
24
24
  if (triggered === undefined)
25
25
  return [];
26
26
  try {
27
27
  const { command, folder } = triggered;
28
- const { exitCode, stdout, stderr } = await modOf(context, { folder }, workspace, deadline).process.run(command);
28
+ const { exitCode, stdout, stderr } = await modOf(job, { folder }, workspace, deadline).process.run(command);
29
29
  return exitCode === 0 ? [] : [`${command.join(' ')} exited with ${exitCode}:\n${`${stdout}${stderr}`.trim()}`];
30
30
  }
31
31
  catch (error) {
32
32
  return [`The ${named} failed: ${messageOf(error)}`];
33
33
  }
34
34
  }, (error) => [`The check job failed, so the ${named} did not run: ${messageOf(error)}`]);
35
- context.announce(`a ${named}`);
35
+ job.announce(`a ${named}`);
36
36
  };
37
37
  }
38
38
  async function triggeredRun(after, run, use, workspace) {
@@ -0,0 +1,14 @@
1
+ import type { JobContext, Mod } from '../mod.js';
2
+ import { type Deadline } from '../runtime/deadline.js';
3
+ import type { ToolCall, ToolUse } from '../utils/call-effects.js';
4
+ import { type Workspace } from './permissions/find-project-scope.js';
5
+ import { type Target } from './permissions/match-target.js';
6
+ export declare function workspaceReader({ claude }: JobContext): () => Promise<Workspace>;
7
+ export declare function afterCall<State extends object>(job: JobContext<State>, contextAfter: (use: ToolUse, workspace: Workspace) => Promise<readonly string[]>, failed: (error: unknown) => readonly string[]): void;
8
+ export declare function modOf<State extends object>(job: JobContext<State>, { call, folder }: {
9
+ readonly call?: ToolCall;
10
+ readonly folder: string;
11
+ }, workspace: Workspace, deadline: Deadline): Mod<State>;
12
+ export declare function modWithin<State extends object>({ mod, claude }: JobContext<State>, deadline: Deadline, workTree?: () => Promise<string | undefined>): Mod<State>;
13
+ export declare function targetWords(target: Target): string;
14
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/jobs/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAEhD,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAItE,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,qCAAqC,CAAA;AACtF,OAAO,EAAY,KAAK,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAOrE,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,EAAE,UAAU,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAOhF;AAaD,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAC5C,GAAG,EAAE,UAAU,CAAC,KAAK,CAAC,EACtB,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,EAChF,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,MAAM,EAAE,GAC5C,IAAI,CAUN;AAMD,wBAAgB,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAEjM;AAED,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAyB,GAAG,GAAG,CAAC,KAAK,CAAC,CAwBvL;AAwBD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CASlD"}
@@ -23,10 +23,10 @@ async function readSession(claude) {
23
23
  throw new Error('HOME is not set, so ~ in a path has no meaning. Start Claude Code with HOME set.');
24
24
  return { home, fs, scope: await findProjectScope(claude.plugin.root, home, fs) };
25
25
  }
26
- export function afterCall(part, contextAfter, failed) {
27
- const readWorkspace = workspaceReader(part);
28
- part.on('tool.call', async (e, next) => {
29
- const before = Promise.all([useOf(part, e), readWorkspace()]);
26
+ export function afterCall(job, contextAfter, failed) {
27
+ const readWorkspace = workspaceReader(job);
28
+ job.on('tool.call', async (e, next) => {
29
+ const before = Promise.all([useOf(job, e), readWorkspace()]);
30
30
  await before.catch(() => undefined);
31
31
  const result = await next(e);
32
32
  if (result.deny !== undefined || result.isError === true)
@@ -38,8 +38,8 @@ export function afterCall(part, contextAfter, failed) {
38
38
  async function useOf({ toolCalls }, e) {
39
39
  return { tool: e.tool, input: toolInputOf(e), ...(await toolCalls.agentOf(e.tool_use_id)) };
40
40
  }
41
- export function modOf(context, { call, folder }, workspace, deadline) {
42
- return modWithin(context, deadline, async () => workspace.scope?.workTreeOf(call !== undefined && 'path' in call ? call.path : folder));
41
+ export function modOf(job, { call, folder }, workspace, deadline) {
42
+ return modWithin(job, deadline, async () => workspace.scope?.workTreeOf(call !== undefined && 'path' in call ? call.path : folder));
43
43
  }
44
44
  export function modWithin({ mod, claude }, deadline, workTree = async () => undefined) {
45
45
  const within = (call, task) => beforeDeadline(claude, deadline, call, task);
@@ -1,8 +1,8 @@
1
- import type { Mod, Part } from '../mod.js';
1
+ import type { Job, Mod } from '../mod.js';
2
2
  import { type PermissionRules as RulesFor, type Rule as RuleFor } from './permissions/decide-permission.js';
3
3
  export type { CommandCall, FetchCall, FileCall, ToolCall } from '../utils/call-effects.js';
4
4
  export type { Target } from './permissions/match-target.js';
5
5
  export type Rule<State extends object = Record<never, never>> = RuleFor<Mod<State>>;
6
6
  export type PermissionRules<State extends object = Record<never, never>> = RulesFor<Mod<State>>;
7
- export declare function permissions<State extends object = Record<never, never>>(rules: PermissionRules<State>): Part<void, State>;
7
+ export declare function permissions<State extends object = Record<never, never>>(rules: PermissionRules<State>): Job<void, State>;
8
8
  //# sourceMappingURL=permissions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/jobs/permissions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAG1C,OAAO,EAAqC,KAAK,eAAe,IAAI,QAAQ,EAAE,KAAK,IAAI,IAAI,OAAO,EAAgB,MAAM,oCAAoC,CAAA;AAK5J,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAC1F,YAAY,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAC3D,MAAM,MAAM,IAAI,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;AACnF,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;AAI/F,wBAAgB,WAAW,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAwBzH"}
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/jobs/permissions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAGzC,OAAO,EAAqC,KAAK,eAAe,IAAI,QAAQ,EAAE,KAAK,IAAI,IAAI,OAAO,EAAgB,MAAM,oCAAoC,CAAA;AAK5J,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAC1F,YAAY,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAC3D,MAAM,MAAM,IAAI,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;AACnF,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;AAI/F,wBAAgB,WAAW,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAwBxH"}
@@ -1,7 +1,7 @@
1
1
  import { decidePermission, stricterVerdict } from './permissions/decide-permission.js';
2
2
  import { targetOf } from './permissions/match-target.js';
3
3
  import { messageOf } from '../utils/text.js';
4
- import { modOf, workspaceReader } from './part-context.js';
4
+ import { modOf, workspaceReader } from './context.js';
5
5
  const deadline = { ms: 2000, job: 'permissions' };
6
6
  export function permissions(rules) {
7
7
  const count = (rules.deny?.length ?? 0) + (rules.ask?.length ?? 0);
@@ -9,22 +9,22 @@ export function permissions(rules) {
9
9
  throw new Error('permissions: give it a deny or an ask rule, or remove it from setup.');
10
10
  for (const rule of [...(rules.deny ?? []), ...(rules.ask ?? [])])
11
11
  targetOf(rule);
12
- return (context) => {
13
- const readWorkspace = workspaceReader(context);
12
+ return (job) => {
13
+ const readWorkspace = workspaceReader(job);
14
14
  const verdictOf = async (e) => {
15
15
  try {
16
- const [agent, workspace] = await Promise.all([context.toolCalls.agentOf(e.tool_use_id), readWorkspace()]);
16
+ const [agent, workspace] = await Promise.all([job.toolCalls.agentOf(e.tool_use_id), readWorkspace()]);
17
17
  const use = { tool: e.tool, input: e.input, ...agent };
18
- return await decidePermission(rules, use, workspace, (call, folder) => modOf(context, { call, folder }, workspace, deadline));
18
+ return await decidePermission(rules, use, workspace, (call, folder) => modOf(job, { call, folder }, workspace, deadline));
19
19
  }
20
20
  catch (error) {
21
21
  return { decision: 'deny', reason: `The permissions job could not read the session, so it denies the call: ${messageOf(error)}` };
22
22
  }
23
23
  };
24
- context.on('tool.check', async (e, next) => {
24
+ job.on('tool.check', async (e, next) => {
25
25
  const [below, ours] = await Promise.all([next(e), verdictOf(e)]);
26
26
  return ours === undefined ? below : stricterVerdict(below, ours);
27
27
  });
28
- context.announce(`${count} permission rule${count === 1 ? '' : 's'}`);
28
+ job.announce(`${count} permission rule${count === 1 ? '' : 's'}`);
29
29
  };
30
30
  }
package/jobs/program.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Part } from '../mod.js';
1
+ import type { Job } from '../mod.js';
2
2
  export type Program = {
3
3
  readonly state: 'stopped' | 'starting' | 'running' | 'backoff' | 'fatal';
4
4
  ready(): Promise<{
@@ -9,5 +9,5 @@ export type Program = {
9
9
  export declare function program(options: {
10
10
  readonly command: readonly string[];
11
11
  readonly environment?: Record<string, string>;
12
- }): Part<Program>;
12
+ }): Job<Program>;
13
13
  //# sourceMappingURL=program.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/jobs/program.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGrC,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;IACxE,KAAK,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACvD,CAAA;AAMD,wBAAgB,OAAO,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAyEtI"}
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/jobs/program.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAGpC,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;IACxE,KAAK,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACvD,CAAA;AAMD,wBAAgB,OAAO,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAAC,CAyErI"}
package/jobs/prompt.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Mod, Part } from '../mod.js';
1
+ import type { Job, Mod } from '../mod.js';
2
2
  import { type ToolCall } from '../utils/call-effects.js';
3
3
  import { type Target } from './permissions/match-target.js';
4
4
  type PromptInput = {
@@ -11,6 +11,6 @@ type PromptOptions<State extends object> = {
11
11
  when?: RegExp | ((userPrompt: string) => boolean);
12
12
  after?: Target | Target[];
13
13
  };
14
- export declare function prompt<State extends object = Record<never, never>>({ name, prompt: text, when, after }: PromptOptions<State>): Part<void, State>;
14
+ export declare function prompt<State extends object = Record<never, never>>({ name, prompt: text, when, after }: PromptOptions<State>): Job<void, State>;
15
15
  export {};
16
16
  //# sourceMappingURL=prompt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/jobs/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAe,MAAM,WAAW,CAAA;AAGvD,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAGlF,KAAK,WAAW,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE3D,KAAK,aAAa,CAAC,KAAK,SAAS,MAAM,IAAI;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IAC5G,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,CAAA;IACjD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1B,CAAA;AAID,wBAAgB,MAAM,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAoChJ"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/jobs/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAc,GAAG,EAAE,MAAM,WAAW,CAAA;AAGrD,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAGlF,KAAK,WAAW,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE3D,KAAK,aAAa,CAAC,KAAK,SAAS,MAAM,IAAI;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IAC5G,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,CAAA;IACjD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1B,CAAA;AAID,wBAAgB,MAAM,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAoC/I"}
package/jobs/prompt.js CHANGED
@@ -2,7 +2,7 @@ import { longestMs } from '../runtime/deadline.js';
2
2
  import { listed, messageOf } from '../utils/text.js';
3
3
  import { callEffects } from '../utils/call-effects.js';
4
4
  import { matchTarget, targetOf } from './permissions/match-target.js';
5
- import { afterCall, modOf, modWithin, targetWords } from './part-context.js';
5
+ import { afterCall, modOf, modWithin, targetWords } from './context.js';
6
6
  const deadline = { ms: 5000, longestMs, job: 'prompt' };
7
7
  export function prompt({ name, prompt: text, when, after }) {
8
8
  if (name.trim() === '')
@@ -12,9 +12,9 @@ export function prompt({ name, prompt: text, when, after }) {
12
12
  const targets = after === undefined ? [] : Array.isArray(after) ? after : [after];
13
13
  for (const target of targets)
14
14
  targetOf(target);
15
- return (part) => {
16
- part.reserveName('prompt', name, `prompt: ${part.mod.name} adds the name "${name}" two times. Give each prompt its own name.`);
17
- const log = (reason) => part.claude.ui.log(`prompt "${name}" added nothing: ${reason}`, { to: 'debug' });
15
+ return (job) => {
16
+ job.reserveName('prompt', name, `prompt: ${job.mod.name} adds the name "${name}" two times. Give each prompt its own name.`);
17
+ const log = (reason) => job.claude.ui.log(`prompt "${name}" added nothing: ${reason}`, { to: 'debug' });
18
18
  const textFor = async (input, mod) => {
19
19
  try {
20
20
  const value = typeof text === 'string' ? text : await text(input, mod);
@@ -30,21 +30,21 @@ export function prompt({ name, prompt: text, when, after }) {
30
30
  return value === undefined ? undefined : `# ${name}\n${value}`;
31
31
  };
32
32
  if (when !== undefined) {
33
- addAfterUserPrompts(part, when, (userPrompt) => headedText({ userPrompt }, modWithin(part, deadline)), log);
34
- part.announce(`the ${name} prompt after matching user prompts`);
33
+ addAfterUserPrompts(job, when, (userPrompt) => headedText({ userPrompt }, modWithin(job, deadline)), log);
34
+ job.announce(`the ${name} prompt after matching user prompts`);
35
35
  }
36
36
  else if (targets.length > 0) {
37
- addAfterCalls(part, targets, headedText, log);
38
- part.announce(`the ${name} prompt after ${listed(targets.map(targetWords))}`);
37
+ addAfterCalls(job, targets, headedText, log);
38
+ job.announce(`the ${name} prompt after ${listed(targets.map(targetWords))}`);
39
39
  }
40
40
  else {
41
- addOncePerConversation(part, name, () => textFor({}, modWithin(part, deadline)), log);
42
- part.announce(`the ${name} prompt`);
41
+ addOncePerConversation(job, name, () => textFor({}, modWithin(job, deadline)), log);
42
+ job.announce(`the ${name} prompt`);
43
43
  }
44
44
  };
45
45
  }
46
- function addOncePerConversation(part, name, textFor, log) {
47
- part.on('prompt.context', async (e, next) => {
46
+ function addOncePerConversation(job, name, textFor, log) {
47
+ job.on('prompt.context', async (e, next) => {
48
48
  const below = await next(e);
49
49
  if (below.blocks.some((block) => block.name === name)) {
50
50
  log(`a block named "${name}" is already in the context`);
@@ -54,8 +54,8 @@ function addOncePerConversation(part, name, textFor, log) {
54
54
  return value === undefined ? below : { ...below, blocks: [...below.blocks, { name, text: value }] };
55
55
  });
56
56
  }
57
- function addAfterUserPrompts(part, when, textFor, log) {
58
- part.on('prompt.submit', async (e, next) => {
57
+ function addAfterUserPrompts(job, when, textFor, log) {
58
+ job.on('prompt.submit', async (e, next) => {
59
59
  let value;
60
60
  try {
61
61
  if (typeof when === 'function' ? when(e.text) : e.text.search(when) >= 0)
@@ -67,14 +67,14 @@ function addAfterUserPrompts(part, when, textFor, log) {
67
67
  return next(value === undefined ? e : { ...e, context: [...(e.context ?? []), value] });
68
68
  });
69
69
  }
70
- function addAfterCalls(part, targets, textFor, log) {
71
- afterCall(part, async (use, workspace) => {
70
+ function addAfterCalls(job, targets, textFor, log) {
71
+ afterCall(job, async (use, workspace) => {
72
72
  const effects = callEffects(use, workspace);
73
73
  for (const target of targets) {
74
74
  const [matched] = await matchTarget(target, use, effects, workspace);
75
75
  if (matched === undefined)
76
76
  continue;
77
- const value = await textFor({ call: matched.call }, modOf(part, matched, workspace, deadline));
77
+ const value = await textFor({ call: matched.call }, modOf(job, matched, workspace, deadline));
78
78
  return value === undefined ? [] : [value];
79
79
  }
80
80
  return [];
@@ -1,4 +1,4 @@
1
- import type { Mod, Part } from '../mod.js';
1
+ import type { Job, Mod } from '../mod.js';
2
2
  export type Reply = string | {
3
3
  text?: string;
4
4
  context?: string;
@@ -12,5 +12,5 @@ export declare function slashCommand<State extends object = Record<never, never>
12
12
  args: string;
13
13
  positionals: string[];
14
14
  }, mod: Mod<State>) => Reply | void | Promise<Reply | void>;
15
- }): Part<void, State>;
15
+ }): Job<void, State>;
16
16
  //# sourceMappingURL=slash-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slash-command.d.ts","sourceRoot":"","sources":["../src/jobs/slash-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAM1C,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAA;AAM5E,wBAAgB,YAAY,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAA;CAC1H,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CA4BpB"}
1
+ {"version":3,"file":"slash-command.d.ts","sourceRoot":"","sources":["../src/jobs/slash-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAMzC,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAA;AAM5E,wBAAgB,YAAY,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAA;CAC1H,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CA4BnB"}
@@ -1,13 +1,13 @@
1
1
  import { parse } from '../vendor.js';
2
2
  import { longestMs } from '../runtime/deadline.js';
3
3
  import { messageOf } from '../utils/text.js';
4
- import { modWithin } from './part-context.js';
4
+ import { modWithin } from './context.js';
5
5
  const deadline = { ms: 30000, longestMs, job: 'slashCommand' };
6
6
  const commandName = /^[A-Za-z0-9_-]{1,64}$/;
7
7
  export function slashCommand(options) {
8
8
  const { name, description, argumentHint, immediate, reply } = options;
9
- return (part) => {
10
- const { mod, claude, on, announce, reserveName } = part;
9
+ return (job) => {
10
+ const { mod, claude, announce, reserveName } = job;
11
11
  if (!commandName.test(name))
12
12
  throw new Error(`${mod.name}: "${name}" is not a slash command name. Use 1 to 64 letters, digits, "_", or "-", without the slash.`);
13
13
  reserveName('slashCommand', name, `${mod.name}: the slash command /${name} is already added. Give each slashCommand its own name.`);
@@ -18,8 +18,8 @@ export function slashCommand(options) {
18
18
  claude.ui.log(`${mod.name}: /${name} is not added: ${oneLine(error)}`);
19
19
  });
20
20
  announce(`/${name}`);
21
- const replyMod = modWithin(part, deadline);
22
- on('command.run', async (e, next) => {
21
+ const replyMod = modWithin(job, deadline);
22
+ job.on('command.run', async (e, next) => {
23
23
  if (e.command !== registered)
24
24
  return next(e);
25
25
  try {
@@ -1,4 +1,4 @@
1
- import type { Mod, Part } from '../mod.js';
1
+ import type { Job, Mod } from '../mod.js';
2
2
  export type Usage = {
3
3
  model: string;
4
4
  context: {
@@ -13,5 +13,5 @@ export type Usage = {
13
13
  export declare function statusLine<State extends object = Record<never, never>>(options: {
14
14
  readonly text: (usage: Usage, mod: Mod<State>) => string | undefined | Promise<string | undefined>;
15
15
  readonly interval?: number;
16
- }): Part<void, State>;
16
+ }): Job<void, State>;
17
17
  //# sourceMappingURL=status-line.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-line.d.ts","sourceRoot":"","sources":["../src/jobs/status-line.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAK1C,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACvB,CAAA;AAID,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IAC/E,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAClG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAyCpB"}
1
+ {"version":3,"file":"status-line.d.ts","sourceRoot":"","sources":["../src/jobs/status-line.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAKzC,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACvB,CAAA;AAID,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE;IAC/E,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAClG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAyCnB"}
@@ -1,14 +1,14 @@
1
1
  import { messageOf } from '../utils/text.js';
2
- import { modWithin } from './part-context.js';
2
+ import { modWithin } from './context.js';
3
3
  const deadline = { ms: 2000, job: 'statusLine' };
4
4
  export function statusLine(options) {
5
5
  const { text, interval = 10000 } = options;
6
- return (part) => {
7
- const { mod, claude, on, announce, reserveName } = part;
6
+ return (job) => {
7
+ const { mod, claude, announce, reserveName } = job;
8
8
  if (!(interval >= 1))
9
9
  throw new Error(`${mod.name}: the status line interval is ${interval}. Give it in milliseconds, 1 or more.`);
10
10
  reserveName('statusLine', '', `${mod.name}: a status line is already added. A mod has one status line: join the texts in one statusLine.`);
11
- const textMod = modWithin(part, deadline);
11
+ const textMod = modWithin(job, deadline);
12
12
  let shown;
13
13
  let queue = Promise.resolve();
14
14
  const update = async () => {
@@ -33,7 +33,7 @@ export function statusLine(options) {
33
33
  queue = queue.then(update);
34
34
  };
35
35
  announce('a status line');
36
- on('session.measure', (e, next) => {
36
+ job.on('session.measure', (e, next) => {
37
37
  refresh();
38
38
  return next(e);
39
39
  });