commandmate 0.3.2 → 0.3.3
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/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +13 -13
- package/.next/app-path-routes-manifest.json +1 -1
- package/.next/build-manifest.json +4 -4
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/1.pack +0 -0
- package/.next/cache/webpack/client-production/2.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/required-server-files.json +1 -1
- package/.next/routes-manifest.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/ollama/models/route.js +1 -0
- package/.next/server/app/api/ollama/models/route.js.nft.json +1 -0
- package/.next/server/app/api/ollama/models.body +1 -0
- package/.next/server/app/api/ollama/models.meta +1 -0
- package/.next/server/app/api/repositories/route.js +3 -3
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +4 -4
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +7 -6
- package/.next/server/chunks/2314.js +1 -1
- package/.next/server/chunks/4559.js +1 -1
- package/.next/server/chunks/539.js +10 -10
- package/.next/server/chunks/5853.js +1 -1
- package/.next/server/chunks/6228.js +1 -1
- package/.next/server/chunks/7425.js +59 -39
- package/.next/server/chunks/7566.js +1 -1
- package/.next/server/chunks/8693.js +1 -1
- package/.next/server/chunks/9446.js +1 -0
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/8091-274bc0716106e7fc.js +1 -0
- package/.next/static/chunks/app/page-060057e02b841125.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-78580947c201d698.js +1 -0
- package/.next/static/chunks/{main-db79434ee4a6c931.js → main-2feda12a4d321111.js} +1 -1
- package/.next/static/css/{bd6065b03ddb3efd.css → e85de230ef5ddc40.css} +1 -1
- package/.next/trace +5 -5
- package/.next/types/app/api/ollama/models/route.ts +343 -0
- package/README.md +74 -76
- package/dist/server/src/config/schedule-config.js +7 -1
- package/dist/server/src/lib/auto-yes-manager.js +2 -2
- package/dist/server/src/lib/claude-executor.js +15 -4
- package/dist/server/src/lib/cli-patterns.js +73 -9
- package/dist/server/src/lib/cli-tools/gemini.js +81 -22
- package/dist/server/src/lib/cli-tools/manager.js +4 -2
- package/dist/server/src/lib/cli-tools/types.js +64 -2
- package/dist/server/src/lib/cli-tools/vibe-local.js +163 -0
- package/dist/server/src/lib/cmate-parser.js +25 -3
- package/dist/server/src/lib/db-migrations.js +50 -1
- package/dist/server/src/lib/db.js +51 -1
- package/dist/server/src/lib/prompt-detector.js +4 -3
- package/dist/server/src/lib/response-poller.js +22 -11
- package/dist/server/src/lib/schedule-manager.js +6 -2
- package/dist/server/src/lib/selected-agents-validator.js +99 -0
- package/dist/server/src/types/sidebar.js +9 -4
- package/package.json +1 -1
- package/.next/server/chunks/7536.js +0 -1
- package/.next/static/chunks/8091-925542bdfc843dce.js +0 -1
- package/.next/static/chunks/app/page-238b5a70d8c101e9.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-0c889ab3f30d5af7.js +0 -1
- /package/.next/static/{j8HFvzDZj7tHjAnhpXUno → O7EDFfAYQNe_HRbORxQAC}/_buildManifest.js +0 -0
- /package/.next/static/{j8HFvzDZj7tHjAnhpXUno → O7EDFfAYQNe_HRbORxQAC}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// File: /home/runner/work/CommandMate/CommandMate/src/app/api/ollama/models/route.ts
|
|
2
|
+
import * as entry from '../../../../../../src/app/api/ollama/models/route.js'
|
|
3
|
+
import type { NextRequest } from 'next/server.js'
|
|
4
|
+
|
|
5
|
+
type TEntry = typeof import('../../../../../../src/app/api/ollama/models/route.js')
|
|
6
|
+
|
|
7
|
+
// Check that the entry is a valid entry
|
|
8
|
+
checkFields<Diff<{
|
|
9
|
+
GET?: Function
|
|
10
|
+
HEAD?: Function
|
|
11
|
+
OPTIONS?: Function
|
|
12
|
+
POST?: Function
|
|
13
|
+
PUT?: Function
|
|
14
|
+
DELETE?: Function
|
|
15
|
+
PATCH?: Function
|
|
16
|
+
config?: {}
|
|
17
|
+
generateStaticParams?: Function
|
|
18
|
+
revalidate?: RevalidateRange<TEntry> | false
|
|
19
|
+
dynamic?: 'auto' | 'force-dynamic' | 'error' | 'force-static'
|
|
20
|
+
dynamicParams?: boolean
|
|
21
|
+
fetchCache?: 'auto' | 'force-no-store' | 'only-no-store' | 'default-no-store' | 'default-cache' | 'only-cache' | 'force-cache'
|
|
22
|
+
preferredRegion?: 'auto' | 'global' | 'home' | string | string[]
|
|
23
|
+
runtime?: 'nodejs' | 'experimental-edge' | 'edge'
|
|
24
|
+
maxDuration?: number
|
|
25
|
+
|
|
26
|
+
}, TEntry, ''>>()
|
|
27
|
+
|
|
28
|
+
// Check the prop type of the entry function
|
|
29
|
+
if ('GET' in entry) {
|
|
30
|
+
checkFields<
|
|
31
|
+
Diff<
|
|
32
|
+
ParamCheck<Request | NextRequest>,
|
|
33
|
+
{
|
|
34
|
+
__tag__: 'GET'
|
|
35
|
+
__param_position__: 'first'
|
|
36
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'GET'>>
|
|
37
|
+
},
|
|
38
|
+
'GET'
|
|
39
|
+
>
|
|
40
|
+
>()
|
|
41
|
+
checkFields<
|
|
42
|
+
Diff<
|
|
43
|
+
ParamCheck<PageParams>,
|
|
44
|
+
{
|
|
45
|
+
__tag__: 'GET'
|
|
46
|
+
__param_position__: 'second'
|
|
47
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'GET'>>
|
|
48
|
+
},
|
|
49
|
+
'GET'
|
|
50
|
+
>
|
|
51
|
+
>()
|
|
52
|
+
|
|
53
|
+
checkFields<
|
|
54
|
+
Diff<
|
|
55
|
+
{
|
|
56
|
+
__tag__: 'GET',
|
|
57
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
__tag__: 'GET',
|
|
61
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'GET'>>
|
|
62
|
+
},
|
|
63
|
+
'GET'
|
|
64
|
+
>
|
|
65
|
+
>()
|
|
66
|
+
}
|
|
67
|
+
// Check the prop type of the entry function
|
|
68
|
+
if ('HEAD' in entry) {
|
|
69
|
+
checkFields<
|
|
70
|
+
Diff<
|
|
71
|
+
ParamCheck<Request | NextRequest>,
|
|
72
|
+
{
|
|
73
|
+
__tag__: 'HEAD'
|
|
74
|
+
__param_position__: 'first'
|
|
75
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'HEAD'>>
|
|
76
|
+
},
|
|
77
|
+
'HEAD'
|
|
78
|
+
>
|
|
79
|
+
>()
|
|
80
|
+
checkFields<
|
|
81
|
+
Diff<
|
|
82
|
+
ParamCheck<PageParams>,
|
|
83
|
+
{
|
|
84
|
+
__tag__: 'HEAD'
|
|
85
|
+
__param_position__: 'second'
|
|
86
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'HEAD'>>
|
|
87
|
+
},
|
|
88
|
+
'HEAD'
|
|
89
|
+
>
|
|
90
|
+
>()
|
|
91
|
+
|
|
92
|
+
checkFields<
|
|
93
|
+
Diff<
|
|
94
|
+
{
|
|
95
|
+
__tag__: 'HEAD',
|
|
96
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
__tag__: 'HEAD',
|
|
100
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'HEAD'>>
|
|
101
|
+
},
|
|
102
|
+
'HEAD'
|
|
103
|
+
>
|
|
104
|
+
>()
|
|
105
|
+
}
|
|
106
|
+
// Check the prop type of the entry function
|
|
107
|
+
if ('OPTIONS' in entry) {
|
|
108
|
+
checkFields<
|
|
109
|
+
Diff<
|
|
110
|
+
ParamCheck<Request | NextRequest>,
|
|
111
|
+
{
|
|
112
|
+
__tag__: 'OPTIONS'
|
|
113
|
+
__param_position__: 'first'
|
|
114
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'OPTIONS'>>
|
|
115
|
+
},
|
|
116
|
+
'OPTIONS'
|
|
117
|
+
>
|
|
118
|
+
>()
|
|
119
|
+
checkFields<
|
|
120
|
+
Diff<
|
|
121
|
+
ParamCheck<PageParams>,
|
|
122
|
+
{
|
|
123
|
+
__tag__: 'OPTIONS'
|
|
124
|
+
__param_position__: 'second'
|
|
125
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'OPTIONS'>>
|
|
126
|
+
},
|
|
127
|
+
'OPTIONS'
|
|
128
|
+
>
|
|
129
|
+
>()
|
|
130
|
+
|
|
131
|
+
checkFields<
|
|
132
|
+
Diff<
|
|
133
|
+
{
|
|
134
|
+
__tag__: 'OPTIONS',
|
|
135
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
__tag__: 'OPTIONS',
|
|
139
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'OPTIONS'>>
|
|
140
|
+
},
|
|
141
|
+
'OPTIONS'
|
|
142
|
+
>
|
|
143
|
+
>()
|
|
144
|
+
}
|
|
145
|
+
// Check the prop type of the entry function
|
|
146
|
+
if ('POST' in entry) {
|
|
147
|
+
checkFields<
|
|
148
|
+
Diff<
|
|
149
|
+
ParamCheck<Request | NextRequest>,
|
|
150
|
+
{
|
|
151
|
+
__tag__: 'POST'
|
|
152
|
+
__param_position__: 'first'
|
|
153
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'POST'>>
|
|
154
|
+
},
|
|
155
|
+
'POST'
|
|
156
|
+
>
|
|
157
|
+
>()
|
|
158
|
+
checkFields<
|
|
159
|
+
Diff<
|
|
160
|
+
ParamCheck<PageParams>,
|
|
161
|
+
{
|
|
162
|
+
__tag__: 'POST'
|
|
163
|
+
__param_position__: 'second'
|
|
164
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'POST'>>
|
|
165
|
+
},
|
|
166
|
+
'POST'
|
|
167
|
+
>
|
|
168
|
+
>()
|
|
169
|
+
|
|
170
|
+
checkFields<
|
|
171
|
+
Diff<
|
|
172
|
+
{
|
|
173
|
+
__tag__: 'POST',
|
|
174
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
__tag__: 'POST',
|
|
178
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'POST'>>
|
|
179
|
+
},
|
|
180
|
+
'POST'
|
|
181
|
+
>
|
|
182
|
+
>()
|
|
183
|
+
}
|
|
184
|
+
// Check the prop type of the entry function
|
|
185
|
+
if ('PUT' in entry) {
|
|
186
|
+
checkFields<
|
|
187
|
+
Diff<
|
|
188
|
+
ParamCheck<Request | NextRequest>,
|
|
189
|
+
{
|
|
190
|
+
__tag__: 'PUT'
|
|
191
|
+
__param_position__: 'first'
|
|
192
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'PUT'>>
|
|
193
|
+
},
|
|
194
|
+
'PUT'
|
|
195
|
+
>
|
|
196
|
+
>()
|
|
197
|
+
checkFields<
|
|
198
|
+
Diff<
|
|
199
|
+
ParamCheck<PageParams>,
|
|
200
|
+
{
|
|
201
|
+
__tag__: 'PUT'
|
|
202
|
+
__param_position__: 'second'
|
|
203
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'PUT'>>
|
|
204
|
+
},
|
|
205
|
+
'PUT'
|
|
206
|
+
>
|
|
207
|
+
>()
|
|
208
|
+
|
|
209
|
+
checkFields<
|
|
210
|
+
Diff<
|
|
211
|
+
{
|
|
212
|
+
__tag__: 'PUT',
|
|
213
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
__tag__: 'PUT',
|
|
217
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'PUT'>>
|
|
218
|
+
},
|
|
219
|
+
'PUT'
|
|
220
|
+
>
|
|
221
|
+
>()
|
|
222
|
+
}
|
|
223
|
+
// Check the prop type of the entry function
|
|
224
|
+
if ('DELETE' in entry) {
|
|
225
|
+
checkFields<
|
|
226
|
+
Diff<
|
|
227
|
+
ParamCheck<Request | NextRequest>,
|
|
228
|
+
{
|
|
229
|
+
__tag__: 'DELETE'
|
|
230
|
+
__param_position__: 'first'
|
|
231
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'DELETE'>>
|
|
232
|
+
},
|
|
233
|
+
'DELETE'
|
|
234
|
+
>
|
|
235
|
+
>()
|
|
236
|
+
checkFields<
|
|
237
|
+
Diff<
|
|
238
|
+
ParamCheck<PageParams>,
|
|
239
|
+
{
|
|
240
|
+
__tag__: 'DELETE'
|
|
241
|
+
__param_position__: 'second'
|
|
242
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'DELETE'>>
|
|
243
|
+
},
|
|
244
|
+
'DELETE'
|
|
245
|
+
>
|
|
246
|
+
>()
|
|
247
|
+
|
|
248
|
+
checkFields<
|
|
249
|
+
Diff<
|
|
250
|
+
{
|
|
251
|
+
__tag__: 'DELETE',
|
|
252
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
__tag__: 'DELETE',
|
|
256
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'DELETE'>>
|
|
257
|
+
},
|
|
258
|
+
'DELETE'
|
|
259
|
+
>
|
|
260
|
+
>()
|
|
261
|
+
}
|
|
262
|
+
// Check the prop type of the entry function
|
|
263
|
+
if ('PATCH' in entry) {
|
|
264
|
+
checkFields<
|
|
265
|
+
Diff<
|
|
266
|
+
ParamCheck<Request | NextRequest>,
|
|
267
|
+
{
|
|
268
|
+
__tag__: 'PATCH'
|
|
269
|
+
__param_position__: 'first'
|
|
270
|
+
__param_type__: FirstArg<MaybeField<TEntry, 'PATCH'>>
|
|
271
|
+
},
|
|
272
|
+
'PATCH'
|
|
273
|
+
>
|
|
274
|
+
>()
|
|
275
|
+
checkFields<
|
|
276
|
+
Diff<
|
|
277
|
+
ParamCheck<PageParams>,
|
|
278
|
+
{
|
|
279
|
+
__tag__: 'PATCH'
|
|
280
|
+
__param_position__: 'second'
|
|
281
|
+
__param_type__: SecondArg<MaybeField<TEntry, 'PATCH'>>
|
|
282
|
+
},
|
|
283
|
+
'PATCH'
|
|
284
|
+
>
|
|
285
|
+
>()
|
|
286
|
+
|
|
287
|
+
checkFields<
|
|
288
|
+
Diff<
|
|
289
|
+
{
|
|
290
|
+
__tag__: 'PATCH',
|
|
291
|
+
__return_type__: Response | void | never | Promise<Response | void | never>
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
__tag__: 'PATCH',
|
|
295
|
+
__return_type__: ReturnType<MaybeField<TEntry, 'PATCH'>>
|
|
296
|
+
},
|
|
297
|
+
'PATCH'
|
|
298
|
+
>
|
|
299
|
+
>()
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Check the arguments and return type of the generateStaticParams function
|
|
303
|
+
if ('generateStaticParams' in entry) {
|
|
304
|
+
checkFields<Diff<{ params: PageParams }, FirstArg<MaybeField<TEntry, 'generateStaticParams'>>, 'generateStaticParams'>>()
|
|
305
|
+
checkFields<Diff<{ __tag__: 'generateStaticParams', __return_type__: any[] | Promise<any[]> }, { __tag__: 'generateStaticParams', __return_type__: ReturnType<MaybeField<TEntry, 'generateStaticParams'>> }>>()
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
type PageParams = any
|
|
309
|
+
export interface PageProps {
|
|
310
|
+
params?: any
|
|
311
|
+
searchParams?: any
|
|
312
|
+
}
|
|
313
|
+
export interface LayoutProps {
|
|
314
|
+
children?: React.ReactNode
|
|
315
|
+
|
|
316
|
+
params?: any
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// =============
|
|
320
|
+
// Utility types
|
|
321
|
+
type RevalidateRange<T> = T extends { revalidate: any } ? NonNegative<T['revalidate']> : never
|
|
322
|
+
|
|
323
|
+
// If T is unknown or any, it will be an empty {} type. Otherwise, it will be the same as Omit<T, keyof Base>.
|
|
324
|
+
type OmitWithTag<T, K extends keyof any, _M> = Omit<T, K>
|
|
325
|
+
type Diff<Base, T extends Base, Message extends string = ''> = 0 extends (1 & T) ? {} : OmitWithTag<T, keyof Base, Message>
|
|
326
|
+
|
|
327
|
+
type FirstArg<T extends Function> = T extends (...args: [infer T, any]) => any ? unknown extends T ? any : T : never
|
|
328
|
+
type SecondArg<T extends Function> = T extends (...args: [any, infer T]) => any ? unknown extends T ? any : T : never
|
|
329
|
+
type MaybeField<T, K extends string> = T extends { [k in K]: infer G } ? G extends Function ? G : never : never
|
|
330
|
+
|
|
331
|
+
type ParamCheck<T> = {
|
|
332
|
+
__tag__: string
|
|
333
|
+
__param_position__: string
|
|
334
|
+
__param_type__: T
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function checkFields<_ extends { [k in keyof any]: never }>() {}
|
|
338
|
+
|
|
339
|
+
// https://github.com/sindresorhus/type-fest
|
|
340
|
+
type Numeric = number | bigint
|
|
341
|
+
type Zero = 0 | 0n
|
|
342
|
+
type Negative<T extends Numeric> = T extends Zero ? never : `${T}` extends `-${string}` ? T : never
|
|
343
|
+
type NonNegative<T extends Numeric> = T extends Zero ? T : Negative<T> extends never ? T : '__invalid_negative_number__'
|
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# CommandMate
|
|
2
2
|
|
|
3
|
+
[](https://github.com/Kewton/CommandMate)
|
|
3
4
|

|
|
4
5
|

|
|
5
6
|

|
|
@@ -16,12 +17,17 @@
|
|
|
16
17
|
|
|
17
18
|
Not a "remote control" — a **mobile dev cockpit**.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npx commandmate
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**From install to mobile monitoring in 60 seconds.** macOS / Linux · Node.js v20+ · npm · git · tmux · openssl
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
AI writes code for you — but you're stuck watching a terminal, afraid to walk away.
|
|
29
|
+
Close the lid and every session dies.
|
|
30
|
+
**CommandMate keeps it alive, and puts the controls on your phone.**
|
|
25
31
|
|
|
26
32
|
Of course, it works great on desktop too — the two-column layout gives you a full overview of all sessions and worktrees at a glance.
|
|
27
33
|
|
|
@@ -29,83 +35,69 @@ Of course, it works great on desktop too — the two-column layout gives you a f
|
|
|
29
35
|
<img src="./docs/images/demo-desktop.gif" alt="CommandMate desktop demo" width="600">
|
|
30
36
|
</p>
|
|
31
37
|
|
|
32
|
-
```bash
|
|
33
|
-
npx commandmate
|
|
34
|
-
```
|
|
35
|
-
|
|
36
38
|
---
|
|
37
39
|
|
|
38
|
-
##
|
|
40
|
+
## Key Features
|
|
39
41
|
|
|
40
|
-
|
|
|
41
|
-
|
|
42
|
+
| Feature | What it does | Why it matters |
|
|
43
|
+
|---------|-------------|----------------|
|
|
42
44
|
| **Auto Yes Mode** | Agent runs without stopping for confirmations | No babysitting — Claude Code keeps working while you're away |
|
|
43
45
|
| **Git Worktree Sessions** | One session per worktree, parallel execution | Multiple tasks progress simultaneously |
|
|
44
46
|
| **Mobile Web UI** | Full session control from any browser | Monitor and steer from your phone |
|
|
45
47
|
| **File Viewer** | Browse worktree files from the browser | Review code changes without touching your PC |
|
|
46
48
|
| **Markdown Editor** | Edit Markdown files in the browser | Update AI instructions on the go |
|
|
47
49
|
| **Screenshot Instructions** | Attach images to your prompts | Snap a bug → "Fix this" — the agent sees the screenshot |
|
|
50
|
+
| **Token Authentication** | SHA-256 hashed token + HTTPS + rate limiting | Secure remote access — no credentials leaked, brute-force protected |
|
|
51
|
+
| **Scheduled Execution** | Cron-based auto-run via CMATE.md | Daily reviews, nightly tests — Claude Code works on a schedule |
|
|
48
52
|
|
|
49
53
|
---
|
|
50
54
|
|
|
51
|
-
##
|
|
55
|
+
## Use Cases
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
npm install -g commandmate
|
|
61
|
-
commandmate init
|
|
62
|
-
commandmate start --daemon
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Open http://localhost:3000 in your browser.
|
|
66
|
-
|
|
67
|
-
See the [CLI Setup Guide](./docs/en/user-guide/cli-setup-guide.md) for details.
|
|
57
|
+
| Scenario | How CommandMate helps |
|
|
58
|
+
|----------|----------------------|
|
|
59
|
+
| **Couch coding** | Start a task on your PC, then monitor and steer from the sofa |
|
|
60
|
+
| **Commute review** | Review AI-generated code changes on the train |
|
|
61
|
+
| **Overnight runs** | Let Claude Code work all night — check progress from bed |
|
|
62
|
+
| **Visual bug fix** | Snap a UI bug on your phone, send it with "Fix this" |
|
|
63
|
+
| **Parallel tasks** | Run multiple worktree sessions, manage them all from one dashboard |
|
|
68
64
|
|
|
69
65
|
---
|
|
70
66
|
|
|
71
67
|
## Comparison
|
|
72
68
|
|
|
73
|
-
| Feature | CommandMate | Happy Coder | claude-squad | Omnara |
|
|
74
|
-
|
|
75
|
-
| Auto Yes Mode | Yes | No | Yes (TUI only) | No |
|
|
76
|
-
| Git Worktree Management | Yes | No | Yes (TUI only) | No |
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
69
|
+
| Feature | CommandMate | Remote Control (Official) | Happy Coder | claude-squad | Omnara |
|
|
70
|
+
|---------|:-----------:|:------------------------:|:-----------:|:------------:|:------:|
|
|
71
|
+
| Auto Yes Mode | Yes | No | No | Yes (TUI only) | No |
|
|
72
|
+
| Git Worktree Management | Yes | No | No | Yes (TUI only) | No |
|
|
73
|
+
| Parallel Sessions | Yes | **No (1 only)** | Yes | Yes | No |
|
|
74
|
+
| Mobile Web UI | Yes | Yes (claude.ai) | Yes | **No** | Yes |
|
|
75
|
+
| File Viewer | Yes | No | No | No | No |
|
|
76
|
+
| Markdown Editor | Yes | No | No | No | No |
|
|
77
|
+
| Screenshot Instructions | Yes | No | No | Not possible | No |
|
|
78
|
+
| Scheduled Execution | Yes | No | No | No | No |
|
|
79
|
+
| Survives Laptop Close | Yes (daemon) | **No (terminal must stay open)** | Yes | Yes | Yes |
|
|
80
|
+
| Token Authentication | Yes | N/A (Anthropic account) | N/A (app) | No | N/A (cloud) |
|
|
81
|
+
| Free / OSS | Yes | Requires Pro/Max | Free + Paid | Yes | $20/mo |
|
|
82
|
+
| Runs 100% Locally | Yes | Via Anthropic API | Server-routed | Yes | Cloud fallback |
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
|
|
86
|
-
##
|
|
86
|
+
## Screenshots
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
1. Start tasks on your PC
|
|
90
|
-
$ commandmate start --daemon
|
|
91
|
-
→ Claude Code begins working with Auto Yes
|
|
88
|
+
### Desktop
|
|
92
89
|
|
|
93
|
-
|
|
90
|
+

|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
→ Web UI shows all sessions at a glance
|
|
92
|
+
### Mobile
|
|
97
93
|
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
| Top Page | Worktree (History) | Worktree (Terminal) |
|
|
95
|
+
|----------|-------------------|-------------------|
|
|
96
|
+
|  |  |  |
|
|
100
97
|
|
|
101
|
-
|
|
102
|
-
→ Edit a Markdown instruction file, or type a new prompt
|
|
98
|
+
### Worktree Detail (Desktop)
|
|
103
99
|
|
|
104
|
-
|
|
105
|
-
→ Screenshot Instructions: attach a photo and say "Fix this"
|
|
106
|
-
|
|
107
|
-
7. Claude Code sees the image and starts fixing
|
|
108
|
-
```
|
|
100
|
+

|
|
109
101
|
|
|
110
102
|
---
|
|
111
103
|
|
|
@@ -115,7 +107,7 @@ Runs **100% locally**. No external server, no cloud relay, no account required.
|
|
|
115
107
|
|
|
116
108
|
- Fully open-source ([MIT License](./LICENSE))
|
|
117
109
|
- Local database, local sessions
|
|
118
|
-
- For remote access, use a VPN or authenticated reverse proxy
|
|
110
|
+
- For remote access, use a tunneling service ([Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/), [ngrok](https://ngrok.com/), [Pinggy](https://pinggy.io/)), a VPN, or an authenticated reverse proxy
|
|
119
111
|
|
|
120
112
|
See the [Security Guide](./docs/security-guide.md) and [Trust & Safety](./docs/en/TRUST_AND_SAFETY.md) for details.
|
|
121
113
|
|
|
@@ -136,6 +128,25 @@ Each Git worktree gets its own tmux session, so multiple tasks run in parallel w
|
|
|
136
128
|
|
|
137
129
|
---
|
|
138
130
|
|
|
131
|
+
<details>
|
|
132
|
+
<summary><strong>Quick Start (detailed)</strong></summary>
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Install & start in one command
|
|
136
|
+
npx commandmate
|
|
137
|
+
|
|
138
|
+
# Or install globally
|
|
139
|
+
npm install -g commandmate
|
|
140
|
+
commandmate init
|
|
141
|
+
commandmate start --daemon
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Open http://localhost:3000 in your browser.
|
|
145
|
+
|
|
146
|
+
See the [CLI Setup Guide](./docs/en/user-guide/cli-setup-guide.md) for details.
|
|
147
|
+
|
|
148
|
+
</details>
|
|
149
|
+
|
|
139
150
|
<details>
|
|
140
151
|
<summary><strong>CLI Commands</strong></summary>
|
|
141
152
|
|
|
@@ -196,25 +207,6 @@ See `commandmate --help` for all options.
|
|
|
196
207
|
|
|
197
208
|
</details>
|
|
198
209
|
|
|
199
|
-
<details>
|
|
200
|
-
<summary><strong>Screenshots</strong></summary>
|
|
201
|
-
|
|
202
|
-
### Desktop
|
|
203
|
-
|
|
204
|
-

|
|
205
|
-
|
|
206
|
-
### Worktree Detail View (Message / Console / History)
|
|
207
|
-
|
|
208
|
-
| Desktop | Mobile (History) | Mobile (Terminal) |
|
|
209
|
-
|---------|-----------------|-------------------|
|
|
210
|
-
|  |  |  |
|
|
211
|
-
|
|
212
|
-
### Top Page (Mobile)
|
|
213
|
-
|
|
214
|
-

|
|
215
|
-
|
|
216
|
-
</details>
|
|
217
|
-
|
|
218
210
|
<details>
|
|
219
211
|
<summary><strong>Troubleshooting & FAQ</strong></summary>
|
|
220
212
|
|
|
@@ -258,7 +250,13 @@ Claude Code sets `CLAUDECODE=1` to prevent nesting. CommandMate removes this aut
|
|
|
258
250
|
A: CommandMate runs a web server on your PC. To access it from your phone, your phone and PC must be on the same network (Wi-Fi). Run `commandmate init` and enable external access — this sets `CM_BIND=0.0.0.0`. Then open `http://<your-PC-IP>:3000` in your phone's browser.
|
|
259
251
|
|
|
260
252
|
**Q: Can I access it from outside my home network?**
|
|
261
|
-
A: Yes. Use a tunneling service
|
|
253
|
+
A: Yes. Use a tunneling service to securely expose your local server without opening router ports:
|
|
254
|
+
|
|
255
|
+
- [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) — free, requires Cloudflare account
|
|
256
|
+
- [ngrok](https://ngrok.com/) — free tier available, easy setup
|
|
257
|
+
- [Pinggy](https://pinggy.io/) — no sign-up required, simple SSH-based tunnel
|
|
258
|
+
|
|
259
|
+
Alternatively, a VPN or an authenticated reverse proxy (Basic Auth, OIDC, etc.) also works. **Do not** expose the server directly to the internet without authentication.
|
|
262
260
|
|
|
263
261
|
**Q: Does it work on iPhone / Android?**
|
|
264
262
|
A: Yes. CommandMate's Web UI is responsive and works on any modern mobile browser (Safari, Chrome, etc.). No app install required.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* [S4-014] UUID v4 format validation
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.UUID_V4_PATTERN = exports.DEFAULT_PERMISSIONS = exports.CODEX_SANDBOXES = exports.CLAUDE_PERMISSIONS = exports.MAX_SCHEDULE_CRON_LENGTH = exports.MAX_SCHEDULE_MESSAGE_LENGTH = exports.MAX_SCHEDULE_NAME_LENGTH = void 0;
|
|
13
|
+
exports.UUID_V4_PATTERN = exports.DEFAULT_PERMISSIONS = exports.VIBE_LOCAL_PERMISSIONS = exports.GEMINI_PERMISSIONS = exports.CODEX_SANDBOXES = exports.CLAUDE_PERMISSIONS = exports.MAX_SCHEDULE_CRON_LENGTH = exports.MAX_SCHEDULE_MESSAGE_LENGTH = exports.MAX_SCHEDULE_NAME_LENGTH = void 0;
|
|
14
14
|
exports.isValidUuidV4 = isValidUuidV4;
|
|
15
15
|
// =============================================================================
|
|
16
16
|
// Validation Constants
|
|
@@ -28,10 +28,16 @@ exports.MAX_SCHEDULE_CRON_LENGTH = 100;
|
|
|
28
28
|
exports.CLAUDE_PERMISSIONS = ['default', 'acceptEdits', 'plan', 'dontAsk', 'bypassPermissions'];
|
|
29
29
|
/** Allowed sandbox values for codex CLI (--sandbox) */
|
|
30
30
|
exports.CODEX_SANDBOXES = ['read-only', 'workspace-write', 'danger-full-access'];
|
|
31
|
+
/** Allowed permission values for gemini CLI (no permission flags) */
|
|
32
|
+
exports.GEMINI_PERMISSIONS = [];
|
|
33
|
+
/** Allowed permission values for vibe-local CLI (no permission flags) */
|
|
34
|
+
exports.VIBE_LOCAL_PERMISSIONS = [];
|
|
31
35
|
/** Default permission per CLI tool */
|
|
32
36
|
exports.DEFAULT_PERMISSIONS = {
|
|
33
37
|
claude: 'acceptEdits',
|
|
34
38
|
codex: 'workspace-write',
|
|
39
|
+
gemini: '',
|
|
40
|
+
'vibe-local': '',
|
|
35
41
|
};
|
|
36
42
|
// =============================================================================
|
|
37
43
|
// UUID Validation
|
|
@@ -403,7 +403,7 @@ async function captureAndCleanOutput(worktreeId, cliToolId) {
|
|
|
403
403
|
// captureSessionOutput() default is 1000 lines, but tmux buffer capture
|
|
404
404
|
// requires 5000 to avoid truncating long outputs.
|
|
405
405
|
const output = await (0, cli_session_1.captureSessionOutput)(worktreeId, cliToolId, 5000);
|
|
406
|
-
return (0, cli_patterns_1.stripAnsi)(output);
|
|
406
|
+
return (0, cli_patterns_1.stripBoxDrawing)((0, cli_patterns_1.stripAnsi)(output));
|
|
407
407
|
}
|
|
408
408
|
/**
|
|
409
409
|
* Process stop condition check using delta-based approach.
|
|
@@ -465,7 +465,7 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
465
465
|
try {
|
|
466
466
|
// 1. Detect prompt
|
|
467
467
|
const promptOptions = (0, cli_patterns_1.buildDetectPromptOptions)(cliToolId);
|
|
468
|
-
const promptDetection = (0, prompt_detector_1.detectPrompt)(cleanOutput, promptOptions);
|
|
468
|
+
const promptDetection = (0, prompt_detector_1.detectPrompt)((0, cli_patterns_1.stripBoxDrawing)(cleanOutput), promptOptions);
|
|
469
469
|
if (!promptDetection.isPrompt || !promptDetection.promptData) {
|
|
470
470
|
// No prompt detected - reset lastAnsweredPromptKey (Issue #306)
|
|
471
471
|
pollerState.lastAnsweredPromptKey = null;
|
|
@@ -30,7 +30,7 @@ exports.EXECUTION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
|
30
30
|
/** Maximum message length sent to claude -p */
|
|
31
31
|
exports.MAX_MESSAGE_LENGTH = 10000;
|
|
32
32
|
/** Allowed CLI tool identifiers for scheduled execution */
|
|
33
|
-
exports.ALLOWED_CLI_TOOLS = new Set(['claude', 'codex']);
|
|
33
|
+
exports.ALLOWED_CLI_TOOLS = new Set(['claude', 'codex', 'gemini', 'vibe-local']);
|
|
34
34
|
// =============================================================================
|
|
35
35
|
// Executor
|
|
36
36
|
// =============================================================================
|
|
@@ -55,17 +55,27 @@ function truncateOutput(output) {
|
|
|
55
55
|
*
|
|
56
56
|
* - claude: -p <message> --output-format text --permission-mode <permission>
|
|
57
57
|
* - codex: exec <message> --sandbox <permission>
|
|
58
|
+
* - gemini: -p <message>
|
|
59
|
+
* - vibe-local: [-p <message> -y] or [--model <model> -p <message> -y]
|
|
58
60
|
* - others: -p <message> (fallback)
|
|
59
61
|
*
|
|
60
62
|
* @param message - Prompt message
|
|
61
63
|
* @param cliToolId - CLI tool identifier
|
|
62
64
|
* @param permission - Permission mode (claude: --permission-mode, codex: --sandbox)
|
|
65
|
+
* @param options - Additional options (e.g., model for vibe-local)
|
|
63
66
|
* @returns Array of CLI arguments
|
|
64
67
|
*/
|
|
65
|
-
function buildCliArgs(message, cliToolId, permission) {
|
|
68
|
+
function buildCliArgs(message, cliToolId, permission, options) {
|
|
66
69
|
switch (cliToolId) {
|
|
67
70
|
case 'codex':
|
|
68
71
|
return ['exec', message, '--sandbox', permission ?? 'workspace-write'];
|
|
72
|
+
case 'gemini':
|
|
73
|
+
return ['-p', message];
|
|
74
|
+
case 'vibe-local':
|
|
75
|
+
if (options?.model) {
|
|
76
|
+
return ['--model', options.model, '-p', message, '-y'];
|
|
77
|
+
}
|
|
78
|
+
return ['-p', message, '-y'];
|
|
69
79
|
case 'claude':
|
|
70
80
|
default:
|
|
71
81
|
return ['-p', message, '--output-format', 'text', '--permission-mode', permission ?? 'acceptEdits'];
|
|
@@ -78,9 +88,10 @@ function buildCliArgs(message, cliToolId, permission) {
|
|
|
78
88
|
* @param cwd - Working directory (worktree path from DB)
|
|
79
89
|
* @param cliToolId - CLI tool to use (default: 'claude')
|
|
80
90
|
* @param permission - Permission mode (claude: --permission-mode, codex: --sandbox)
|
|
91
|
+
* @param options - Additional options (e.g., model for vibe-local)
|
|
81
92
|
* @returns Execution result with output and status
|
|
82
93
|
*/
|
|
83
|
-
async function executeClaudeCommand(message, cwd, cliToolId = 'claude', permission) {
|
|
94
|
+
async function executeClaudeCommand(message, cwd, cliToolId = 'claude', permission, options) {
|
|
84
95
|
// Validate cliToolId against whitelist [SEC-001]
|
|
85
96
|
if (!exports.ALLOWED_CLI_TOOLS.has(cliToolId)) {
|
|
86
97
|
return {
|
|
@@ -94,7 +105,7 @@ async function executeClaudeCommand(message, cwd, cliToolId = 'claude', permissi
|
|
|
94
105
|
const truncatedMessage = message.length > exports.MAX_MESSAGE_LENGTH
|
|
95
106
|
? message.substring(0, exports.MAX_MESSAGE_LENGTH)
|
|
96
107
|
: message;
|
|
97
|
-
const args = buildCliArgs(truncatedMessage, cliToolId, permission);
|
|
108
|
+
const args = buildCliArgs(truncatedMessage, cliToolId, permission, options);
|
|
98
109
|
return new Promise((resolve) => {
|
|
99
110
|
const child = (0, child_process_1.execFile)(cliToolId, args, {
|
|
100
111
|
cwd,
|