@cmodjs/core 0.3.0 → 1.0.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 +50 -10
- package/docs/dependencies.md +12 -12
- package/docs/hooks.md +39 -27
- package/docs/index.md +29 -25
- package/docs/install-steps.md +9 -7
- package/docs/jobs.md +59 -111
- package/docs/mod.md +200 -174
- package/docs/options.md +2 -2
- package/docs/permissions.md +27 -16
- package/docs/session.md +248 -0
- package/docs/state.md +11 -7
- package/docs/testing.md +65 -22
- package/docs/ui.md +108 -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 +8 -3
- 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 +154 -75
- package/mod.d.ts.map +1 -1
- package/mod.js +94 -3
- package/options.d.ts +2 -2
- package/options.js +19 -19
- package/package.json +3 -3
- package/records.d.ts +10 -8
- package/records.d.ts.map +1 -1
- package/records.js +28 -17
- package/register.d.ts.map +1 -1
- package/register.js +17 -5
- package/runtime/announce.d.ts +18 -0
- package/runtime/announce.d.ts.map +1 -0
- package/runtime/announce.js +66 -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 +3 -2
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/conversations.d.ts +16 -0
- package/runtime/conversations.d.ts.map +1 -0
- package/runtime/conversations.js +291 -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 +9 -0
- package/runtime/engine.d.ts +17 -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 +63 -26
- package/runtime/hooks.d.ts +5 -4
- package/runtime/hooks.d.ts.map +1 -1
- package/runtime/hooks.js +10 -5
- package/runtime/installer.d.ts.map +1 -1
- package/runtime/installer.js +11 -9
- package/runtime/lifecycle.d.ts +3 -1
- package/runtime/lifecycle.d.ts.map +1 -1
- package/runtime/lifecycle.js +316 -185
- package/runtime/metadata.d.ts +3 -1
- package/runtime/metadata.d.ts.map +1 -1
- package/runtime/metadata.js +21 -11
- 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 +36 -0
- package/runtime/sessions.d.ts.map +1 -0
- package/runtime/sessions.js +235 -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 +31 -0
- package/runtime/toaster.d.ts.map +1 -0
- package/runtime/toaster.js +176 -0
- package/runtime/ui.d.ts +6 -17
- package/runtime/ui.d.ts.map +1 -1
- package/runtime/ui.js +36 -112
- package/session/context/context.d.ts +10 -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 +54 -0
- package/session/context/turn/message/message.d.ts.map +1 -0
- package/session/context/turn/message/message.js +137 -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 +12 -0
- package/session/context/turn/turn.d.ts.map +1 -0
- package/session/context/turn/turn.js +2 -0
- package/session/conversation.d.ts +64 -0
- package/session/conversation.d.ts.map +1 -0
- package/session/conversation.js +123 -0
- package/session/goal/goal.d.ts +10 -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 +99 -0
- package/session/session.d.ts.map +1 -0
- package/session/session.js +1 -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 +7 -3
- 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 +209 -97
- package/src/options.ts +22 -22
- package/src/records.ts +35 -23
- package/src/register.ts +17 -5
- package/src/runtime/announce.ts +74 -0
- package/src/runtime/bound.ts +12 -0
- package/src/runtime/claude.ts +4 -2
- package/src/runtime/conversations.ts +302 -0
- package/src/runtime/deadline.ts +2 -2
- package/src/runtime/dependencies.ts +12 -0
- package/src/runtime/engine.ts +22 -0
- package/src/runtime/grants.ts +66 -24
- package/src/runtime/hooks.ts +19 -10
- package/src/runtime/installer.ts +10 -9
- package/src/runtime/lifecycle.ts +312 -180
- package/src/runtime/metadata.ts +33 -11
- 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 +242 -0
- package/src/runtime/state.ts +50 -14
- package/src/runtime/toaster.ts +218 -0
- package/src/runtime/ui.ts +42 -139
- package/src/session/context/context.ts +12 -0
- package/src/session/context/turn/message/document.ts +8 -0
- package/src/session/context/turn/message/message.ts +165 -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 +14 -0
- package/src/session/conversation.ts +169 -0
- package/src/session/goal/goal.ts +9 -0
- package/src/session/goal/task.ts +19 -0
- package/src/session/session.ts +94 -0
- package/src/testing/fake-claude.ts +22 -16
- package/src/testing/fake-elements.ts +3 -2
- package/src/testing/fake-files.ts +1 -1
- package/src/testing/fake-sessions.ts +203 -0
- package/src/testing.ts +112 -33
- 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 +3 -3
- package/src/utils/changelog.ts +32 -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 +15 -1
- package/src/utils/text.ts +4 -0
- package/testing/fake-claude.d.ts +4 -1
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +18 -11
- package/testing/fake-elements.js +4 -2
- package/testing/fake-files.js +1 -1
- package/testing/fake-sessions.d.ts +74 -0
- package/testing/fake-sessions.d.ts.map +1 -0
- package/testing/fake-sessions.js +170 -0
- package/testing.d.ts +33 -13
- package/testing.d.ts.map +1 -1
- package/testing.js +92 -21
- 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 +1 -1
- package/utils/call-effects.d.ts.map +1 -1
- package/utils/call-effects.js +2 -2
- package/utils/changelog.d.ts +9 -0
- package/utils/changelog.d.ts.map +1 -0
- package/utils/changelog.js +29 -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 +2 -0
- package/utils/paths.d.ts.map +1 -1
- package/utils/paths.js +13 -1
- 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,7 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
AgentSpawnArgs,
|
|
3
|
-
AgentSpawnResult,
|
|
4
2
|
AskOptions,
|
|
5
3
|
ClassicHookInputs,
|
|
6
4
|
CmodDependencies,
|
|
7
|
-
FsEntry,
|
|
8
|
-
FsStat,
|
|
9
5
|
FsStatOptions,
|
|
10
6
|
HookStream,
|
|
11
7
|
HttpInit,
|
|
@@ -21,26 +17,45 @@ import type {
|
|
|
21
17
|
ProcessSpawnRequest,
|
|
22
18
|
ProcessSpawnResult,
|
|
23
19
|
RenderElement,
|
|
24
|
-
|
|
25
|
-
Timer,
|
|
26
|
-
ToastOptions,
|
|
20
|
+
Settings,
|
|
27
21
|
UiScrollArgs,
|
|
28
22
|
UiScrollResult,
|
|
29
23
|
} from 'claude-code'
|
|
30
24
|
import type { Step } from './installer.js'
|
|
31
25
|
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'
|
|
26
|
+
import { bound } from './runtime/bound.js'
|
|
27
|
+
import { Mod as modSender } from './session/context/turn/message/sender.js'
|
|
28
|
+
import type { Sessions } from './session/session.js'
|
|
37
29
|
import type { Pane } from './ui/define-pane.js'
|
|
38
|
-
import type {
|
|
30
|
+
import type { Place, PlaceProps } from './ui/places.js'
|
|
31
|
+
import type { Matcher } from './utils/matcher.js'
|
|
39
32
|
|
|
40
|
-
export type
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
export type Disposable = {
|
|
34
|
+
dispose(): void
|
|
35
|
+
}
|
|
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 = {
|
|
@@ -50,30 +65,47 @@ export type PaneHandle = {
|
|
|
50
65
|
readonly isOpen: boolean
|
|
51
66
|
}
|
|
52
67
|
|
|
53
|
-
export
|
|
54
|
-
export
|
|
55
|
-
export
|
|
56
|
-
export
|
|
68
|
+
export const SessionStart = 'SessionStart'
|
|
69
|
+
export const SessionEnd = 'SessionEnd'
|
|
70
|
+
export const UserPromptSubmit = 'UserPromptSubmit'
|
|
71
|
+
export const InstructionsLoaded = 'InstructionsLoaded'
|
|
72
|
+
export const PreToolUse = 'PreToolUse'
|
|
73
|
+
export const PermissionRequest = 'PermissionRequest'
|
|
74
|
+
export const PermissionDenied = 'PermissionDenied'
|
|
75
|
+
export const PostToolUse = 'PostToolUse'
|
|
76
|
+
export const PostToolUseFailure = 'PostToolUseFailure'
|
|
77
|
+
export const PostToolBatch = 'PostToolBatch'
|
|
78
|
+
export const SubagentStart = 'SubagentStart'
|
|
79
|
+
export const SubagentStop = 'SubagentStop'
|
|
80
|
+
export const Notification = 'Notification'
|
|
81
|
+
export const PreCompact = 'PreCompact'
|
|
82
|
+
export const Stop = 'Stop'
|
|
83
|
+
export const StopFailure = 'StopFailure'
|
|
84
|
+
export const CwdChanged = 'CwdChanged'
|
|
85
|
+
export const FileChanged = 'FileChanged'
|
|
57
86
|
|
|
58
|
-
export
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
export const hooks = [
|
|
88
|
+
SessionStart,
|
|
89
|
+
SessionEnd,
|
|
90
|
+
UserPromptSubmit,
|
|
91
|
+
InstructionsLoaded,
|
|
92
|
+
PreToolUse,
|
|
93
|
+
PermissionRequest,
|
|
94
|
+
PermissionDenied,
|
|
95
|
+
PostToolUse,
|
|
96
|
+
PostToolUseFailure,
|
|
97
|
+
PostToolBatch,
|
|
98
|
+
SubagentStart,
|
|
99
|
+
SubagentStop,
|
|
100
|
+
Notification,
|
|
101
|
+
PreCompact,
|
|
102
|
+
Stop,
|
|
103
|
+
StopFailure,
|
|
104
|
+
CwdChanged,
|
|
105
|
+
FileChanged,
|
|
106
|
+
] as const
|
|
107
|
+
|
|
108
|
+
export type Hook = (typeof hooks)[number]
|
|
77
109
|
|
|
78
110
|
export type HookAnswer = {
|
|
79
111
|
continue?: boolean
|
|
@@ -83,7 +115,7 @@ export type HookAnswer = {
|
|
|
83
115
|
decision?: 'block'
|
|
84
116
|
reason?: string
|
|
85
117
|
hookSpecificOutput?: {
|
|
86
|
-
hookEventName?:
|
|
118
|
+
hookEventName?: Hook
|
|
87
119
|
additionalContext?: string
|
|
88
120
|
permissionDecision?: 'allow' | 'deny' | 'ask'
|
|
89
121
|
permissionDecisionReason?: string
|
|
@@ -119,20 +151,14 @@ type HookInputs = Omit<ClassicHookInputs, 'PreToolUse' | 'PostToolUse' | 'PostTo
|
|
|
119
151
|
CwdChanged: Omit<ClassicHookInputs['CwdChanged'], 'transcript_path'>
|
|
120
152
|
}
|
|
121
153
|
|
|
122
|
-
export type HookInput<
|
|
154
|
+
export type HookInput<H extends Hook> = HookInputs[H]
|
|
123
155
|
|
|
124
|
-
export type
|
|
156
|
+
export type HookListener<H extends Hook> = (input: HookInput<H>) => HookAnswer | void | Promise<HookAnswer | void>
|
|
125
157
|
|
|
126
158
|
export type HookOptions = {
|
|
127
159
|
readonly timeoutMs?: number
|
|
128
160
|
}
|
|
129
161
|
|
|
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
162
|
export type Metadata = Readonly<Record<string, string>>
|
|
137
163
|
|
|
138
164
|
export type FileMatch = {
|
|
@@ -142,71 +168,136 @@ export type FileMatch = {
|
|
|
142
168
|
readonly error?: string
|
|
143
169
|
}
|
|
144
170
|
|
|
145
|
-
type
|
|
146
|
-
|
|
147
|
-
|
|
171
|
+
export type Entry = {
|
|
172
|
+
readonly name: string
|
|
173
|
+
readonly isFile: boolean
|
|
174
|
+
readonly isFolder: boolean
|
|
175
|
+
readonly isLink: boolean
|
|
176
|
+
readonly size: number
|
|
177
|
+
readonly modifiedAt: number
|
|
148
178
|
}
|
|
149
179
|
|
|
150
|
-
export type
|
|
151
|
-
readonly
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
readonly
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
180
|
+
export type Stat = Omit<Entry, 'name'> & {
|
|
181
|
+
readonly realPath?: string
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type Allowed = {
|
|
185
|
+
allows(value: string): boolean
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export type Permissions = {
|
|
189
|
+
readonly conversation: boolean
|
|
190
|
+
readonly prompt: boolean
|
|
191
|
+
readonly model: boolean
|
|
192
|
+
readonly tasks: boolean
|
|
193
|
+
readonly tools: boolean
|
|
194
|
+
readonly approve: boolean
|
|
195
|
+
readonly network: Allowed
|
|
196
|
+
readonly run: Allowed
|
|
197
|
+
readonly files: Allowed
|
|
198
|
+
readonly config: Allowed
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type SettingsFile = {
|
|
202
|
+
read(): Promise<Settings>
|
|
203
|
+
update(values: Readonly<Record<string, unknown>>): Promise<void>
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type Imports = {
|
|
207
|
+
readonly sessions: Sessions
|
|
208
|
+
readonly settings: { readonly user: SettingsFile; readonly project: SettingsFile; readonly local: SettingsFile }
|
|
209
|
+
readonly model: { complete(request: ModelCompleteRequest, options?: ModelCompleteOptions): Promise<ModelCompleteResult> }
|
|
170
210
|
readonly fs: {
|
|
171
211
|
read(path: string): Promise<string>
|
|
172
212
|
write(path: string, text: string): Promise<void>
|
|
173
|
-
list(path?: string): Promise<FsEntry[]>
|
|
174
213
|
exists(path: string): Promise<boolean>
|
|
175
|
-
stat(path: string, options?: FsStatOptions): Promise<FsStat>
|
|
176
214
|
find(glob: string | readonly string[]): Promise<readonly FileMatch[]>
|
|
215
|
+
list(path?: string): Promise<Entry[]>
|
|
216
|
+
stat(path: string, options?: FsStatOptions): Promise<Stat>
|
|
177
217
|
}
|
|
178
218
|
readonly metadata: {
|
|
179
219
|
read(path: string): Promise<Metadata>
|
|
180
220
|
update(path: string, change: (metadata: Record<string, string>) => void): Promise<void>
|
|
181
221
|
}
|
|
182
|
-
readonly
|
|
183
|
-
|
|
222
|
+
readonly process: {
|
|
223
|
+
run(argv: readonly string[], init?: ProcessRunInit): Promise<ProcessRunResult>
|
|
224
|
+
spawn(argv: readonly string[], init?: Omit<ProcessSpawnRequest, 'argv'>): HookStream<ProcessSpawnChunk, ProcessSpawnResult>
|
|
225
|
+
}
|
|
226
|
+
readonly http: { fetch(url: string, init?: HttpInit): Promise<HttpResponse> }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const sessions: Imports['sessions'] = {
|
|
230
|
+
get current() {
|
|
231
|
+
return bound().sessions.current
|
|
232
|
+
},
|
|
233
|
+
list: (options) => bound().sessions.list(options),
|
|
234
|
+
search: (text, options) => bound().sessions.search(text, options),
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export const settings: Imports['settings'] = {
|
|
238
|
+
user: { read: () => bound().settings.user.read(), update: (values) => bound().settings.user.update(values) },
|
|
239
|
+
project: { read: () => bound().settings.project.read(), update: (values) => bound().settings.project.update(values) },
|
|
240
|
+
local: { read: () => bound().settings.local.read(), update: (values) => bound().settings.local.update(values) },
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export const model: Imports['model'] = {
|
|
244
|
+
complete: (request, options) => bound().model.complete(request, options),
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export const fs: Imports['fs'] = {
|
|
248
|
+
read: (path) => bound().fs.read(path),
|
|
249
|
+
write: (path, text) => bound().fs.write(path, text),
|
|
250
|
+
exists: (path) => bound().fs.exists(path),
|
|
251
|
+
find: (glob) => bound().fs.find(glob),
|
|
252
|
+
list: (path) => bound().fs.list(path),
|
|
253
|
+
stat: (path, options) => bound().fs.stat(path, options),
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export const metadata: Imports['metadata'] = {
|
|
257
|
+
read: (path) => bound().metadata.read(path),
|
|
258
|
+
update: (path, change) => bound().metadata.update(path, change),
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const process: Imports['process'] = {
|
|
262
|
+
run: (argv, init) => bound().process.run(argv, init),
|
|
263
|
+
spawn: (argv, init) => bound().process.spawn(argv, init),
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export const http: Imports['http'] = {
|
|
267
|
+
fetch: (url, init) => bound().http.fetch(url, init),
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export type Mod<State extends object = Record<never, never>, Declared extends Options = Options> = {
|
|
271
|
+
readonly name: string
|
|
272
|
+
readonly folder: string
|
|
273
|
+
readonly dataFolder: string
|
|
274
|
+
readonly state: Readonly<State>
|
|
275
|
+
readonly options: OptionValues<Declared>
|
|
276
|
+
readonly permissions: Permissions
|
|
277
|
+
on<H extends Hook>(hook: H, listener: HookListener<H>, options?: HookOptions): Disposable
|
|
278
|
+
on<H extends Hook>(hook: H, matcher: Matcher<HookInput<H>>, listener: HookListener<H>, options?: HookOptions): Disposable
|
|
279
|
+
every(ms: number, listener: () => unknown): Disposable
|
|
280
|
+
after(ms: number, listener: () => unknown): Disposable
|
|
281
|
+
use<Handle>(job: Job<Handle, State>): Handle
|
|
282
|
+
log(text: string): void
|
|
283
|
+
readonly ui: {
|
|
284
|
+
pane(pane: Pane<State>): PaneHandle
|
|
285
|
+
render<P extends Place>(place: P, Component: (props: PlaceProps<P>) => RenderElement): Disposable
|
|
286
|
+
readonly toast: Toast
|
|
287
|
+
ask(question: string, options?: readonly string[] | AskOptions): Promise<string>
|
|
288
|
+
copy(text: string): Promise<void>
|
|
289
|
+
scroll(args: UiScrollArgs): Promise<UiScrollResult>
|
|
290
|
+
notice(callId: string, text: string | undefined): void
|
|
184
291
|
}
|
|
185
292
|
readonly settings: {
|
|
186
293
|
page(page: Pane<State>): void
|
|
187
294
|
open(pageId?: string): Promise<void>
|
|
188
295
|
}
|
|
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
296
|
readonly dependencies: CmodDependencies
|
|
207
|
-
readonly claude: ModClaude
|
|
208
297
|
}
|
|
209
298
|
|
|
299
|
+
export const Mod = modSender
|
|
300
|
+
|
|
210
301
|
type StateGroups = {
|
|
211
302
|
readonly memory?: object
|
|
212
303
|
readonly session?: object
|
|
@@ -224,14 +315,13 @@ export type ModDefinition<State extends StateGroups = Record<never, never>, Name
|
|
|
224
315
|
readonly options?: Declared
|
|
225
316
|
readonly api?: Name extends keyof CmodDependencies ? Api<CmodDependencies[Name], State> : { readonly [method: string]: (input: never, mod: Mod<State>) => unknown }
|
|
226
317
|
readonly installer?: readonly Step<State>[]
|
|
227
|
-
setup(mod: Mod<State, Declared>):
|
|
318
|
+
setup(mod: Mod<State, Declared>): unknown
|
|
228
319
|
}
|
|
229
320
|
|
|
230
321
|
export type JobContext<State extends object = Record<never, never>> = {
|
|
231
322
|
readonly mod: Mod<State>
|
|
232
323
|
announce(feature: string): void
|
|
233
|
-
reserveName(
|
|
234
|
-
readonly toolCalls: ToolCalls
|
|
324
|
+
reserveName(type: string, name: string, taken: string): Disposable
|
|
235
325
|
}
|
|
236
326
|
|
|
237
327
|
export type Job<Handle, State extends object = Record<never, never>> = (context: JobContext<State>) => Handle
|
|
@@ -241,3 +331,25 @@ export function defineMod<State extends StateGroups = Record<never, never>, Name
|
|
|
241
331
|
if (definition.options !== undefined) checkOptions(definition.name, definition.options)
|
|
242
332
|
return definition
|
|
243
333
|
}
|
|
334
|
+
|
|
335
|
+
export type { Matcher } from './utils/matcher.js'
|
|
336
|
+
export type { Place, PlaceProps } from './ui/places.js'
|
|
337
|
+
export { AbovePrompt, AskUserQuestion, CommandOutput, PromptHint, SessionMode, Spinner, ToolGroup, ToolProgress, TurnDuration } from './ui/places.js'
|
|
338
|
+
export { Session, type SessionEvent, type SessionPayload, type SessionScope, type SessionSend, type Sessions, type TaskStartArgs, type Usage } from './session/session.js'
|
|
339
|
+
export { ContextEnd, ContextStart, type Context } from './session/context/context.js'
|
|
340
|
+
export { TurnEnd, TurnStart, type Turn } from './session/context/turn/turn.js'
|
|
341
|
+
export { Message, type MessageType } from './session/context/turn/message/message.js'
|
|
342
|
+
export { Prompt } from './session/context/turn/message/prompt.js'
|
|
343
|
+
export { Note } from './session/context/turn/message/note.js'
|
|
344
|
+
export { Reply } from './session/context/turn/message/reply.js'
|
|
345
|
+
export { ToolCall } from './session/context/turn/message/tool-call.js'
|
|
346
|
+
export { ToolResult } from './session/context/turn/message/tool-result.js'
|
|
347
|
+
export { Skill } from './session/context/turn/message/skill.js'
|
|
348
|
+
export { Document } from './session/context/turn/message/document.js'
|
|
349
|
+
export { Notice } from './session/context/turn/message/notice.js'
|
|
350
|
+
export { Channel, Person, Schedule, Sdk, type Sender, type SenderType } from './session/context/turn/message/sender.js'
|
|
351
|
+
export { GoalChange, type Goal } from './session/goal/goal.js'
|
|
352
|
+
export { Task, TaskEnd, TaskStart } from './session/goal/task.js'
|
|
353
|
+
export { longestMs } from './runtime/deadline.js'
|
|
354
|
+
export { notInstalled } from './runtime/dependencies.js'
|
|
355
|
+
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
|
}
|
package/src/records.ts
CHANGED
|
@@ -19,23 +19,30 @@ export type Steps = {
|
|
|
19
19
|
permissions?: readonly string[]
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export const listPermissions = ['network', 'run', 'files'] as const
|
|
23
|
-
export const flagPermissions = ['conversation', 'prompt', 'model', '
|
|
22
|
+
export const listPermissions = ['network', 'run', 'files', 'config'] as const
|
|
23
|
+
export const flagPermissions = ['conversation', 'prompt', 'model', 'tasks', 'tools', 'approve'] as const
|
|
24
24
|
export type ListPermission = (typeof listPermissions)[number]
|
|
25
25
|
export type FlagPermission = (typeof flagPermissions)[number]
|
|
26
26
|
const permissionNames: readonly string[] = [...listPermissions, ...flagPermissions]
|
|
27
27
|
const hostName = /^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$/
|
|
28
28
|
const programName = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/
|
|
29
|
+
const settingName = /^[A-Za-z][A-Za-z0-9]*$/
|
|
30
|
+
const listItemHint: Readonly<Record<ListPermission, string>> = {
|
|
31
|
+
network: 'a host alone, such as "api.github.com", or a socket path, such as "/var/run/docker.sock"',
|
|
32
|
+
run: 'a program\'s command, such as "gh"',
|
|
33
|
+
files: 'a path that starts with ~/ or /, such as "~/.zshrc"',
|
|
34
|
+
config: 'a Claude Code setting\'s name, such as "cleanupPeriodDays"',
|
|
35
|
+
}
|
|
29
36
|
|
|
30
37
|
export type ReadFile = (path: string) => Promise<string | undefined>
|
|
31
38
|
|
|
32
39
|
export type RunnerEvent =
|
|
33
|
-
| {
|
|
34
|
-
| {
|
|
35
|
-
| {
|
|
36
|
-
| {
|
|
37
|
-
| {
|
|
38
|
-
| {
|
|
40
|
+
| { type: 'progress'; done: number; total: number; label: string }
|
|
41
|
+
| { type: 'log'; text: string }
|
|
42
|
+
| { type: 'needs-consent'; sha256: string; install: string; uninstall: string; keys: string; permissions: readonly string[] }
|
|
43
|
+
| { type: 'done'; name: string; version?: string }
|
|
44
|
+
| { type: 'missing'; name: string }
|
|
45
|
+
| { type: 'failed'; code: number; message: string }
|
|
39
46
|
|
|
40
47
|
export const pluginName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/
|
|
41
48
|
|
|
@@ -153,12 +160,12 @@ function readPermissions(steps: Record<string, unknown>): string[] {
|
|
|
153
160
|
items.push('run:*')
|
|
154
161
|
continue
|
|
155
162
|
}
|
|
156
|
-
const example =
|
|
163
|
+
const example = { network: '["api.github.com"]', run: '["gh"], or "*" for any program', files: '["~/.zshrc"]', config: '["cleanupPeriodDays"]' }[name]
|
|
157
164
|
if (!Array.isArray(value) || value.length === 0 || !value.every((each) => typeof each === 'string')) throw new Error(`${at} sets "${name}" to ${JSON.stringify(value)}. Write a list, such as "${name}": ${example}.`)
|
|
158
|
-
for (const each of value
|
|
165
|
+
for (const each of value) {
|
|
159
166
|
const isPath = /^(~\/|\/)/.test(each) && !each.split('/').includes('..')
|
|
160
|
-
const isValid =
|
|
161
|
-
if (
|
|
167
|
+
const isValid = { network: hostName.test(each) || isPath, run: programName.test(each), files: isPath, config: settingName.test(each) }[name]
|
|
168
|
+
if (isValid !== true) throw new Error(`${at} lists "${each}" under "${name}". Write ${listItemHint[name as ListPermission]}.`)
|
|
162
169
|
items.push(`${name}:${each}`)
|
|
163
170
|
}
|
|
164
171
|
}
|
|
@@ -176,17 +183,17 @@ export function permissionWords(item: string): string {
|
|
|
176
183
|
case 'files':
|
|
177
184
|
return `Change ${target}`
|
|
178
185
|
case 'conversation':
|
|
179
|
-
return 'Read
|
|
186
|
+
return 'Read your Claude Code conversations'
|
|
180
187
|
case 'prompt':
|
|
181
188
|
return 'Add text Claude reads and start turns'
|
|
182
189
|
case 'model':
|
|
183
190
|
return 'Ask a model, which uses your plan'
|
|
184
|
-
case '
|
|
185
|
-
return 'Start
|
|
191
|
+
case 'tasks':
|
|
192
|
+
return 'Start tasks that work beside Claude'
|
|
186
193
|
case 'tools':
|
|
187
194
|
return "Use and change Claude's tool calls"
|
|
188
195
|
case 'config':
|
|
189
|
-
return
|
|
196
|
+
return `Change ${target} in your Claude Code settings`
|
|
190
197
|
case 'approve':
|
|
191
198
|
return "Approve Claude's tool calls for you"
|
|
192
199
|
default:
|
|
@@ -196,6 +203,8 @@ export function permissionWords(item: string): string {
|
|
|
196
203
|
|
|
197
204
|
export const settingsPagesMethod = 'cmod:settingsPages'
|
|
198
205
|
|
|
206
|
+
export const changelogPage = 'changelog'
|
|
207
|
+
|
|
199
208
|
export const openPageMethod = 'cmod:openPage'
|
|
200
209
|
|
|
201
210
|
export const pendingStepsMethod = 'cmod:pendingSteps'
|
|
@@ -240,7 +249,10 @@ function readKeys(keys: unknown): Steps {
|
|
|
240
249
|
return { keys: commands }
|
|
241
250
|
}
|
|
242
251
|
|
|
252
|
+
export const coreVersion = '1.0.0'
|
|
253
|
+
|
|
243
254
|
export function oldestCmodFor(steps: Steps): string {
|
|
255
|
+
if (steps.permissions?.some((item) => item === 'tasks' || item.startsWith('config:')) === true) return '1.0.0'
|
|
244
256
|
if (steps.permissions !== undefined) return '0.2.0'
|
|
245
257
|
return Object.keys(steps.keys ?? {}).length > 0 ? '0.1.12' : '0.0.0'
|
|
246
258
|
}
|
|
@@ -303,7 +315,7 @@ export async function scriptsSha256(steps: Steps, files: { read: ReadFile; list:
|
|
|
303
315
|
}
|
|
304
316
|
|
|
305
317
|
export function formatEvent(event: RunnerEvent): string {
|
|
306
|
-
switch (event.
|
|
318
|
+
switch (event.type) {
|
|
307
319
|
case 'progress':
|
|
308
320
|
return `progress ${event.done} ${event.total}${event.label === '' ? '' : ` ${event.label}`}`
|
|
309
321
|
case 'log':
|
|
@@ -321,19 +333,19 @@ export function formatEvent(event: RunnerEvent): string {
|
|
|
321
333
|
|
|
322
334
|
export function parseEvent(line: string): RunnerEvent {
|
|
323
335
|
const progress = /^progress (\d+) (\d+)(?: (.*))?$/.exec(line)
|
|
324
|
-
if (progress !== null) return {
|
|
336
|
+
if (progress !== null) return { type: 'progress', done: Number(progress[1]), total: Number(progress[2]), label: progress[3] ?? '' }
|
|
325
337
|
const consent = /^needs-consent (\S+)\t([^\t]*)\t([^\t]*)(?:\t(.*))?$/.exec(line)
|
|
326
338
|
if (consent !== null) {
|
|
327
339
|
const [keys = '', ...permissions] = (consent[4] ?? '').split('\t')
|
|
328
|
-
return {
|
|
340
|
+
return { type: 'needs-consent', sha256: consent[1] as string, install: consent[2] as string, uninstall: consent[3] as string, keys, permissions: permissions.filter((item) => item !== '') }
|
|
329
341
|
}
|
|
330
342
|
const done = /^done (\S+)(?: (\S+))?$/.exec(line)
|
|
331
|
-
if (done !== null) return {
|
|
343
|
+
if (done !== null) return { type: 'done', name: done[1] as string, ...(done[2] === undefined ? {} : { version: done[2] }) }
|
|
332
344
|
const missing = /^missing (\S+)$/.exec(line)
|
|
333
|
-
if (missing !== null) return {
|
|
345
|
+
if (missing !== null) return { type: 'missing', name: missing[1] as string }
|
|
334
346
|
const failed = /^failed (-?\d+)(?:\t(.*))?$/.exec(line)
|
|
335
|
-
if (failed !== null) return {
|
|
336
|
-
return {
|
|
347
|
+
if (failed !== null) return { type: 'failed', code: Number(failed[1]), message: failed[2] ?? '' }
|
|
348
|
+
return { type: 'log', text: line.replace(/^log /, '') }
|
|
337
349
|
}
|
|
338
350
|
|
|
339
351
|
export function isAtLeast(version: string, minimum: string): boolean {
|