@cmodjs/core 0.1.6 → 0.1.8

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.
@@ -6,7 +6,7 @@ import { formatExit, listed, messageOf } from '../utils/text.js'
6
6
  import type { Claude } from './claude.js'
7
7
  import { beforeDeadline } from './deadline.js'
8
8
  import { answerCall, dependencyCalls, notInstalled } from './dependencies.js'
9
- import { classicHook, userSkillHook, type RoutedEvent } from './hooks.js'
9
+ import { classicHook, permissionEvents, userSkillHook, type RoutedEvent } from './hooks.js'
10
10
  import { createRouter, type Router, type RouterNext } from './router.js'
11
11
  import { createState } from './state.js'
12
12
  import { toolCalls } from './tool-calls.js'
@@ -36,6 +36,7 @@ type ModRuntime = {
36
36
  readonly router: Router
37
37
  readonly progress: Progress
38
38
  readonly dataFolder: string
39
+ readonly checksPermissions: () => boolean
39
40
  }
40
41
 
41
42
  type ActiveMod<State extends object> = {
@@ -120,7 +121,7 @@ async function cmodVersion(claude: Claude): Promise<string | undefined> {
120
121
  return result.stdout.trim().split(/\s+/).at(-1)
121
122
  }
122
123
 
123
- export function createLifecycle<State extends object>(definition: ModDefinition<State>): Lifecycle<State> {
124
+ export function createLifecycle<State extends object>(definition: ModDefinition<State>, checksPermissions: () => boolean = () => true): Lifecycle<State> {
124
125
  let router: Router = createRouter()
125
126
  let phase: Phase = 'starting'
126
127
  let runtime: Pick<ModRuntime, 'claude' | 'progress'> | undefined
@@ -136,7 +137,7 @@ export function createLifecycle<State extends object>(definition: ModDefinition<
136
137
  const startSettled = new Promise<void>((resolve) => (settleStart = resolve))
137
138
 
138
139
  const claude = () => {
139
- if (runtime === undefined) throw new Error(`${definition.name}: the lifecycle has not started. connect(on, mod) starts it at session.start.`)
140
+ if (runtime === undefined) throw new Error(`${definition.name}: the lifecycle has not started. registerMod(addHook, mod) starts it at session.start.`)
140
141
  return runtime.claude
141
142
  }
142
143
 
@@ -171,7 +172,7 @@ export function createLifecycle<State extends object>(definition: ModDefinition<
171
172
 
172
173
  const record = () => {
173
174
  recording ??= recordThroughCmod()
174
- .catch((error: unknown) => claude().ui.log(`${definition.name} has no CMod record yet: ${messageOf(error)}`, { to: 'debug' }))
175
+ .catch((error: unknown) => claude().ui.log(`${definition.name} has no cmod record yet: ${messageOf(error)}`, { to: 'debug' }))
175
176
  .finally(() => {
176
177
  recording = undefined
177
178
  })
@@ -180,7 +181,7 @@ export function createLifecycle<State extends object>(definition: ModDefinition<
180
181
  const activate = async () => {
181
182
  if (runtime === undefined || plugin === undefined) return
182
183
  const activeRouter = createRouter()
183
- const active = await createMod(definition, { ...runtime, router: activeRouter, dataFolder: dataFolder(plugin.store, plugin.name) }).catch((error: unknown) => {
184
+ const active = await createMod(definition, { ...runtime, router: activeRouter, dataFolder: dataFolder(plugin.store, plugin.name), checksPermissions }).catch((error: unknown) => {
184
185
  fail(messageOf(error), 'Fix it, then run /reload-plugins.')
185
186
  throw error
186
187
  })
@@ -226,7 +227,7 @@ export function createLifecycle<State extends object>(definition: ModDefinition<
226
227
  if (plugin === undefined) return
227
228
  if (plugin.name === cmodPluginName) return bootstrap(plugin.root)
228
229
  phase = 'installing'
229
- if ((await cmodVersion(claude())) === undefined) return waitForCMod()
230
+ if ((await cmodVersion(claude())) === undefined) return waitForcmod()
230
231
  endLine()
231
232
  const progress = showLine()
232
233
  let outcome: RunnerEvent | undefined
@@ -242,9 +243,9 @@ export function createLifecycle<State extends object>(definition: ModDefinition<
242
243
  fail(reason, `Fix the cause, then run: cmod install ${definition.name}`)
243
244
  }
244
245
 
245
- const waitForCMod = () => {
246
+ const waitForcmod = () => {
246
247
  phase = 'waiting'
247
- showLine().wait('Waiting for CMod')
248
+ showLine().wait('Waiting for cmod')
248
249
  let check: Promise<void> | undefined
249
250
  const stop = () => {
250
251
  timer.cancel()
@@ -263,7 +264,7 @@ export function createLifecycle<State extends object>(definition: ModDefinition<
263
264
  report(error)
264
265
  })
265
266
  })
266
- const longWait = claude().clock.after(cmodWaitMs, () => showLine().wait("Still waiting for CMod to download cmod. See CMod's own line."))
267
+ const longWait = claude().clock.after(cmodWaitMs, () => showLine().wait("Still waiting for cmod to download cmod. See cmod's own line."))
267
268
  }
268
269
 
269
270
  const bootstrap = async (root: string) => {
@@ -447,6 +448,10 @@ async function createMod<State extends object>(definition: ModDefinition<State>,
447
448
  }
448
449
  await failsAs('its state did not load', () => modState.load())
449
450
  await failsAs('its setup function threw', () => definition.setup(mod))
451
+ const permissionHooks = permissionEvents.filter((event) => router.has(event))
452
+ if (permissionHooks.length > 0 && !runtime.checksPermissions()) {
453
+ throw new Error(`it decides permissions on ${listed(permissionHooks)}, so hooks/register.ts must call registerPermissionCheck(addHook) after registerMod`)
454
+ }
450
455
  await failsAs('its open panes did not load', () => area.restorePanes())
451
456
  if (hookEvents.length > 0) added.push(`${hookEvents.length === 1 ? 'a hook' : 'hooks'} on ${listed(hookEvents)}`)
452
457
  return { mod, added }
@@ -7,6 +7,7 @@ export type RoutedHook<N extends RoutedEvent> = (e: Frozen<Args<N>>, next: Route
7
7
 
8
8
  export type Router = {
9
9
  add<N extends RoutedEvent>(event: N, hook: RoutedHook<N>): void
10
+ has(event: RoutedEvent): boolean
10
11
  dispatch<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>): Promise<EventResult<N>>
11
12
  }
12
13
 
@@ -21,6 +22,7 @@ export function createRouter(): Router {
21
22
  chain.push(hook as unknown as ErasedHook)
22
23
  hooks.set(event, chain)
23
24
  },
25
+ has: (event) => hooks.has(event),
24
26
  dispatch<N extends RoutedEvent>(event: N, e: Frozen<Args<N>>, next: RouterNext<N>): Promise<EventResult<N>> {
25
27
  const chain = hooks.get(event)
26
28
  const call = async (index: number, current: unknown): Promise<unknown> => {
@@ -34,6 +34,11 @@ export function toolCalls(claude: Claude, router: Router): ToolCalls {
34
34
  return next(e)
35
35
  })
36
36
  router.add('tool.call', async (e, next) => {
37
+ cwds.set(e.tool_use_id, await claude.session.cwd())
38
+ for (const oldest of cwds.keys()) {
39
+ if (cwds.size <= keptCalls) break
40
+ cwds.delete(oldest)
41
+ }
37
42
  if (e.agentId === undefined) return next(e)
38
43
  agentIds.set(e.tool_use_id, e.agentId)
39
44
  try {
@@ -42,14 +47,6 @@ export function toolCalls(claude: Claude, router: Router): ToolCalls {
42
47
  agentIds.delete(e.tool_use_id)
43
48
  }
44
49
  })
45
- router.add('classic.PreToolUse', async (e, next) => {
46
- cwds.set(e.tool_use_id, await claude.session.cwd())
47
- for (const oldest of cwds.keys()) {
48
- if (cwds.size <= keptCalls) break
49
- cwds.delete(oldest)
50
- }
51
- return next(e)
52
- })
53
50
  for (const event of ['classic.PostToolUse', 'classic.PostToolUseFailure'] as const) {
54
51
  router.add(event, async (e, next) => {
55
52
  try {
package/vendor.js CHANGED
@@ -179,9 +179,7 @@ var require_utils = __commonJS((exports) => {
179
179
  const platform = navigator.platform.toLowerCase();
180
180
  return platform === "win32" || platform === "windows";
181
181
  }
182
- if (typeof process !== "undefined" && process.platform) {
183
- return process.platform === "win32";
184
- }
182
+ if (false) {}
185
183
  return false;
186
184
  };
187
185
  exports.removeBackslashes = (str) => {
package/connect.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import type { On } from 'claude-code';
2
- import type { ModDefinition } from './mod.js';
3
- export declare function connect<State extends object>(on: On, definition: ModDefinition<State>): void;
4
- //# sourceMappingURL=connect.d.ts.map
package/connect.d.ts.map DELETED
@@ -1 +0,0 @@
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"}