@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/src/jobs/tool.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import type { FromSchema, JSONSchema } from 'json-schema-to-ts'
2
- import type { Mod, Part } from '../mod.js'
2
+ import type { Job, Mod } from '../mod.js'
3
3
  import { Validator } from '../vendor.js'
4
4
  import { toolDeadline } from '../runtime/deadline.js'
5
5
  import { reservedKeys, toolInputOf } from '../runtime/tool-calls.js'
6
6
  import { messageOf } from '../utils/text.js'
7
- import { modWithin } from './part-context.js'
7
+ import { modWithin } from './context.js'
8
8
 
9
9
  const toolName = /^[A-Za-z0-9_-]{1,64}$/
10
10
 
@@ -13,10 +13,10 @@ export function tool<const Schema extends object = { type: 'object' }, State ext
13
13
  readonly description: string
14
14
  readonly inputSchema?: Schema
15
15
  readonly execute: (input: Schema extends JSONSchema ? FromSchema<Schema> : never, mod: Mod<State>) => unknown
16
- }): Part<{ readonly name: string }, State> {
16
+ }): Job<{ readonly name: string }, State> {
17
17
  const { name, description, inputSchema, execute } = options
18
- return (part) => {
19
- const { mod, claude, on, announce, reserveName } = part
18
+ return (job) => {
19
+ const { mod, claude, announce, reserveName } = job
20
20
  if (!toolName.test(name)) throw new Error(`${mod.name}: "${name}" is not a tool name. Use 1 to 64 letters, digits, "_", or "-".`)
21
21
  const properties = (inputSchema as { properties?: object } | undefined)?.properties ?? {}
22
22
  const reserved = reservedKeys.filter((key) => Object.hasOwn(properties, key))
@@ -35,8 +35,8 @@ export function tool<const Schema extends object = { type: 'object' }, State ext
35
35
  )
36
36
  announce(`the ${name} tool`)
37
37
 
38
- const executeMod = modWithin(part, toolDeadline)
39
- on('tool.call', async (e, next) => {
38
+ const executeMod = modWithin(job, toolDeadline)
39
+ job.on('tool.call', async (e, next) => {
40
40
  if (e.tool !== registered) return next(e)
41
41
  const input = toolInputOf(e)
42
42
  const { valid, errors } = validator.validate(input)
package/src/mod.ts CHANGED
@@ -111,7 +111,7 @@ export type Mod<State extends object = Record<never, never>> = {
111
111
  readonly state: Readonly<State>
112
112
  readonly dataFolder: string
113
113
  on<E extends ModEvent>(event: E, hook: ModHook<E>): void
114
- use<Handle>(part: Part<Handle, State>): Handle
114
+ use<Handle>(job: Job<Handle, State>): Handle
115
115
  readonly ui: {
116
116
  pane(pane: Pane<State>): PaneHandle
117
117
  render<S extends Slot>(slot: S, Component: (props: SlotProps<S>) => RenderElement): void
@@ -157,7 +157,7 @@ export type ModDefinition<State extends StateGroups = Record<never, never>, Name
157
157
  setup(mod: Mod<State>): void | Promise<void>
158
158
  }
159
159
 
160
- export type PartContext<State extends object = Record<never, never>> = {
160
+ export type JobContext<State extends object = Record<never, never>> = {
161
161
  readonly mod: Mod<State>
162
162
  readonly claude: Claude
163
163
  on<N extends RoutedEvent>(event: N, hook: RoutedHook<N>): void
@@ -166,7 +166,7 @@ export type PartContext<State extends object = Record<never, never>> = {
166
166
  readonly toolCalls: ToolCalls
167
167
  }
168
168
 
169
- export type Part<Handle, State extends object = Record<never, never>> = (context: PartContext<State>) => Handle
169
+ export type Job<Handle, State extends object = Record<never, never>> = (context: JobContext<State>) => Handle
170
170
 
171
171
  export function defineMod<State extends StateGroups = Record<never, never>, Name extends string = string>(definition: ModDefinition<State, Name>): ModDefinition<State, Name> {
172
172
  if (definition.name.trim() === '') throw new Error('defineMod: the mod needs a name, such as the name in .claude-plugin/plugin.json.')
@@ -1,5 +1,5 @@
1
1
  import type { Args, EventResult, Frozen, HookBudget, HookStream, ProcessSpawnChunk, ProcessSpawnResult } from 'claude-code'
2
- import type { Mod, ModDefinition, ModEvent, ModHook, PartContext } from '../mod.js'
2
+ import type { Mod, ModDefinition, ModEvent, ModHook } from '../mod.js'
3
3
  import { dataFolder, isAtLeast, parseEvent, readRecord, readSteps, scriptsSha256, storeFolder, type ReadFile, type RunnerEvent } from '../records.js'
4
4
  import { relativePath } from '../utils/paths.js'
5
5
  import { formatExit, listed, messageOf } from '../utils/text.js'
@@ -355,7 +355,6 @@ async function createMod<State extends object>(definition: ModDefinition<State>,
355
355
  const announce = (feature: string) => {
356
356
  added.push(feature)
357
357
  }
358
- const on: PartContext<State>['on'] = (event, hook) => router.add(event, hook)
359
358
  const [session, root, startCwd] = await Promise.all([claude.session.id(), claude.session.root(), claude.session.cwd()])
360
359
  let cwd = startCwd
361
360
  let loadedCwd = startCwd
@@ -370,7 +369,7 @@ async function createMod<State extends object>(definition: ModDefinition<State>,
370
369
  if (!hookEvents.includes(event)) hookEvents.push(event)
371
370
  router.add(`classic.${event}`, classicHook(definition.name, event, hook, claude, agents))
372
371
  },
373
- use: (part) => part({ mod, claude, on, announce, reserveName, toolCalls: agents }),
372
+ use: (job) => job({ mod, claude, on: (event, hook) => router.add(event, hook), announce, reserveName, toolCalls: agents }),
374
373
  ui: area.ui,
375
374
  process: {
376
375
  run: (argv, init) => claude.process.run(argv, init),
@@ -414,32 +413,32 @@ async function createMod<State extends object>(definition: ModDefinition<State>,
414
413
  claude.ui.log(`${definition.name} keeps the state of ${modState.root} until the next prompt or folder move: ${messageOf(error)}`)
415
414
  }
416
415
  }
417
- on('classic.SessionStart', async (e, next) => {
416
+ router.add('classic.SessionStart', async (e, next) => {
418
417
  await modState.switchSession(e.session_id, e.source).catch((error: unknown) => {
419
418
  claude.ui.log(`${definition.name} kept its session values from before the ${e.source}: ${messageOf(error)}`)
420
419
  })
421
420
  return next(e)
422
421
  })
423
- on('classic.UserPromptSubmit', async (e, next) => {
422
+ router.add('classic.UserPromptSubmit', async (e, next) => {
424
423
  staleCwd = undefined
425
424
  await followSession()
426
425
  return next(e)
427
426
  })
428
427
  for (const event of ['classic.PostToolUse', 'classic.PostToolUseFailure'] as const) {
429
- on(event, async (e, next) => {
428
+ router.add(event, async (e, next) => {
430
429
  if (shellTools.includes(e.tool_name)) await followSession()
431
430
  return next(e)
432
431
  })
433
432
  }
434
- on('command.run', async (e, next) => {
433
+ router.add('command.run', async (e, next) => {
435
434
  const answer = await next(e)
436
435
  if (e.command === 'cd') await followSession(true)
437
436
  return answer
438
437
  })
439
- on('skill.prompt', userSkillHook(claude))
438
+ router.add('skill.prompt', userSkillHook(claude))
440
439
  const api = Object.fromEntries(Object.entries(definition.api ?? {}).map(([method, run]) => [method, (input: never) => run(input, mod)]))
441
- on('cmod.call', (e, next) => (e.to === definition.name ? answerCall(definition.name, api, e) : next(e)))
442
- const agents = toolCalls({ claude, on })
440
+ router.add('cmod.call', (e, next) => (e.to === definition.name ? answerCall(definition.name, api, e) : next(e)))
441
+ const agents = toolCalls(claude, router)
443
442
  const names = new Set<string>()
444
443
  const reserveName = (kind: string, name: string, taken: string) => {
445
444
  const key = `${kind}:${name}`
@@ -1,4 +1,5 @@
1
- import type { PartContext } from '../mod.js'
1
+ import type { Claude } from './claude.js'
2
+ import type { Router } from './router.js'
2
3
 
3
4
  export type Agent = { agentId?: string; agentType?: string }
4
5
 
@@ -17,22 +18,22 @@ type AgentFields = { readonly agent_id?: string; readonly agent_type?: string }
17
18
 
18
19
  const keptCalls = 100
19
20
 
20
- export function toolCalls({ claude, on }: Pick<PartContext, 'claude' | 'on'>): ToolCalls {
21
+ export function toolCalls(claude: Claude, router: Router): ToolCalls {
21
22
  let mainAgentType: string | undefined
22
23
  const agentIds = new Map<string, string>()
23
24
  const cwds = new Map<string, string>()
24
25
  const noteAgent = (e: AgentFields) => {
25
26
  if (e.agent_id === undefined) mainAgentType = e.agent_type
26
27
  }
27
- on('classic.SessionStart', (e, next) => {
28
+ router.add('classic.SessionStart', (e, next) => {
28
29
  noteAgent(e)
29
30
  return next(e)
30
31
  })
31
- on('classic.UserPromptSubmit', (e, next) => {
32
+ router.add('classic.UserPromptSubmit', (e, next) => {
32
33
  noteAgent(e)
33
34
  return next(e)
34
35
  })
35
- on('tool.call', async (e, next) => {
36
+ router.add('tool.call', async (e, next) => {
36
37
  if (e.agentId === undefined) return next(e)
37
38
  agentIds.set(e.tool_use_id, e.agentId)
38
39
  try {
@@ -41,7 +42,7 @@ export function toolCalls({ claude, on }: Pick<PartContext, 'claude' | 'on'>): T
41
42
  agentIds.delete(e.tool_use_id)
42
43
  }
43
44
  })
44
- on('classic.PreToolUse', async (e, next) => {
45
+ router.add('classic.PreToolUse', async (e, next) => {
45
46
  cwds.set(e.tool_use_id, await claude.session.cwd())
46
47
  for (const oldest of cwds.keys()) {
47
48
  if (cwds.size <= keptCalls) break
@@ -50,7 +51,7 @@ export function toolCalls({ claude, on }: Pick<PartContext, 'claude' | 'on'>): T
50
51
  return next(e)
51
52
  })
52
53
  for (const event of ['classic.PostToolUse', 'classic.PostToolUseFailure'] as const) {
53
- on(event, async (e, next) => {
54
+ router.add(event, async (e, next) => {
54
55
  try {
55
56
  return await next(e)
56
57
  } finally {
@@ -1,14 +0,0 @@
1
- import type { Mod, PartContext } 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 }: PartContext): () => Promise<Workspace>;
7
- export declare function afterCall<State extends object>(part: PartContext<State>, contextAfter: (use: ToolUse, workspace: Workspace) => Promise<readonly string[]>, failed: (error: unknown) => readonly string[]): void;
8
- export declare function modOf<State extends object>(context: PartContext<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 }: PartContext<State>, deadline: Deadline, workTree?: () => Promise<string | undefined>): Mod<State>;
13
- export declare function targetWords(target: Target): string;
14
- //# sourceMappingURL=part-context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"part-context.d.ts","sourceRoot":"","sources":["../src/jobs/part-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEjD,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,WAAW,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAOjF;AAaD,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAC5C,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,EACxB,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,OAAO,EAAE,WAAW,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,CAEtM;AAED,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAyB,GAAG,GAAG,CAAC,KAAK,CAAC,CAwBxL;AAwBD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CASlD"}