@cmodjs/core 0.3.0 → 1.5.0
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/docs/commands.md +61 -10
- package/docs/dependencies.md +16 -14
- package/docs/hooks.md +64 -29
- package/docs/index.md +29 -25
- package/docs/install-steps.md +13 -9
- package/docs/jobs.md +59 -111
- package/docs/mod.md +227 -175
- package/docs/options.md +2 -2
- package/docs/permissions.md +27 -16
- package/docs/session.md +311 -0
- package/docs/state.md +11 -7
- package/docs/testing.md +68 -23
- package/docs/ui.md +116 -76
- package/jobs/check.d.ts.map +1 -1
- package/jobs/check.js +5 -2
- package/jobs/context.d.ts +7 -8
- package/jobs/context.d.ts.map +1 -1
- package/jobs/context.js +23 -73
- package/jobs/permissions/decide-permission.d.ts +5 -3
- package/jobs/permissions/decide-permission.d.ts.map +1 -1
- package/jobs/permissions/decide-permission.js +6 -4
- package/jobs/permissions/find-project-scope.d.ts +1 -1
- package/jobs/permissions/find-project-scope.d.ts.map +1 -1
- package/jobs/permissions/find-project-scope.js +8 -11
- package/jobs/permissions/match-target.d.ts +2 -2
- package/jobs/permissions/match-target.d.ts.map +1 -1
- package/jobs/permissions.d.ts +1 -1
- package/jobs/permissions.d.ts.map +1 -1
- package/jobs/permissions.js +6 -4
- package/jobs/program.d.ts.map +1 -1
- package/jobs/program.js +14 -4
- package/jobs/prompt.d.ts +4 -2
- package/jobs/prompt.d.ts.map +1 -1
- package/jobs/prompt.js +16 -15
- package/jobs/schedule.d.ts +2 -2
- package/jobs/schedule.d.ts.map +1 -1
- package/jobs/schedule.js +9 -9
- package/jobs/slash-command.d.ts +4 -4
- package/jobs/slash-command.d.ts.map +1 -1
- package/jobs/slash-command.js +14 -9
- package/jobs/status-line.d.ts +1 -11
- package/jobs/status-line.d.ts.map +1 -1
- package/jobs/status-line.js +8 -12
- package/jobs/tool.d.ts +2 -2
- package/jobs/tool.d.ts.map +1 -1
- package/jobs/tool.js +15 -9
- package/mod.d.ts +178 -75
- package/mod.d.ts.map +1 -1
- package/mod.js +127 -3
- package/options.d.ts +2 -2
- package/options.js +19 -19
- package/package.json +3 -3
- package/records.d.ts +13 -8
- package/records.d.ts.map +1 -1
- package/records.js +33 -17
- package/register.d.ts.map +1 -1
- package/register.js +34 -5
- package/runtime/announce.d.ts +18 -0
- package/runtime/announce.d.ts.map +1 -0
- package/runtime/announce.js +68 -0
- package/runtime/before.d.ts +32 -0
- package/runtime/before.d.ts.map +1 -0
- package/runtime/before.js +214 -0
- package/runtime/bound.d.ts +4 -0
- package/runtime/bound.d.ts.map +1 -0
- package/runtime/bound.js +9 -0
- package/runtime/claude.d.ts +4 -2
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/conversations.d.ts +17 -0
- package/runtime/conversations.d.ts.map +1 -0
- package/runtime/conversations.js +563 -0
- package/runtime/deadline.d.ts +0 -1
- package/runtime/deadline.d.ts.map +1 -1
- package/runtime/deadline.js +1 -1
- package/runtime/dependencies.d.ts +2 -0
- package/runtime/dependencies.d.ts.map +1 -1
- package/runtime/dependencies.js +10 -1
- package/runtime/engine.d.ts +13 -0
- package/runtime/engine.d.ts.map +1 -0
- package/runtime/engine.js +10 -0
- package/runtime/grants.d.ts +4 -0
- package/runtime/grants.d.ts.map +1 -1
- package/runtime/grants.js +68 -31
- package/runtime/hooks.d.ts +5 -4
- package/runtime/hooks.d.ts.map +1 -1
- package/runtime/hooks.js +29 -9
- package/runtime/installer.d.ts +1 -1
- package/runtime/installer.d.ts.map +1 -1
- package/runtime/installer.js +17 -14
- package/runtime/lifecycle.d.ts +3 -1
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +414 -212
- package/runtime/metadata.d.ts +3 -1
- package/runtime/metadata.d.ts.map +1 -1
- package/runtime/metadata.js +25 -14
- package/runtime/options.d.ts +3 -1
- package/runtime/options.d.ts.map +1 -1
- package/runtime/options.js +4 -4
- package/runtime/programs.d.ts +8 -0
- package/runtime/programs.d.ts.map +1 -1
- package/runtime/programs.js +39 -1
- package/runtime/router.d.ts +2 -1
- package/runtime/router.d.ts.map +1 -1
- package/runtime/router.js +11 -3
- package/runtime/sessions.d.ts +58 -0
- package/runtime/sessions.d.ts.map +1 -0
- package/runtime/sessions.js +433 -0
- package/runtime/state.d.ts +6 -2
- package/runtime/state.d.ts.map +1 -1
- package/runtime/state.js +46 -13
- package/runtime/toaster.d.ts +24 -0
- package/runtime/toaster.d.ts.map +1 -0
- package/runtime/toaster.js +286 -0
- package/runtime/ui.d.ts +6 -17
- package/runtime/ui.d.ts.map +1 -1
- package/runtime/ui.js +62 -118
- package/session/context/context.d.ts +12 -0
- package/session/context/context.d.ts.map +1 -0
- package/session/context/context.js +2 -0
- package/session/context/turn/message/document.d.ts +7 -0
- package/session/context/turn/message/document.d.ts.map +1 -0
- package/session/context/turn/message/document.js +1 -0
- package/session/context/turn/message/message.d.ts +55 -0
- package/session/context/turn/message/message.d.ts.map +1 -0
- package/session/context/turn/message/message.js +178 -0
- package/session/context/turn/message/note.d.ts +8 -0
- package/session/context/turn/message/note.d.ts.map +1 -0
- package/session/context/turn/message/note.js +1 -0
- package/session/context/turn/message/notice.d.ts +6 -0
- package/session/context/turn/message/notice.d.ts.map +1 -0
- package/session/context/turn/message/notice.js +1 -0
- package/session/context/turn/message/prompt.d.ts +8 -0
- package/session/context/turn/message/prompt.d.ts.map +1 -0
- package/session/context/turn/message/prompt.js +1 -0
- package/session/context/turn/message/reply.d.ts +6 -0
- package/session/context/turn/message/reply.d.ts.map +1 -0
- package/session/context/turn/message/reply.js +1 -0
- package/session/context/turn/message/sender.d.ts +14 -0
- package/session/context/turn/message/sender.d.ts.map +1 -0
- package/session/context/turn/message/sender.js +30 -0
- package/session/context/turn/message/skill.d.ts +7 -0
- package/session/context/turn/message/skill.d.ts.map +1 -0
- package/session/context/turn/message/skill.js +1 -0
- package/session/context/turn/message/tool-call.d.ts +9 -0
- package/session/context/turn/message/tool-call.d.ts.map +1 -0
- package/session/context/turn/message/tool-call.js +1 -0
- package/session/context/turn/message/tool-result.d.ts +8 -0
- package/session/context/turn/message/tool-result.d.ts.map +1 -0
- package/session/context/turn/message/tool-result.js +1 -0
- package/session/context/turn/turn.d.ts +13 -0
- package/session/context/turn/turn.d.ts.map +1 -0
- package/session/context/turn/turn.js +2 -0
- package/session/conversation.d.ts +73 -0
- package/session/conversation.d.ts.map +1 -0
- package/session/conversation.js +146 -0
- package/session/goal/goal.d.ts +11 -0
- package/session/goal/goal.d.ts.map +1 -0
- package/session/goal/goal.js +1 -0
- package/session/goal/task.d.ts +16 -0
- package/session/goal/task.d.ts.map +1 -0
- package/session/goal/task.js +3 -0
- package/session/session.d.ts +158 -0
- package/session/session.d.ts.map +1 -0
- package/session/session.js +2 -0
- package/src/jobs/check.ts +7 -4
- package/src/jobs/context.ts +24 -82
- package/src/jobs/permissions/decide-permission.ts +10 -8
- package/src/jobs/permissions/find-project-scope.ts +8 -14
- package/src/jobs/permissions/match-target.ts +3 -3
- package/src/jobs/permissions.ts +8 -6
- package/src/jobs/program.ts +13 -4
- package/src/jobs/prompt.ts +21 -24
- package/src/jobs/schedule.ts +14 -14
- package/src/jobs/slash-command.ts +20 -14
- package/src/jobs/status-line.ts +9 -21
- package/src/jobs/tool.ts +17 -11
- package/src/mod.ts +252 -97
- package/src/options.ts +22 -22
- package/src/records.ts +40 -23
- package/src/register.ts +34 -5
- package/src/runtime/announce.ts +76 -0
- package/src/runtime/before.ts +200 -0
- package/src/runtime/bound.ts +12 -0
- package/src/runtime/claude.ts +7 -2
- package/src/runtime/conversations.ts +579 -0
- package/src/runtime/deadline.ts +2 -2
- package/src/runtime/dependencies.ts +13 -1
- package/src/runtime/engine.ts +23 -0
- package/src/runtime/grants.ts +69 -29
- package/src/runtime/hooks.ts +39 -14
- package/src/runtime/installer.ts +16 -14
- package/src/runtime/lifecycle.ts +413 -201
- package/src/runtime/metadata.ts +37 -14
- package/src/runtime/options.ts +19 -4
- package/src/runtime/programs.ts +40 -1
- package/src/runtime/router.ts +11 -4
- package/src/runtime/sessions.ts +447 -0
- package/src/runtime/state.ts +50 -14
- package/src/runtime/toaster.ts +334 -0
- package/src/runtime/ui.ts +65 -143
- package/src/session/context/context.ts +14 -0
- package/src/session/context/turn/message/document.ts +8 -0
- package/src/session/context/turn/message/message.ts +203 -0
- package/src/session/context/turn/message/note.ts +9 -0
- package/src/session/context/turn/message/notice.ts +7 -0
- package/src/session/context/turn/message/prompt.ts +9 -0
- package/src/session/context/turn/message/reply.ts +7 -0
- package/src/session/context/turn/message/sender.ts +38 -0
- package/src/session/context/turn/message/skill.ts +8 -0
- package/src/session/context/turn/message/tool-call.ts +10 -0
- package/src/session/context/turn/message/tool-result.ts +9 -0
- package/src/session/context/turn/turn.ts +15 -0
- package/src/session/conversation.ts +194 -0
- package/src/session/goal/goal.ts +10 -0
- package/src/session/goal/task.ts +19 -0
- package/src/session/session.ts +141 -0
- package/src/testing/fake-claude.ts +25 -17
- package/src/testing/fake-elements.ts +3 -2
- package/src/testing/fake-files.ts +1 -1
- package/src/testing/fake-sessions.ts +277 -0
- package/src/testing.ts +138 -35
- package/src/ui/components.ts +3 -3
- package/src/ui/elements.ts +22 -8
- package/src/ui/markdown.ts +22 -26
- package/src/ui/places.ts +49 -0
- package/src/utils/call-effects.ts +5 -5
- package/src/utils/changelog.ts +32 -0
- package/src/utils/disposable.ts +3 -0
- package/src/utils/matcher.ts +37 -0
- package/src/utils/metadata.ts +17 -15
- package/src/utils/parse-shell.ts +9 -8
- package/src/utils/paths.ts +21 -4
- package/src/utils/text.ts +4 -0
- package/testing/fake-claude.d.ts +5 -1
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +21 -12
- package/testing/fake-elements.js +4 -2
- package/testing/fake-files.js +1 -1
- package/testing/fake-sessions.d.ts +81 -0
- package/testing/fake-sessions.d.ts.map +1 -0
- package/testing/fake-sessions.js +249 -0
- package/testing.d.ts +34 -13
- package/testing.d.ts.map +1 -1
- package/testing.js +115 -23
- package/ui/components.d.ts +2 -3
- package/ui/components.d.ts.map +1 -1
- package/ui/components.js +3 -3
- package/ui/elements.d.ts.map +1 -1
- package/ui/elements.js +19 -9
- package/ui/markdown.d.ts +35 -33
- package/ui/markdown.d.ts.map +1 -1
- package/ui/markdown.js +14 -16
- package/ui/places.d.ts +43 -0
- package/ui/places.d.ts.map +1 -0
- package/ui/places.js +31 -0
- package/utils/call-effects.d.ts +2 -1
- package/utils/call-effects.d.ts.map +1 -1
- package/utils/call-effects.js +3 -3
- package/utils/changelog.d.ts +9 -0
- package/utils/changelog.d.ts.map +1 -0
- package/utils/changelog.js +29 -0
- package/utils/disposable.d.ts +4 -0
- package/utils/disposable.d.ts.map +1 -0
- package/utils/disposable.js +1 -0
- package/utils/matcher.d.ts +13 -0
- package/utils/matcher.d.ts.map +1 -0
- package/utils/matcher.js +32 -0
- package/utils/metadata.d.ts +3 -3
- package/utils/metadata.js +18 -14
- package/utils/parse-shell.js +9 -7
- package/utils/paths.d.ts +4 -1
- package/utils/paths.d.ts.map +1 -1
- package/utils/paths.js +19 -4
- package/utils/text.d.ts +1 -0
- package/utils/text.d.ts.map +1 -1
- package/utils/text.js +3 -0
- package/src/ui/slots.ts +0 -36
- package/ui/slots.d.ts +0 -208
- package/ui/slots.d.ts.map +0 -1
- package/ui/slots.js +0 -19
package/src/mod.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
AgentSpawnArgs,
|
|
3
|
-
AgentSpawnResult,
|
|
4
2
|
AskOptions,
|
|
5
3
|
ClassicHookInputs,
|
|
6
4
|
CmodDependencies,
|
|
7
|
-
|
|
8
|
-
FsStat,
|
|
5
|
+
ConfigRow,
|
|
9
6
|
FsStatOptions,
|
|
10
7
|
HookStream,
|
|
11
8
|
HttpInit,
|
|
@@ -21,26 +18,44 @@ import type {
|
|
|
21
18
|
ProcessSpawnRequest,
|
|
22
19
|
ProcessSpawnResult,
|
|
23
20
|
RenderElement,
|
|
24
|
-
|
|
25
|
-
Timer,
|
|
26
|
-
ToastOptions,
|
|
21
|
+
Settings,
|
|
27
22
|
UiScrollArgs,
|
|
28
23
|
UiScrollResult,
|
|
29
24
|
} from 'claude-code'
|
|
30
25
|
import type { Step } from './installer.js'
|
|
31
26
|
import { checkOptions, type Option, type Options, type OptionValues } from './options.js'
|
|
32
|
-
import
|
|
33
|
-
import
|
|
34
|
-
import type {
|
|
35
|
-
import type { RoutedHook } from './runtime/router.js'
|
|
36
|
-
import type { ToolCalls } from './runtime/tool-calls.js'
|
|
27
|
+
import { bound } from './runtime/bound.js'
|
|
28
|
+
import { Mod as modSender } from './session/context/turn/message/sender.js'
|
|
29
|
+
import type { Sessions } from './session/session.js'
|
|
37
30
|
import type { Pane } from './ui/define-pane.js'
|
|
38
|
-
import type {
|
|
31
|
+
import type { Place, PlaceProps } from './ui/places.js'
|
|
32
|
+
import type { Disposable } from './utils/disposable.js'
|
|
33
|
+
import type { Matcher } from './utils/matcher.js'
|
|
39
34
|
|
|
40
|
-
export type
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
export type { Disposable }
|
|
36
|
+
|
|
37
|
+
export type ToastId = string | number
|
|
38
|
+
|
|
39
|
+
export type ToastType = 'default' | 'success' | 'info' | 'warning' | 'error' | 'loading'
|
|
40
|
+
|
|
41
|
+
export type ToastOptions = {
|
|
42
|
+
readonly id?: ToastId
|
|
43
|
+
readonly description?: string | RenderElement
|
|
44
|
+
readonly action?: { readonly label: string; readonly onClick: () => unknown }
|
|
45
|
+
readonly duration?: number
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type ToastMessage<Value> = string | ((value: Value) => string)
|
|
49
|
+
|
|
50
|
+
export type Toast = {
|
|
51
|
+
(message: string, options?: ToastOptions): ToastId
|
|
52
|
+
success(message: string, options?: ToastOptions): ToastId
|
|
53
|
+
info(message: string, options?: ToastOptions): ToastId
|
|
54
|
+
warning(message: string, options?: ToastOptions): ToastId
|
|
55
|
+
error(message: string, options?: ToastOptions): ToastId
|
|
56
|
+
loading(message: string, options?: ToastOptions): ToastId
|
|
57
|
+
promise<T>(task: Promise<T> | (() => Promise<T>), messages: { readonly loading: string; readonly success: ToastMessage<T>; readonly error: ToastMessage<unknown> }): { unwrap(): Promise<T> }
|
|
58
|
+
dismiss(id?: ToastId): void
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
export type PaneHandle = {
|
|
@@ -48,32 +63,81 @@ export type PaneHandle = {
|
|
|
48
63
|
close(): Promise<void>
|
|
49
64
|
toggle(options?: Readonly<Pick<PaneOpenArgs, 'focus'>>): Promise<void>
|
|
50
65
|
readonly isOpen: boolean
|
|
66
|
+
readonly isShown: boolean
|
|
67
|
+
readonly isFocused: boolean
|
|
51
68
|
}
|
|
52
69
|
|
|
53
|
-
export
|
|
54
|
-
export
|
|
55
|
-
export
|
|
56
|
-
export
|
|
70
|
+
export const SessionStart = 'SessionStart'
|
|
71
|
+
export const SessionEnd = 'SessionEnd'
|
|
72
|
+
export const UserPromptSubmit = 'UserPromptSubmit'
|
|
73
|
+
export const InstructionsLoaded = 'InstructionsLoaded'
|
|
74
|
+
export const PreToolUse = 'PreToolUse'
|
|
75
|
+
export const PermissionRequest = 'PermissionRequest'
|
|
76
|
+
export const PermissionDenied = 'PermissionDenied'
|
|
77
|
+
export const PostToolUse = 'PostToolUse'
|
|
78
|
+
export const PostToolUseFailure = 'PostToolUseFailure'
|
|
79
|
+
export const PostToolBatch = 'PostToolBatch'
|
|
80
|
+
export const SubagentStart = 'SubagentStart'
|
|
81
|
+
export const SubagentStop = 'SubagentStop'
|
|
82
|
+
export const Notification = 'Notification'
|
|
83
|
+
export const PreCompact = 'PreCompact'
|
|
84
|
+
export const Stop = 'Stop'
|
|
85
|
+
export const StopFailure = 'StopFailure'
|
|
86
|
+
export const CwdChanged = 'CwdChanged'
|
|
87
|
+
export const FileChanged = 'FileChanged'
|
|
88
|
+
export const UserPromptExpansion = 'UserPromptExpansion'
|
|
89
|
+
export const Setup = 'Setup'
|
|
90
|
+
export const ConfigChange = 'ConfigChange'
|
|
91
|
+
export const DirectoryAdded = 'DirectoryAdded'
|
|
92
|
+
export const PreModelSwitch = 'PreModelSwitch'
|
|
93
|
+
export const PostModelSwitch = 'PostModelSwitch'
|
|
94
|
+
export const PostCompact = 'PostCompact'
|
|
95
|
+
export const MessageDisplay = 'MessageDisplay'
|
|
96
|
+
export const TodoCreated = 'TaskCreated'
|
|
97
|
+
export const TodoCompleted = 'TaskCompleted'
|
|
98
|
+
export const TeammateIdle = 'TeammateIdle'
|
|
99
|
+
export const Elicitation = 'Elicitation'
|
|
100
|
+
export const ElicitationResult = 'ElicitationResult'
|
|
101
|
+
export const WorktreeCreate = 'WorktreeCreate'
|
|
102
|
+
export const WorktreeRemove = 'WorktreeRemove'
|
|
103
|
+
|
|
104
|
+
export const hooks = [
|
|
105
|
+
Setup,
|
|
106
|
+
SessionStart,
|
|
107
|
+
SessionEnd,
|
|
108
|
+
UserPromptSubmit,
|
|
109
|
+
UserPromptExpansion,
|
|
110
|
+
InstructionsLoaded,
|
|
111
|
+
ConfigChange,
|
|
112
|
+
DirectoryAdded,
|
|
113
|
+
PreModelSwitch,
|
|
114
|
+
PostModelSwitch,
|
|
115
|
+
PreToolUse,
|
|
116
|
+
PermissionRequest,
|
|
117
|
+
PermissionDenied,
|
|
118
|
+
PostToolUse,
|
|
119
|
+
PostToolUseFailure,
|
|
120
|
+
PostToolBatch,
|
|
121
|
+
MessageDisplay,
|
|
122
|
+
SubagentStart,
|
|
123
|
+
SubagentStop,
|
|
124
|
+
TodoCreated,
|
|
125
|
+
TodoCompleted,
|
|
126
|
+
TeammateIdle,
|
|
127
|
+
Elicitation,
|
|
128
|
+
ElicitationResult,
|
|
129
|
+
Notification,
|
|
130
|
+
PreCompact,
|
|
131
|
+
PostCompact,
|
|
132
|
+
Stop,
|
|
133
|
+
StopFailure,
|
|
134
|
+
CwdChanged,
|
|
135
|
+
FileChanged,
|
|
136
|
+
WorktreeCreate,
|
|
137
|
+
WorktreeRemove,
|
|
138
|
+
] as const
|
|
57
139
|
|
|
58
|
-
export type
|
|
59
|
-
| 'SessionStart'
|
|
60
|
-
| 'SessionEnd'
|
|
61
|
-
| 'UserPromptSubmit'
|
|
62
|
-
| 'InstructionsLoaded'
|
|
63
|
-
| 'PreToolUse'
|
|
64
|
-
| 'PermissionRequest'
|
|
65
|
-
| 'PermissionDenied'
|
|
66
|
-
| 'PostToolUse'
|
|
67
|
-
| 'PostToolUseFailure'
|
|
68
|
-
| 'PostToolBatch'
|
|
69
|
-
| 'SubagentStart'
|
|
70
|
-
| 'SubagentStop'
|
|
71
|
-
| 'Notification'
|
|
72
|
-
| 'PreCompact'
|
|
73
|
-
| 'Stop'
|
|
74
|
-
| 'StopFailure'
|
|
75
|
-
| 'CwdChanged'
|
|
76
|
-
| 'FileChanged'
|
|
140
|
+
export type Hook = (typeof hooks)[number]
|
|
77
141
|
|
|
78
142
|
export type HookAnswer = {
|
|
79
143
|
continue?: boolean
|
|
@@ -83,7 +147,7 @@ export type HookAnswer = {
|
|
|
83
147
|
decision?: 'block'
|
|
84
148
|
reason?: string
|
|
85
149
|
hookSpecificOutput?: {
|
|
86
|
-
hookEventName?:
|
|
150
|
+
hookEventName?: Hook
|
|
87
151
|
additionalContext?: string
|
|
88
152
|
permissionDecision?: 'allow' | 'deny' | 'ask'
|
|
89
153
|
permissionDecisionReason?: string
|
|
@@ -97,6 +161,8 @@ export type HookAnswer = {
|
|
|
97
161
|
updatedToolOutput?: unknown
|
|
98
162
|
updatedMCPToolOutput?: unknown
|
|
99
163
|
retry?: boolean
|
|
164
|
+
displayContent?: string
|
|
165
|
+
worktreePath?: string
|
|
100
166
|
}
|
|
101
167
|
}
|
|
102
168
|
|
|
@@ -119,20 +185,14 @@ type HookInputs = Omit<ClassicHookInputs, 'PreToolUse' | 'PostToolUse' | 'PostTo
|
|
|
119
185
|
CwdChanged: Omit<ClassicHookInputs['CwdChanged'], 'transcript_path'>
|
|
120
186
|
}
|
|
121
187
|
|
|
122
|
-
export type HookInput<
|
|
188
|
+
export type HookInput<H extends Hook> = HookInputs[H]
|
|
123
189
|
|
|
124
|
-
export type
|
|
190
|
+
export type HookListener<H extends Hook> = (input: HookInput<H>) => HookAnswer | void | Promise<HookAnswer | void>
|
|
125
191
|
|
|
126
192
|
export type HookOptions = {
|
|
127
193
|
readonly timeoutMs?: number
|
|
128
194
|
}
|
|
129
195
|
|
|
130
|
-
export type ScrollArgs = Omit<UiScrollArgs, 'to'> & { readonly to: Exclude<UiScrollArgs['to'], { requestId: string }> }
|
|
131
|
-
|
|
132
|
-
export type ModClaude = Claude & {
|
|
133
|
-
on<N extends RoutedEvent>(event: N, hook: RoutedHook<N>): void
|
|
134
|
-
}
|
|
135
|
-
|
|
136
196
|
export type Metadata = Readonly<Record<string, string>>
|
|
137
197
|
|
|
138
198
|
export type FileMatch = {
|
|
@@ -142,71 +202,145 @@ export type FileMatch = {
|
|
|
142
202
|
readonly error?: string
|
|
143
203
|
}
|
|
144
204
|
|
|
145
|
-
type
|
|
146
|
-
|
|
147
|
-
|
|
205
|
+
export type Entry = {
|
|
206
|
+
readonly name: string
|
|
207
|
+
readonly isFile: boolean
|
|
208
|
+
readonly isFolder: boolean
|
|
209
|
+
readonly isLink: boolean
|
|
210
|
+
readonly size: number
|
|
211
|
+
readonly modifiedAt: number
|
|
148
212
|
}
|
|
149
213
|
|
|
150
|
-
export type
|
|
151
|
-
readonly
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
readonly
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
214
|
+
export type Stat = Omit<Entry, 'name'> & {
|
|
215
|
+
readonly realPath?: string
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export type Allowed = {
|
|
219
|
+
allows(value: string): boolean
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type Permissions = {
|
|
223
|
+
readonly conversation: boolean
|
|
224
|
+
readonly prompt: boolean
|
|
225
|
+
readonly model: boolean
|
|
226
|
+
readonly tasks: boolean
|
|
227
|
+
readonly tools: boolean
|
|
228
|
+
readonly approve: boolean
|
|
229
|
+
readonly network: Allowed
|
|
230
|
+
readonly run: Allowed
|
|
231
|
+
readonly files: Allowed
|
|
232
|
+
readonly config: Allowed
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export type SettingsFile = {
|
|
236
|
+
read(): Promise<Settings>
|
|
237
|
+
update(values: Readonly<Record<string, unknown>>): Promise<void>
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export type Setting = Pick<ConfigRow, 'key' | 'label' | 'kind' | 'value' | 'isLocked'> & {
|
|
241
|
+
readonly description?: string
|
|
242
|
+
readonly options?: readonly string[]
|
|
243
|
+
readonly plugin?: string
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export type Imports = {
|
|
247
|
+
readonly sessions: Sessions
|
|
248
|
+
readonly settings: { list(): Promise<Setting[]>; readonly user: SettingsFile; readonly project: SettingsFile; readonly local: SettingsFile }
|
|
249
|
+
readonly model: { complete(request: ModelCompleteRequest, options?: ModelCompleteOptions): Promise<ModelCompleteResult> }
|
|
170
250
|
readonly fs: {
|
|
171
251
|
read(path: string): Promise<string>
|
|
172
252
|
write(path: string, text: string): Promise<void>
|
|
173
|
-
list(path?: string): Promise<FsEntry[]>
|
|
174
253
|
exists(path: string): Promise<boolean>
|
|
175
|
-
stat(path: string, options?: FsStatOptions): Promise<FsStat>
|
|
176
254
|
find(glob: string | readonly string[]): Promise<readonly FileMatch[]>
|
|
255
|
+
list(path?: string): Promise<Entry[]>
|
|
256
|
+
stat(path: string, options?: FsStatOptions): Promise<Stat>
|
|
177
257
|
}
|
|
178
258
|
readonly metadata: {
|
|
179
259
|
read(path: string): Promise<Metadata>
|
|
180
260
|
update(path: string, change: (metadata: Record<string, string>) => void): Promise<void>
|
|
181
261
|
}
|
|
182
|
-
readonly
|
|
183
|
-
|
|
262
|
+
readonly process: {
|
|
263
|
+
run(argv: readonly string[], init?: ProcessRunInit): Promise<ProcessRunResult>
|
|
264
|
+
spawn(argv: readonly string[], init?: Omit<ProcessSpawnRequest, 'argv'>): HookStream<ProcessSpawnChunk, ProcessSpawnResult>
|
|
265
|
+
}
|
|
266
|
+
readonly http: { fetch(url: string, init?: HttpInit): Promise<HttpResponse> }
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export const sessions: Imports['sessions'] = {
|
|
270
|
+
get current() {
|
|
271
|
+
return bound().sessions.current
|
|
272
|
+
},
|
|
273
|
+
list: (options) => bound().sessions.list(options),
|
|
274
|
+
search: (text, options) => bound().sessions.search(text, options),
|
|
275
|
+
on: ((...args: Parameters<Imports['sessions']['on']>) => bound().sessions.on(...args)) as Imports['sessions']['on'],
|
|
276
|
+
before: ((...args: Parameters<Imports['sessions']['before']>) => bound().sessions.before(...args)) as Imports['sessions']['before'],
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export const settings: Imports['settings'] = {
|
|
280
|
+
list: () => bound().settings.list(),
|
|
281
|
+
user: { read: () => bound().settings.user.read(), update: (values) => bound().settings.user.update(values) },
|
|
282
|
+
project: { read: () => bound().settings.project.read(), update: (values) => bound().settings.project.update(values) },
|
|
283
|
+
local: { read: () => bound().settings.local.read(), update: (values) => bound().settings.local.update(values) },
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export const model: Imports['model'] = {
|
|
287
|
+
complete: (request, options) => bound().model.complete(request, options),
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export const fs: Imports['fs'] = {
|
|
291
|
+
read: (path) => bound().fs.read(path),
|
|
292
|
+
write: (path, text) => bound().fs.write(path, text),
|
|
293
|
+
exists: (path) => bound().fs.exists(path),
|
|
294
|
+
find: (glob) => bound().fs.find(glob),
|
|
295
|
+
list: (path) => bound().fs.list(path),
|
|
296
|
+
stat: (path, options) => bound().fs.stat(path, options),
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export const metadata: Imports['metadata'] = {
|
|
300
|
+
read: (path) => bound().metadata.read(path),
|
|
301
|
+
update: (path, change) => bound().metadata.update(path, change),
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export const process: Imports['process'] = {
|
|
305
|
+
run: (argv, init) => bound().process.run(argv, init),
|
|
306
|
+
spawn: (argv, init) => bound().process.spawn(argv, init),
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export const http: Imports['http'] = {
|
|
310
|
+
fetch: (url, init) => bound().http.fetch(url, init),
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export type Mod<State extends object = Record<never, never>, Declared extends Options = Options> = {
|
|
314
|
+
readonly name: string
|
|
315
|
+
readonly folder: string
|
|
316
|
+
readonly dataFolder: string
|
|
317
|
+
readonly state: Readonly<State>
|
|
318
|
+
readonly options: OptionValues<Declared>
|
|
319
|
+
readonly permissions: Permissions
|
|
320
|
+
on<H extends Hook>(hook: H, listener: HookListener<H>, options?: HookOptions): Disposable
|
|
321
|
+
on<H extends Hook>(hook: H, matcher: Matcher<HookInput<H>>, listener: HookListener<H>, options?: HookOptions): Disposable
|
|
322
|
+
every(ms: number, listener: () => unknown): Disposable
|
|
323
|
+
after(ms: number, listener: () => unknown): Disposable
|
|
324
|
+
use<Handle>(job: Job<Handle, State>): Handle
|
|
325
|
+
log(text: string): void
|
|
326
|
+
readonly ui: {
|
|
327
|
+
pane(pane: Pane<State>): PaneHandle
|
|
328
|
+
render<P extends Place>(place: P, Component: (props: PlaceProps<P>) => RenderElement): Disposable
|
|
329
|
+
readonly toast: Toast
|
|
330
|
+
ask(question: string, options?: readonly string[] | AskOptions): Promise<string>
|
|
331
|
+
copy(text: string): Promise<void>
|
|
332
|
+
scroll(args: UiScrollArgs): Promise<UiScrollResult>
|
|
333
|
+
notice(callId: string, text: string | undefined): void
|
|
184
334
|
}
|
|
185
335
|
readonly settings: {
|
|
186
336
|
page(page: Pane<State>): void
|
|
187
337
|
open(pageId?: string): Promise<void>
|
|
188
338
|
}
|
|
189
|
-
readonly session: {
|
|
190
|
-
messages: SessionMessages
|
|
191
|
-
append(text: string): Promise<void>
|
|
192
|
-
submit(text: string): Promise<void>
|
|
193
|
-
}
|
|
194
|
-
readonly agent: {
|
|
195
|
-
spawn(args: AgentSpawnArgs): Promise<AgentSpawnResult>
|
|
196
|
-
}
|
|
197
|
-
readonly model: {
|
|
198
|
-
complete(request: ModelCompleteRequest, options?: ModelCompleteOptions): Promise<ModelCompleteResult>
|
|
199
|
-
}
|
|
200
|
-
readonly permissions: {
|
|
201
|
-
has(name: ListPermission, value: string): boolean
|
|
202
|
-
has(name: FlagPermission): boolean
|
|
203
|
-
}
|
|
204
|
-
readonly projectRoot: string
|
|
205
|
-
readonly cwd: string
|
|
206
339
|
readonly dependencies: CmodDependencies
|
|
207
|
-
readonly claude: ModClaude
|
|
208
340
|
}
|
|
209
341
|
|
|
342
|
+
export const Mod = modSender
|
|
343
|
+
|
|
210
344
|
type StateGroups = {
|
|
211
345
|
readonly memory?: object
|
|
212
346
|
readonly session?: object
|
|
@@ -224,14 +358,13 @@ export type ModDefinition<State extends StateGroups = Record<never, never>, Name
|
|
|
224
358
|
readonly options?: Declared
|
|
225
359
|
readonly api?: Name extends keyof CmodDependencies ? Api<CmodDependencies[Name], State> : { readonly [method: string]: (input: never, mod: Mod<State>) => unknown }
|
|
226
360
|
readonly installer?: readonly Step<State>[]
|
|
227
|
-
setup(mod: Mod<State, Declared>):
|
|
361
|
+
setup(mod: Mod<State, Declared>): unknown
|
|
228
362
|
}
|
|
229
363
|
|
|
230
364
|
export type JobContext<State extends object = Record<never, never>> = {
|
|
231
365
|
readonly mod: Mod<State>
|
|
232
366
|
announce(feature: string): void
|
|
233
|
-
reserveName(
|
|
234
|
-
readonly toolCalls: ToolCalls
|
|
367
|
+
reserveName(type: string, name: string, taken: string): Disposable
|
|
235
368
|
}
|
|
236
369
|
|
|
237
370
|
export type Job<Handle, State extends object = Record<never, never>> = (context: JobContext<State>) => Handle
|
|
@@ -241,3 +374,25 @@ export function defineMod<State extends StateGroups = Record<never, never>, Name
|
|
|
241
374
|
if (definition.options !== undefined) checkOptions(definition.name, definition.options)
|
|
242
375
|
return definition
|
|
243
376
|
}
|
|
377
|
+
|
|
378
|
+
export type { Matcher } from './utils/matcher.js'
|
|
379
|
+
export type { Place, PlaceProps } from './ui/places.js'
|
|
380
|
+
export { AbovePrompt, AskUserQuestion, CommandOutput, PromptHint, SessionMode, Spinner, ToolGroup, ToolProgress, TurnDuration } from './ui/places.js'
|
|
381
|
+
export { Session, UsageChange, type BeforeAnswer, type BeforeEvent, type BeforeListener, type Client, type Listener, type RecordPart, type Refusal, type SearchOptions, type SessionEvent, type SessionPayload, type SessionScope, type SessionSend, type Sessions, type TaskStartArgs, type ToolCallArgs, type Usage } from './session/session.js'
|
|
382
|
+
export { ContextEnd, ContextStart, type Context } from './session/context/context.js'
|
|
383
|
+
export { TurnEnd, TurnStart, type Turn } from './session/context/turn/turn.js'
|
|
384
|
+
export { Message, type MessageType } from './session/context/turn/message/message.js'
|
|
385
|
+
export { Prompt } from './session/context/turn/message/prompt.js'
|
|
386
|
+
export { Note } from './session/context/turn/message/note.js'
|
|
387
|
+
export { Reply } from './session/context/turn/message/reply.js'
|
|
388
|
+
export { ToolCall } from './session/context/turn/message/tool-call.js'
|
|
389
|
+
export { ToolResult } from './session/context/turn/message/tool-result.js'
|
|
390
|
+
export { Skill } from './session/context/turn/message/skill.js'
|
|
391
|
+
export { Document } from './session/context/turn/message/document.js'
|
|
392
|
+
export { Notice } from './session/context/turn/message/notice.js'
|
|
393
|
+
export { Channel, Person, Schedule, Sdk, type Sender, type SenderType } from './session/context/turn/message/sender.js'
|
|
394
|
+
export { GoalChange, type Goal } from './session/goal/goal.js'
|
|
395
|
+
export { Task, TaskEnd, TaskStart } from './session/goal/task.js'
|
|
396
|
+
export { longestMs } from './runtime/deadline.js'
|
|
397
|
+
export { notInstalled } from './runtime/dependencies.js'
|
|
398
|
+
export { messageOf } from './utils/text.js'
|
package/src/options.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type OptionType = 'text' | 'secret' | 'number' | 'toggle' | 'choice' | 'folder' | 'file' | 'list'
|
|
2
2
|
|
|
3
3
|
export type OptionValue = string | number | boolean | readonly string[]
|
|
4
4
|
|
|
5
5
|
type Described = { readonly title: string; readonly description: string }
|
|
6
6
|
|
|
7
7
|
export type Option<Value extends OptionValue = OptionValue> = Described & {
|
|
8
|
-
readonly
|
|
8
|
+
readonly type: OptionType
|
|
9
9
|
readonly default?: Value
|
|
10
10
|
readonly min?: number
|
|
11
11
|
readonly max?: number
|
|
@@ -27,17 +27,17 @@ export type UserConfigField = Described & {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export const option = {
|
|
30
|
-
text: (field: Described & { readonly default?: string }): Option<string> => ({ ...field,
|
|
31
|
-
secret: (field: Described): Option<string> => ({ ...field,
|
|
32
|
-
number: (field: Described & { readonly default?: number; readonly min?: number; readonly max?: number }): Option<number> => ({ ...field,
|
|
33
|
-
toggle: (field: Described & { readonly default?: boolean }): Option<boolean> => ({ ...field,
|
|
34
|
-
choice: <const Choice extends string>(choices: readonly Choice[], field: Described & { readonly default?: Choice }): Option<Choice> => ({ ...field,
|
|
35
|
-
folder: (field: Described & { readonly default?: string }): Option<string> => ({ ...field,
|
|
36
|
-
file: (field: Described & { readonly default?: string }): Option<string> => ({ ...field,
|
|
37
|
-
list: (field: Described & { readonly default?: readonly string[] }): Option<readonly string[]> => ({ ...field,
|
|
30
|
+
text: (field: Described & { readonly default?: string }): Option<string> => ({ ...field, type: 'text' }),
|
|
31
|
+
secret: (field: Described): Option<string> => ({ ...field, type: 'secret' }),
|
|
32
|
+
number: (field: Described & { readonly default?: number; readonly min?: number; readonly max?: number }): Option<number> => ({ ...field, type: 'number' }),
|
|
33
|
+
toggle: (field: Described & { readonly default?: boolean }): Option<boolean> => ({ ...field, type: 'toggle', default: field.default ?? false }),
|
|
34
|
+
choice: <const Choice extends string>(choices: readonly Choice[], field: Described & { readonly default?: Choice }): Option<Choice> => ({ ...field, type: 'choice', choices }),
|
|
35
|
+
folder: (field: Described & { readonly default?: string }): Option<string> => ({ ...field, type: 'folder' }),
|
|
36
|
+
file: (field: Described & { readonly default?: string }): Option<string> => ({ ...field, type: 'file' }),
|
|
37
|
+
list: (field: Described & { readonly default?: readonly string[] }): Option<readonly string[]> => ({ ...field, type: 'list' }),
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const types: Readonly<Record<
|
|
40
|
+
const types: Readonly<Record<OptionType, UserConfigField['type']>> = { text: 'string', secret: 'string', number: 'number', toggle: 'boolean', choice: 'string', folder: 'directory', file: 'file', list: 'string' }
|
|
41
41
|
|
|
42
42
|
const optionKey = /^[A-Za-z_]\w*$/
|
|
43
43
|
|
|
@@ -46,8 +46,8 @@ export function checkOptions(name: string, options: Options): Options {
|
|
|
46
46
|
const at = `${name}: options.${key}`
|
|
47
47
|
if (!optionKey.test(key)) throw new Error(`${at} is not an option name. Use letters, digits, and _, starting with a letter, as Claude Code passes each option on as CLAUDE_PLUGIN_OPTION_${key.toUpperCase()}.`)
|
|
48
48
|
if (declared.title.trim() === '') throw new Error(`${at} needs a title, the label /config shows.`)
|
|
49
|
-
if (declared.
|
|
50
|
-
if (declared.
|
|
49
|
+
if (declared.type === 'choice' && (declared.choices ?? []).length === 0) throw new Error(`${at} is a choice with no choices. Give option.choice(['a', 'b'], { ... }).`)
|
|
50
|
+
if (declared.type === 'choice' && declared.default !== undefined && !(declared.choices ?? []).includes(declared.default as string)) throw new Error(`${at} defaults to ${String(declared.default)}, which is not one of its choices: ${(declared.choices ?? []).join(', ')}.`)
|
|
51
51
|
}
|
|
52
52
|
return options
|
|
53
53
|
}
|
|
@@ -57,12 +57,12 @@ export function userConfigOf(options: Options): Record<string, UserConfigField>
|
|
|
57
57
|
Object.entries(options).map(([key, declared]) => [
|
|
58
58
|
key,
|
|
59
59
|
{
|
|
60
|
-
type: types[declared.
|
|
60
|
+
type: types[declared.type],
|
|
61
61
|
title: declared.title,
|
|
62
62
|
description: declared.description,
|
|
63
|
-
...(declared.
|
|
64
|
-
...(declared.
|
|
65
|
-
...(declared.
|
|
63
|
+
...(declared.type === 'secret' ? { sensitive: true } : {}),
|
|
64
|
+
...(declared.type === 'list' ? { multiple: true } : {}),
|
|
65
|
+
...(declared.type === 'choice' ? { options: declared.choices } : {}),
|
|
66
66
|
...(declared.default === undefined ? {} : { default: declared.default }),
|
|
67
67
|
...(declared.min === undefined ? {} : { min: declared.min }),
|
|
68
68
|
...(declared.max === undefined ? {} : { max: declared.max }),
|
|
@@ -76,16 +76,16 @@ export function isUnset(value: unknown): boolean {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
export function fitsOption(declared: Option, value: unknown): string | undefined {
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
if (
|
|
79
|
+
const type = declared.type
|
|
80
|
+
if (type === 'toggle') return typeof value === 'boolean' ? undefined : 'takes true or false'
|
|
81
|
+
if (type === 'number') {
|
|
82
82
|
if (typeof value !== 'number' || !Number.isFinite(value)) return 'takes a number'
|
|
83
83
|
if (declared.min !== undefined && value < declared.min) return `takes ${declared.min} or more`
|
|
84
84
|
if (declared.max !== undefined && value > declared.max) return `takes ${declared.max} or less`
|
|
85
85
|
return undefined
|
|
86
86
|
}
|
|
87
|
-
if (
|
|
87
|
+
if (type === 'list') return Array.isArray(value) && value.every((item) => typeof item === 'string') ? undefined : 'takes a list of text'
|
|
88
88
|
if (typeof value !== 'string') return 'takes text'
|
|
89
|
-
if (
|
|
89
|
+
if (type === 'choice' && !(declared.choices ?? []).includes(value)) return `takes one of: ${(declared.choices ?? []).join(', ')}`
|
|
90
90
|
return undefined
|
|
91
91
|
}
|