@foundation0/api 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/agents.ts +492 -0
- package/dist/git.js +4 -0
- package/git.ts +31 -0
- package/mcp/cli.mjs +37 -0
- package/mcp/cli.ts +43 -0
- package/mcp/client.ts +149 -0
- package/mcp/index.ts +15 -0
- package/mcp/server.ts +461 -0
- package/package.json +40 -0
- package/projects.ts +2690 -0
- package/taskgraph-parser.ts +217 -0
package/mcp/server.ts
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
|
|
4
|
+
import * as agentsApi from '../agents.ts'
|
|
5
|
+
import * as projectsApi from '../projects.ts'
|
|
6
|
+
|
|
7
|
+
type ApiMethod = (...args: unknown[]) => unknown
|
|
8
|
+
type ToolInvocationPayload = {
|
|
9
|
+
args?: unknown[]
|
|
10
|
+
options?: Record<string, unknown>
|
|
11
|
+
[key: string]: unknown
|
|
12
|
+
}
|
|
13
|
+
type BatchToolCall = {
|
|
14
|
+
tool: string
|
|
15
|
+
args?: unknown[]
|
|
16
|
+
options?: Record<string, unknown>
|
|
17
|
+
[key: string]: unknown
|
|
18
|
+
}
|
|
19
|
+
type BatchToolCallPayload = {
|
|
20
|
+
calls: BatchToolCall[]
|
|
21
|
+
continueOnError: boolean
|
|
22
|
+
}
|
|
23
|
+
type BatchResult = {
|
|
24
|
+
index: number
|
|
25
|
+
tool: string
|
|
26
|
+
isError: boolean
|
|
27
|
+
data: unknown
|
|
28
|
+
}
|
|
29
|
+
type ToolDefinition = {
|
|
30
|
+
name: string
|
|
31
|
+
method: ApiMethod
|
|
32
|
+
path: string[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type ToolNamespace = Record<string, unknown>
|
|
36
|
+
|
|
37
|
+
type ApiEndpoint = {
|
|
38
|
+
agents: ToolNamespace
|
|
39
|
+
projects: ToolNamespace
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
43
|
+
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
44
|
+
|
|
45
|
+
const normalizePayload = (payload: unknown): { args: string[]; options: Record<string, unknown> } => {
|
|
46
|
+
if (!isRecord(payload)) {
|
|
47
|
+
return {
|
|
48
|
+
args: [],
|
|
49
|
+
options: {},
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const explicitArgs = Array.isArray(payload.args) ? payload.args : undefined
|
|
54
|
+
const explicitOptions = isRecord(payload.options) ? payload.options : undefined
|
|
55
|
+
|
|
56
|
+
const args = explicitArgs ? explicitArgs.map((entry) => String(entry)) : []
|
|
57
|
+
const options: Record<string, unknown> = explicitOptions ? { ...explicitOptions } : {}
|
|
58
|
+
|
|
59
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
60
|
+
if (key === 'args' || key === 'options') {
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (value !== undefined) {
|
|
65
|
+
options[key] = value
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
args,
|
|
71
|
+
options,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const normalizeBatchToolCall = (
|
|
76
|
+
call: unknown,
|
|
77
|
+
index: number,
|
|
78
|
+
): { tool: string; payload: ToolInvocationPayload } => {
|
|
79
|
+
if (!isRecord(call)) {
|
|
80
|
+
throw new Error(`Invalid batch call at index ${index}: expected object`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const tool = typeof call.tool === 'string' ? call.tool.trim() : ''
|
|
84
|
+
if (!tool) {
|
|
85
|
+
throw new Error(`Invalid batch call at index ${index}: missing "tool"`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const args = Array.isArray(call.args) ? call.args : []
|
|
89
|
+
const { options, ...extras } = call
|
|
90
|
+
const normalized: ToolInvocationPayload = {
|
|
91
|
+
args,
|
|
92
|
+
options: isRecord(options) ? options : {},
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const [key, value] of Object.entries(extras)) {
|
|
96
|
+
if (value !== undefined) {
|
|
97
|
+
normalized.options[key] = value
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
tool,
|
|
103
|
+
payload: normalized,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const normalizeBatchPayload = (payload: unknown): BatchToolCallPayload => {
|
|
108
|
+
if (!isRecord(payload)) {
|
|
109
|
+
throw new Error('Batch tool call requires an object payload')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!Array.isArray(payload.calls)) {
|
|
113
|
+
throw new Error('Batch tool call requires a "calls" array')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const calls = payload.calls.map((call, index) => normalizeBatchToolCall(call, index))
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
calls: calls.map(({ tool, payload }) => ({
|
|
120
|
+
tool,
|
|
121
|
+
...payload,
|
|
122
|
+
})),
|
|
123
|
+
continueOnError: Boolean(payload.continueOnError),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const collectTools = (api: ToolNamespace, namespace: string[], path: string[] = []): ToolDefinition[] => {
|
|
128
|
+
const tools: ToolDefinition[] = []
|
|
129
|
+
const currentPath = [...path, ...namespace]
|
|
130
|
+
|
|
131
|
+
for (const [segment, value] of Object.entries(api)) {
|
|
132
|
+
if (typeof value !== 'function') {
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
tools.push({
|
|
137
|
+
name: [...currentPath, segment].join('.'),
|
|
138
|
+
method: value as ApiMethod,
|
|
139
|
+
path: [...currentPath, segment],
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return tools
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const buildToolName = (tool: ToolDefinition, prefix?: string): string =>
|
|
147
|
+
prefix ? `${prefix}.${tool.name}` : tool.name
|
|
148
|
+
|
|
149
|
+
const buildToolList = (tools: ToolDefinition[], batchToolName: string, prefix?: string) => {
|
|
150
|
+
const toolEntries = tools.map((tool) => ({
|
|
151
|
+
name: buildToolName(tool, prefix),
|
|
152
|
+
description: `Call API method ${tool.path.join('.')}`,
|
|
153
|
+
inputSchema: {
|
|
154
|
+
type: 'object',
|
|
155
|
+
additionalProperties: true,
|
|
156
|
+
properties: {
|
|
157
|
+
args: {
|
|
158
|
+
type: 'array',
|
|
159
|
+
items: { type: 'string' },
|
|
160
|
+
description: 'Positional arguments',
|
|
161
|
+
},
|
|
162
|
+
options: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
additionalProperties: true,
|
|
165
|
+
description: 'Named options',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
}))
|
|
170
|
+
|
|
171
|
+
const batchTool = {
|
|
172
|
+
name: batchToolName,
|
|
173
|
+
description:
|
|
174
|
+
'Preferred mode for client calls: execute multiple MCP tool calls in one request with parallel execution.',
|
|
175
|
+
inputSchema: {
|
|
176
|
+
type: 'object',
|
|
177
|
+
additionalProperties: true,
|
|
178
|
+
properties: {
|
|
179
|
+
calls: {
|
|
180
|
+
type: 'array',
|
|
181
|
+
minItems: 1,
|
|
182
|
+
items: {
|
|
183
|
+
type: 'object',
|
|
184
|
+
additionalProperties: true,
|
|
185
|
+
properties: {
|
|
186
|
+
tool: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
description: 'Full MCP tool name to execute',
|
|
189
|
+
},
|
|
190
|
+
args: {
|
|
191
|
+
type: 'array',
|
|
192
|
+
items: { type: 'string' },
|
|
193
|
+
description: 'Positional args for the tool',
|
|
194
|
+
},
|
|
195
|
+
options: {
|
|
196
|
+
type: 'object',
|
|
197
|
+
additionalProperties: true,
|
|
198
|
+
description: 'Tool invocation options',
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
required: ['tool'],
|
|
202
|
+
},
|
|
203
|
+
description: 'List of tool calls to execute',
|
|
204
|
+
},
|
|
205
|
+
continueOnError: {
|
|
206
|
+
type: 'boolean',
|
|
207
|
+
description: 'Whether to continue when a call in the batch fails',
|
|
208
|
+
default: false,
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
required: ['calls'],
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return [...toolEntries, batchTool]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
type ToolInvoker = (args: string[], options: Record<string, unknown>) => unknown[]
|
|
219
|
+
|
|
220
|
+
const buildOptionsOnly = (args: string[], options: Record<string, unknown>): unknown[] => {
|
|
221
|
+
const invocationArgs: unknown[] = [...args]
|
|
222
|
+
if (Object.keys(options).length > 0) {
|
|
223
|
+
invocationArgs.push(options)
|
|
224
|
+
}
|
|
225
|
+
return invocationArgs
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const buildOptionsThenProcessRoot = (args: string[], options: Record<string, unknown>): unknown[] => {
|
|
229
|
+
const invocationArgs: unknown[] = [...args]
|
|
230
|
+
const remaining = { ...options }
|
|
231
|
+
const processRoot = remaining.processRoot
|
|
232
|
+
if (typeof processRoot === 'string') {
|
|
233
|
+
delete remaining.processRoot
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (Object.keys(remaining).length > 0) {
|
|
237
|
+
invocationArgs.push(remaining)
|
|
238
|
+
}
|
|
239
|
+
if (typeof processRoot === 'string') {
|
|
240
|
+
invocationArgs.push(processRoot)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return invocationArgs
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const buildProcessRootThenOptions = (args: string[], options: Record<string, unknown>): unknown[] => {
|
|
247
|
+
const invocationArgs: unknown[] = [...args]
|
|
248
|
+
const remaining = { ...options }
|
|
249
|
+
const processRoot = remaining.processRoot
|
|
250
|
+
if (typeof processRoot === 'string') {
|
|
251
|
+
delete remaining.processRoot
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (typeof processRoot === 'string') {
|
|
255
|
+
invocationArgs.push(processRoot)
|
|
256
|
+
}
|
|
257
|
+
if (Object.keys(remaining).length > 0) {
|
|
258
|
+
invocationArgs.push(remaining)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return invocationArgs
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const buildProcessRootOnly = (args: string[], options: Record<string, unknown>): unknown[] => {
|
|
265
|
+
const invocationArgs: unknown[] = [...args]
|
|
266
|
+
const processRoot = options.processRoot
|
|
267
|
+
if (typeof processRoot === 'string') {
|
|
268
|
+
invocationArgs.push(processRoot)
|
|
269
|
+
}
|
|
270
|
+
return invocationArgs
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const toolInvocationPlans: Record<string, ToolInvoker> = {
|
|
274
|
+
'agents.setActive': buildProcessRootThenOptions,
|
|
275
|
+
'agents.resolveAgentsRootFrom': buildProcessRootOnly,
|
|
276
|
+
'projects.setActive': buildProcessRootThenOptions,
|
|
277
|
+
'projects.generateSpec': buildOptionsThenProcessRoot,
|
|
278
|
+
'projects.syncTasks': buildOptionsThenProcessRoot,
|
|
279
|
+
'projects.clearIssues': buildOptionsThenProcessRoot,
|
|
280
|
+
'projects.fetchGitTasks': buildOptionsThenProcessRoot,
|
|
281
|
+
'projects.readGitTask': buildOptionsThenProcessRoot,
|
|
282
|
+
'projects.writeGitTask': buildOptionsThenProcessRoot,
|
|
283
|
+
'agents.resolveTargetFile': buildOptionsOnly,
|
|
284
|
+
'projects.resolveProjectTargetFile': buildOptionsOnly,
|
|
285
|
+
'agents.loadAgent': buildProcessRootOnly,
|
|
286
|
+
'agents.main': buildProcessRootOnly,
|
|
287
|
+
'agents.resolveAgentsRoot': buildProcessRootOnly,
|
|
288
|
+
'agents.resolveAgentsRootFrom': buildProcessRootOnly,
|
|
289
|
+
'agents.listAgents': buildProcessRootOnly,
|
|
290
|
+
'projects.resolveProjectRoot': buildProcessRootOnly,
|
|
291
|
+
'projects.listProjects': buildProcessRootOnly,
|
|
292
|
+
'projects.listProjectDocs': buildProcessRootOnly,
|
|
293
|
+
'projects.readProjectDoc': buildProcessRootOnly,
|
|
294
|
+
'projects.main': buildProcessRootOnly,
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const invokeTool = async (tool: ToolDefinition, payload: unknown): Promise<unknown> => {
|
|
298
|
+
const { args, options } = normalizePayload(payload)
|
|
299
|
+
const invoke = toolInvocationPlans[tool.name] ?? ((rawArgs, rawOptions) => {
|
|
300
|
+
const invocationArgs = [...rawArgs]
|
|
301
|
+
if (Object.keys(rawOptions).length > 0) {
|
|
302
|
+
invocationArgs.push(rawOptions)
|
|
303
|
+
}
|
|
304
|
+
return invocationArgs
|
|
305
|
+
})
|
|
306
|
+
const invocationArgs = invoke(args, options)
|
|
307
|
+
|
|
308
|
+
return Promise.resolve(tool.method(...invocationArgs))
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export interface F0McpServerOptions {
|
|
312
|
+
serverName?: string
|
|
313
|
+
serverVersion?: string
|
|
314
|
+
toolsPrefix?: string
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export type F0McpServerInstance = {
|
|
318
|
+
api: ApiEndpoint
|
|
319
|
+
tools: ToolDefinition[]
|
|
320
|
+
server: Server
|
|
321
|
+
run: () => Promise<Server>
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export const createF0McpServer = (options: F0McpServerOptions = {}): F0McpServerInstance => {
|
|
325
|
+
const api: ApiEndpoint = {
|
|
326
|
+
agents: agentsApi,
|
|
327
|
+
projects: projectsApi,
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const tools = [
|
|
331
|
+
...collectTools(api.agents, ['agents']),
|
|
332
|
+
...collectTools(api.projects, ['projects']),
|
|
333
|
+
]
|
|
334
|
+
const prefix = options.toolsPrefix
|
|
335
|
+
const batchToolName = prefix ? `${prefix}.batch` : 'batch'
|
|
336
|
+
|
|
337
|
+
const server = new Server(
|
|
338
|
+
{
|
|
339
|
+
name: options.serverName ?? 'f0-api',
|
|
340
|
+
version: options.serverVersion ?? '1.0.0',
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
capabilities: {
|
|
344
|
+
tools: {},
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
const toolByName = new Map<string, ToolDefinition>(tools.map((tool) => [buildToolName(tool, prefix), tool]))
|
|
350
|
+
|
|
351
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
352
|
+
tools: buildToolList(tools, batchToolName, prefix),
|
|
353
|
+
}))
|
|
354
|
+
|
|
355
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
356
|
+
const requestedName = request.params.name
|
|
357
|
+
|
|
358
|
+
if (requestedName === batchToolName) {
|
|
359
|
+
try {
|
|
360
|
+
const { calls, continueOnError } = normalizeBatchPayload(request.params.arguments)
|
|
361
|
+
const executions = calls.map(({ tool, args = [], options = {} }, index) => ({ tool, args, options, index }))
|
|
362
|
+
const results = await Promise.all(
|
|
363
|
+
executions.map(async ({ tool, args, options, index }) => {
|
|
364
|
+
const toolDefinition = toolByName.get(tool)
|
|
365
|
+
if (!toolDefinition) {
|
|
366
|
+
return {
|
|
367
|
+
index,
|
|
368
|
+
tool,
|
|
369
|
+
isError: true,
|
|
370
|
+
data: `Unknown tool: ${tool}`,
|
|
371
|
+
} as BatchResult
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
const data = await invokeTool(toolDefinition, { args, options })
|
|
376
|
+
return {
|
|
377
|
+
index,
|
|
378
|
+
tool,
|
|
379
|
+
isError: false,
|
|
380
|
+
data,
|
|
381
|
+
} as BatchResult
|
|
382
|
+
} catch (error) {
|
|
383
|
+
if (continueOnError) {
|
|
384
|
+
return {
|
|
385
|
+
index,
|
|
386
|
+
tool,
|
|
387
|
+
isError: true,
|
|
388
|
+
data: error instanceof Error ? error.message : String(error),
|
|
389
|
+
} as BatchResult
|
|
390
|
+
}
|
|
391
|
+
throw error
|
|
392
|
+
}
|
|
393
|
+
}),
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
isError: results.some((result) => result.isError),
|
|
398
|
+
content: [
|
|
399
|
+
{
|
|
400
|
+
type: 'text',
|
|
401
|
+
text: JSON.stringify(results, null, 2),
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
}
|
|
405
|
+
} catch (error) {
|
|
406
|
+
return {
|
|
407
|
+
isError: true,
|
|
408
|
+
content: [
|
|
409
|
+
{
|
|
410
|
+
type: 'text',
|
|
411
|
+
text: error instanceof Error ? error.message : String(error),
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const tool = toolByName.get(requestedName)
|
|
419
|
+
|
|
420
|
+
if (!tool) {
|
|
421
|
+
throw new Error(`Unknown tool: ${requestedName}`)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
const data = await invokeTool(tool, request.params.arguments)
|
|
426
|
+
return {
|
|
427
|
+
content: [
|
|
428
|
+
{
|
|
429
|
+
type: 'text',
|
|
430
|
+
text: JSON.stringify(data, null, 2),
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
}
|
|
434
|
+
} catch (error) {
|
|
435
|
+
return {
|
|
436
|
+
isError: true,
|
|
437
|
+
content: [
|
|
438
|
+
{
|
|
439
|
+
type: 'text',
|
|
440
|
+
text: error instanceof Error ? error.message : String(error),
|
|
441
|
+
},
|
|
442
|
+
],
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
const run = async (): Promise<Server> => {
|
|
448
|
+
await server.connect(new StdioServerTransport())
|
|
449
|
+
return server
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return { api, tools, server, run }
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export const runF0McpServer = async (options: F0McpServerOptions = {}): Promise<Server> => {
|
|
456
|
+
const instance = createF0McpServer(options)
|
|
457
|
+
return instance.run()
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export const normalizeToolCallNameForServer = (prefix: string | undefined, toolName: string): string =>
|
|
461
|
+
prefix ? toolName.replace(new RegExp(`^${prefix}\\.`), '') : toolName
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@foundation0/api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Foundation 0 API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"f0-mcp": "./mcp/cli.mjs",
|
|
8
|
+
"f0-mcp-server": "./mcp/cli.mjs"
|
|
9
|
+
},
|
|
10
|
+
"private": false,
|
|
11
|
+
"main": "agents.ts",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"foundation0",
|
|
14
|
+
"f0",
|
|
15
|
+
"api"
|
|
16
|
+
],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"files": [
|
|
20
|
+
"agents.ts",
|
|
21
|
+
"git.ts",
|
|
22
|
+
"dist/git.js",
|
|
23
|
+
"taskgraph-parser.ts",
|
|
24
|
+
"projects.ts",
|
|
25
|
+
"mcp"
|
|
26
|
+
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build:git": "bun build ../git/packages/git/src/index.ts --target bun --format esm --minify --outfile ./dist/git.js",
|
|
33
|
+
"mcp": "bun run mcp/cli.ts",
|
|
34
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
35
|
+
"deploy": "pnpm prepublishOnly && pnpm publish --access public",
|
|
36
|
+
"version:patch": "pnpm version patch",
|
|
37
|
+
"version:minor": "pnpm version minor",
|
|
38
|
+
"version:major": "pnpm version major"
|
|
39
|
+
}
|
|
40
|
+
}
|