@tanstack/cli 0.0.1
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/dist/bin.cjs +470 -0
- package/dist/bin.d.cts +1 -0
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +469 -0
- package/dist/index.cjs +36 -0
- package/dist/index.d.cts +1172 -0
- package/dist/index.d.mts +1172 -0
- package/dist/index.mjs +3 -0
- package/dist/template-2SxOxCJc.mjs +2496 -0
- package/dist/template-BYKvtZrT.cjs +2734 -0
- package/package.json +66 -0
- package/src/api/fetch.test.ts +114 -0
- package/src/api/fetch.ts +221 -0
- package/src/bin.ts +95 -0
- package/src/commands/create.ts +463 -0
- package/src/commands/mcp.test.ts +152 -0
- package/src/commands/mcp.ts +199 -0
- package/src/engine/compile-with-addons.test.ts +302 -0
- package/src/engine/compile.test.ts +404 -0
- package/src/engine/compile.ts +551 -0
- package/src/engine/config-file.test.ts +118 -0
- package/src/engine/config-file.ts +61 -0
- package/src/engine/custom-addons/integration.ts +323 -0
- package/src/engine/custom-addons/shared.test.ts +98 -0
- package/src/engine/custom-addons/shared.ts +281 -0
- package/src/engine/custom-addons/template.test.ts +288 -0
- package/src/engine/custom-addons/template.ts +124 -0
- package/src/engine/template.test.ts +256 -0
- package/src/engine/template.ts +269 -0
- package/src/engine/types.ts +334 -0
- package/src/index.ts +85 -0
- package/src/parse-gitignore.d.ts +5 -0
- package/src/templates/base.ts +888 -0
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tanstack/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TanStack CLI for scaffolding and tooling",
|
|
5
|
+
"author": "Tanner Linsley",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TanStack/cli.git",
|
|
10
|
+
"directory": "packages/cli"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://tanstack.com/cli",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"tanstack",
|
|
15
|
+
"cli",
|
|
16
|
+
"scaffold",
|
|
17
|
+
"mcp",
|
|
18
|
+
"create",
|
|
19
|
+
"start"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"import": {
|
|
25
|
+
"types": "./dist/index.d.mts",
|
|
26
|
+
"default": "./dist/index.mjs"
|
|
27
|
+
},
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./dist/index.d.cts",
|
|
30
|
+
"default": "./dist/index.cjs"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"main": "./dist/index.cjs",
|
|
35
|
+
"module": "./dist/index.mjs",
|
|
36
|
+
"types": "./dist/index.d.mts",
|
|
37
|
+
"bin": {
|
|
38
|
+
"tanstack": "./dist/bin.mjs"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"src"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsdown --clean",
|
|
46
|
+
"test:types": "tsc --noEmit",
|
|
47
|
+
"test:eslint": "eslint ./src",
|
|
48
|
+
"test:lib": "vitest run --passWithNoTests"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@clack/prompts": "^0.10.0",
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.6.0",
|
|
53
|
+
"chalk": "^5.4.1",
|
|
54
|
+
"commander": "^13.1.0",
|
|
55
|
+
"ejs": "^3.1.10",
|
|
56
|
+
"express": "^4.21.2",
|
|
57
|
+
"ignore": "^7.0.5",
|
|
58
|
+
"parse-gitignore": "^2.0.0",
|
|
59
|
+
"zod": "^3.24.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/ejs": "^3.1.5",
|
|
63
|
+
"@types/express": "^5.0.1",
|
|
64
|
+
"@types/node": "^25.0.7"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import {
|
|
4
|
+
fetchManifest,
|
|
5
|
+
fetchIntegration,
|
|
6
|
+
fetchIntegrations,
|
|
7
|
+
fetchIntegrationInfo,
|
|
8
|
+
fetchIntegrationFiles,
|
|
9
|
+
} from './fetch.js'
|
|
10
|
+
|
|
11
|
+
const INTEGRATIONS_PATH = resolve(__dirname, '../../../../integrations')
|
|
12
|
+
|
|
13
|
+
describe('fetch API', () => {
|
|
14
|
+
describe('fetchManifest', () => {
|
|
15
|
+
it('should fetch manifest from local path', async () => {
|
|
16
|
+
const manifest = await fetchManifest(INTEGRATIONS_PATH)
|
|
17
|
+
|
|
18
|
+
expect(manifest).toBeDefined()
|
|
19
|
+
expect(manifest.integrations).toBeInstanceOf(Array)
|
|
20
|
+
expect(manifest.integrations.length).toBeGreaterThan(0)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should have integrations with required fields', async () => {
|
|
24
|
+
const manifest = await fetchManifest(INTEGRATIONS_PATH)
|
|
25
|
+
|
|
26
|
+
for (const integration of manifest.integrations) {
|
|
27
|
+
expect(integration.id).toBeDefined()
|
|
28
|
+
expect(integration.name).toBeDefined()
|
|
29
|
+
expect(integration.modes).toBeInstanceOf(Array)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should throw for non-existent path', async () => {
|
|
34
|
+
await expect(fetchManifest('/non/existent/path')).rejects.toThrow()
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('fetchIntegrationInfo', () => {
|
|
39
|
+
it('should fetch integration info from local path', async () => {
|
|
40
|
+
const info = await fetchIntegrationInfo('tanstack-query', INTEGRATIONS_PATH)
|
|
41
|
+
|
|
42
|
+
expect(info.name).toBe('TanStack Query')
|
|
43
|
+
expect(info.type).toBe('integration')
|
|
44
|
+
expect(info.modes).toContain('file-router')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should throw for non-existent integration', async () => {
|
|
48
|
+
await expect(
|
|
49
|
+
fetchIntegrationInfo('non-existent', INTEGRATIONS_PATH),
|
|
50
|
+
).rejects.toThrow()
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('fetchIntegrationFiles', () => {
|
|
55
|
+
it('should fetch integration files from local path', async () => {
|
|
56
|
+
const files = await fetchIntegrationFiles('tanstack-query', INTEGRATIONS_PATH)
|
|
57
|
+
|
|
58
|
+
expect(Object.keys(files).length).toBeGreaterThan(0)
|
|
59
|
+
// Files are in assets/src/integrations/query/
|
|
60
|
+
expect(files).toHaveProperty('src/integrations/query/provider.tsx')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should return empty object for integration without assets', async () => {
|
|
64
|
+
// This tests the case where assets dir doesn't exist
|
|
65
|
+
const files = await fetchIntegrationFiles('non-existent', INTEGRATIONS_PATH)
|
|
66
|
+
expect(files).toEqual({})
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe('fetchIntegration', () => {
|
|
71
|
+
it('should fetch complete integration', async () => {
|
|
72
|
+
const integration = await fetchIntegration('tanstack-query', INTEGRATIONS_PATH)
|
|
73
|
+
|
|
74
|
+
expect(integration.id).toBe('tanstack-query')
|
|
75
|
+
expect(integration.name).toBe('TanStack Query')
|
|
76
|
+
expect(integration.files).toBeDefined()
|
|
77
|
+
expect(Object.keys(integration.files).length).toBeGreaterThan(0)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('should include hooks if defined', async () => {
|
|
81
|
+
const integration = await fetchIntegration('tanstack-query', INTEGRATIONS_PATH)
|
|
82
|
+
|
|
83
|
+
expect(integration.hooks).toBeDefined()
|
|
84
|
+
expect(integration.hooks!.length).toBeGreaterThan(0)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('should merge package.json into packageAdditions', async () => {
|
|
88
|
+
const integration = await fetchIntegration('tanstack-query', INTEGRATIONS_PATH)
|
|
89
|
+
|
|
90
|
+
expect(integration.packageAdditions).toBeDefined()
|
|
91
|
+
expect(integration.packageAdditions?.dependencies).toHaveProperty(
|
|
92
|
+
'@tanstack/react-query',
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
describe('fetchIntegrations', () => {
|
|
98
|
+
it('should fetch multiple integrations in parallel', async () => {
|
|
99
|
+
const integrations = await fetchIntegrations(
|
|
100
|
+
['tanstack-query', 'tanstack-form'],
|
|
101
|
+
INTEGRATIONS_PATH,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
expect(integrations).toHaveLength(2)
|
|
105
|
+
expect(integrations[0]?.id).toBe('tanstack-query')
|
|
106
|
+
expect(integrations[1]?.id).toBe('tanstack-form')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should return empty array for empty input', async () => {
|
|
110
|
+
const integrations = await fetchIntegrations([], INTEGRATIONS_PATH)
|
|
111
|
+
expect(integrations).toEqual([])
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
})
|
package/src/api/fetch.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import {
|
|
4
|
+
IntegrationCompiledSchema,
|
|
5
|
+
IntegrationInfoSchema,
|
|
6
|
+
ManifestSchema
|
|
7
|
+
} from '../engine/types.js'
|
|
8
|
+
import type { IntegrationCompiled, IntegrationInfo, Manifest } from '../engine/types.js'
|
|
9
|
+
|
|
10
|
+
const GITHUB_RAW_BASE =
|
|
11
|
+
'https://raw.githubusercontent.com/TanStack/cli/main/integrations'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if a path is a local directory
|
|
15
|
+
*/
|
|
16
|
+
function isLocalPath(path: string): boolean {
|
|
17
|
+
return path.startsWith('/') || path.startsWith('./') || path.startsWith('..')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fetch the integration manifest from GitHub or local path
|
|
22
|
+
*/
|
|
23
|
+
export async function fetchManifest(
|
|
24
|
+
baseUrl: string = GITHUB_RAW_BASE,
|
|
25
|
+
): Promise<Manifest> {
|
|
26
|
+
if (isLocalPath(baseUrl)) {
|
|
27
|
+
const manifestPath = join(baseUrl, 'manifest.json')
|
|
28
|
+
if (!existsSync(manifestPath)) {
|
|
29
|
+
throw new Error(`Manifest not found at ${manifestPath}`)
|
|
30
|
+
}
|
|
31
|
+
const data = JSON.parse(readFileSync(manifestPath, 'utf-8'))
|
|
32
|
+
return ManifestSchema.parse(data)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const url = `${baseUrl}/manifest.json`
|
|
36
|
+
const response = await fetch(url)
|
|
37
|
+
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(`Failed to fetch manifest: ${response.statusText}`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const data = await response.json()
|
|
43
|
+
return ManifestSchema.parse(data)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Fetch integration info.json from GitHub or local path
|
|
48
|
+
*/
|
|
49
|
+
export async function fetchIntegrationInfo(
|
|
50
|
+
integrationId: string,
|
|
51
|
+
baseUrl: string = GITHUB_RAW_BASE,
|
|
52
|
+
): Promise<IntegrationInfo> {
|
|
53
|
+
if (isLocalPath(baseUrl)) {
|
|
54
|
+
const infoPath = join(baseUrl, integrationId, 'info.json')
|
|
55
|
+
if (!existsSync(infoPath)) {
|
|
56
|
+
throw new Error(`Integration info not found at ${infoPath}`)
|
|
57
|
+
}
|
|
58
|
+
const data = JSON.parse(readFileSync(infoPath, 'utf-8'))
|
|
59
|
+
return IntegrationInfoSchema.parse(data)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const url = `${baseUrl}/${integrationId}/info.json`
|
|
63
|
+
const response = await fetch(url)
|
|
64
|
+
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new Error(`Failed to fetch integration ${integrationId}: ${response.statusText}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const data = await response.json()
|
|
70
|
+
return IntegrationInfoSchema.parse(data)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Recursively read all files from a directory
|
|
75
|
+
*/
|
|
76
|
+
function readDirRecursive(
|
|
77
|
+
dir: string,
|
|
78
|
+
basePath: string = '',
|
|
79
|
+
): Record<string, string> {
|
|
80
|
+
const files: Record<string, string> = {}
|
|
81
|
+
|
|
82
|
+
if (!existsSync(dir)) return files
|
|
83
|
+
|
|
84
|
+
for (const entry of readdirSync(dir)) {
|
|
85
|
+
const fullPath = join(dir, entry)
|
|
86
|
+
const relativePath = basePath ? `${basePath}/${entry}` : entry
|
|
87
|
+
const stat = statSync(fullPath)
|
|
88
|
+
|
|
89
|
+
if (stat.isDirectory()) {
|
|
90
|
+
Object.assign(files, readDirRecursive(fullPath, relativePath))
|
|
91
|
+
} else {
|
|
92
|
+
files[relativePath] = readFileSync(fullPath, 'utf-8')
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return files
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Fetch all files for an integration from GitHub or local path
|
|
101
|
+
*/
|
|
102
|
+
export async function fetchIntegrationFiles(
|
|
103
|
+
integrationId: string,
|
|
104
|
+
baseUrl: string = GITHUB_RAW_BASE,
|
|
105
|
+
): Promise<Record<string, string>> {
|
|
106
|
+
if (isLocalPath(baseUrl)) {
|
|
107
|
+
const assetsPath = join(baseUrl, integrationId, 'assets')
|
|
108
|
+
return readDirRecursive(assetsPath)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// First fetch the file list (we'll need a files.json or similar)
|
|
112
|
+
const filesUrl = `${baseUrl}/${integrationId}/files.json`
|
|
113
|
+
const response = await fetch(filesUrl)
|
|
114
|
+
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
// No files.json, return empty
|
|
117
|
+
return {}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const fileList: Array<string> = await response.json()
|
|
121
|
+
const files: Record<string, string> = {}
|
|
122
|
+
|
|
123
|
+
// Fetch each file
|
|
124
|
+
await Promise.all(
|
|
125
|
+
fileList.map(async (filePath) => {
|
|
126
|
+
const fileUrl = `${baseUrl}/${integrationId}/assets/${filePath}`
|
|
127
|
+
const fileResponse = await fetch(fileUrl)
|
|
128
|
+
|
|
129
|
+
if (fileResponse.ok) {
|
|
130
|
+
files[filePath] = await fileResponse.text()
|
|
131
|
+
}
|
|
132
|
+
}),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
return files
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Fetch integration package.json if it exists
|
|
140
|
+
*/
|
|
141
|
+
async function fetchIntegrationPackageJson(
|
|
142
|
+
integrationId: string,
|
|
143
|
+
baseUrl: string,
|
|
144
|
+
): Promise<{
|
|
145
|
+
dependencies?: Record<string, string>
|
|
146
|
+
devDependencies?: Record<string, string>
|
|
147
|
+
scripts?: Record<string, string>
|
|
148
|
+
} | null> {
|
|
149
|
+
if (isLocalPath(baseUrl)) {
|
|
150
|
+
const pkgPath = join(baseUrl, integrationId, 'package.json')
|
|
151
|
+
if (existsSync(pkgPath)) {
|
|
152
|
+
return JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
153
|
+
}
|
|
154
|
+
return null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const url = `${baseUrl}/${integrationId}/package.json`
|
|
158
|
+
const response = await fetch(url)
|
|
159
|
+
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return response.json()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Fetch a complete compiled integration from GitHub
|
|
169
|
+
*/
|
|
170
|
+
export async function fetchIntegration(
|
|
171
|
+
integrationId: string,
|
|
172
|
+
baseUrl: string = GITHUB_RAW_BASE,
|
|
173
|
+
): Promise<IntegrationCompiled> {
|
|
174
|
+
const [info, files, pkgJson] = await Promise.all([
|
|
175
|
+
fetchIntegrationInfo(integrationId, baseUrl),
|
|
176
|
+
fetchIntegrationFiles(integrationId, baseUrl),
|
|
177
|
+
fetchIntegrationPackageJson(integrationId, baseUrl),
|
|
178
|
+
])
|
|
179
|
+
|
|
180
|
+
// Merge package.json into packageAdditions if present
|
|
181
|
+
const packageAdditions = info.packageAdditions ?? {}
|
|
182
|
+
if (pkgJson) {
|
|
183
|
+
if (pkgJson.dependencies) {
|
|
184
|
+
packageAdditions.dependencies = {
|
|
185
|
+
...packageAdditions.dependencies,
|
|
186
|
+
...pkgJson.dependencies,
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (pkgJson.devDependencies) {
|
|
190
|
+
packageAdditions.devDependencies = {
|
|
191
|
+
...packageAdditions.devDependencies,
|
|
192
|
+
...pkgJson.devDependencies,
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (pkgJson.scripts) {
|
|
196
|
+
packageAdditions.scripts = {
|
|
197
|
+
...packageAdditions.scripts,
|
|
198
|
+
...pkgJson.scripts,
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return IntegrationCompiledSchema.parse({
|
|
204
|
+
...info,
|
|
205
|
+
id: integrationId,
|
|
206
|
+
files,
|
|
207
|
+
packageAdditions:
|
|
208
|
+
Object.keys(packageAdditions).length > 0 ? packageAdditions : undefined,
|
|
209
|
+
deletedFiles: [],
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Fetch multiple integrations in parallel
|
|
215
|
+
*/
|
|
216
|
+
export async function fetchIntegrations(
|
|
217
|
+
integrationIds: Array<string>,
|
|
218
|
+
baseUrl: string = GITHUB_RAW_BASE,
|
|
219
|
+
): Promise<Array<IntegrationCompiled>> {
|
|
220
|
+
return Promise.all(integrationIds.map((id) => fetchIntegration(id, baseUrl)))
|
|
221
|
+
}
|
package/src/bin.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { resolve } from 'node:path'
|
|
4
|
+
import { Command } from 'commander'
|
|
5
|
+
import { runCreate } from './commands/create.js'
|
|
6
|
+
import { runMcp } from './commands/mcp.js'
|
|
7
|
+
import { compileIntegration, initIntegration } from './engine/custom-addons/integration.js'
|
|
8
|
+
import { compileTemplate, initTemplate } from './engine/custom-addons/template.js'
|
|
9
|
+
|
|
10
|
+
const program = new Command()
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name('tanstack')
|
|
14
|
+
.description('TanStack CLI for scaffolding and tooling')
|
|
15
|
+
.version('0.0.1')
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.command('create')
|
|
19
|
+
.argument('[project-name]', 'name of the project')
|
|
20
|
+
.option('--template <template>', 'URL to a custom template JSON file')
|
|
21
|
+
.option('--package-manager <pm>', 'package manager (npm, pnpm, yarn, bun)')
|
|
22
|
+
.option('--integrations <integrations>', 'comma-separated list of integration IDs')
|
|
23
|
+
.option('--no-install', 'skip installing dependencies')
|
|
24
|
+
.option('--no-git', 'skip initializing git repository')
|
|
25
|
+
.option('--no-tailwind', 'skip tailwind CSS')
|
|
26
|
+
.option('-y, --yes', 'skip prompts and use defaults')
|
|
27
|
+
.option('--target-dir <path>', 'target directory for the project')
|
|
28
|
+
.option('--integrations-path <path>', 'local path to integrations directory (for development)')
|
|
29
|
+
.description('Create a new TanStack Start project')
|
|
30
|
+
.action(runCreate)
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command('mcp')
|
|
34
|
+
.option('--sse', 'run in SSE mode (for HTTP transport)')
|
|
35
|
+
.option('--port <port>', 'port for SSE server', '8080')
|
|
36
|
+
.description('Start the MCP server for AI agents')
|
|
37
|
+
.action(runMcp)
|
|
38
|
+
|
|
39
|
+
// Integration commands
|
|
40
|
+
const integrationCommand = program.command('integration')
|
|
41
|
+
|
|
42
|
+
integrationCommand
|
|
43
|
+
.command('init')
|
|
44
|
+
.option('--integrations-path <path>', 'local path to integrations directory (for development)')
|
|
45
|
+
.description('Initialize an integration from the current project')
|
|
46
|
+
.action(async (options: { integrationsPath?: string }) => {
|
|
47
|
+
try {
|
|
48
|
+
await initIntegration(resolve(process.cwd()), options.integrationsPath)
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(error instanceof Error ? error.message : 'An error occurred')
|
|
51
|
+
process.exit(1)
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
integrationCommand
|
|
56
|
+
.command('compile')
|
|
57
|
+
.option('--integrations-path <path>', 'local path to integrations directory (for development)')
|
|
58
|
+
.description('Compile/update the integration from the current project')
|
|
59
|
+
.action(async (options: { integrationsPath?: string }) => {
|
|
60
|
+
try {
|
|
61
|
+
await compileIntegration(resolve(process.cwd()), options.integrationsPath)
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(error instanceof Error ? error.message : 'An error occurred')
|
|
64
|
+
process.exit(1)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Custom template commands
|
|
69
|
+
const templateCommand = program.command('template')
|
|
70
|
+
|
|
71
|
+
templateCommand
|
|
72
|
+
.command('init')
|
|
73
|
+
.description('Initialize a custom template from the current project')
|
|
74
|
+
.action(async () => {
|
|
75
|
+
try {
|
|
76
|
+
await initTemplate(resolve(process.cwd()))
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(error instanceof Error ? error.message : 'An error occurred')
|
|
79
|
+
process.exit(1)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
templateCommand
|
|
84
|
+
.command('compile')
|
|
85
|
+
.description('Compile/update the custom template from the current project')
|
|
86
|
+
.action(async () => {
|
|
87
|
+
try {
|
|
88
|
+
await compileTemplate(resolve(process.cwd()))
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(error instanceof Error ? error.message : 'An error occurred')
|
|
91
|
+
process.exit(1)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
program.parse()
|